Append or modify keys in conf files using sed/bash

2019-02-26 07:54发布

问题:

I often have to modify files such as sysctl.conf, and I'm familiar with using sed to replace existing values.

Is there a way to append the new key/value pair to the file if sed wasn't able to replace it?

For instance, using this example: modify config file using bash script

sed -c -i "s/\($TARGET_KEY *= *\).*/\1$REPLACEMENT_VALUE/" $CONFIG_FILE

How could I add the $TARGET_KEY = $REPLACEMENT_VALUE new line to $CONFIG_FILE using the same sed expression with slight changes?

And on a related topic, how can I force creation of $CONFIG_FILE if it didn't exist?

回答1:

You can't easily do it all in a single sed call. It's probably simplest to make it two steps:

if grep -q "$TARGET_KEY *= " $CONFIG_FILE; then   
   sed -c -i "s/\($TARGET_KEY *= *\).*/\1$REPLACEMENT_VALUE/" $CONFIG_FILE
else
   echo "$TARGET_KEY = $REPLACEMENT_VALUE" >>$CONFIG_FILE
fi

There are a few things you should probably do to make the above more robust, however:

  1. Your regular expression is not anchored, which means that trying to set 'PORT' will also find/change 'SUPPORT', etc.

  2. It won't match if the config file might have tabs as well as spaces

  3. It fails if the replacement value has slashes in it.

  4. You should always quote parameter expansions like $CONFIG_FILE, in case the file path contains spaces or shell metacharacters.

  5. It's safe in this instance, but potentially confusing to use single backslashes in a double-quoted string when you want a literal backslash. The shell leaves them alone when it doesn't recognize what comes after it as a special sequence, but it would be clearer if you doubled them.

  6. What does -c do on your version of sed? Neither my Linux nor Mac versions support such an option.

So I would do it this way (the ^I's represent literal tab characters, and the ^A's literal control-A characters, entered by for example typing control-V first on the command line):

if grep -q "^[ ^I]*$TARGET_KEY[ ^I]*=" "$CONFIG_FILE"; then
   sed -i -e "s^A^\\([ ^I]*$TARGET_KEY[ ^I]*=[ ^I]*\\).*$^A\\1$REPLACEMENT_VALUE^A" "$CONFIG_FILE"
else
   echo "$TARGET_KEY = $REPLACEMENT_VALUE" >> "$CONFIG_FILE"
fi


回答2:

Use below pseudo code:

if (grep -q key); then
    sed...
else
    echo key=value >> $CONFIG_FILE
fi