Bash: setting and replacing values in a properties file use sed

A common task when configuring software is modifying a properties file to set or override behavior.  And although properties files are simple key=value pairs, there are some corner cases that make it challenging.

For example, when setting a key/value pair, the key may be commented out with a hash mark in front of the line.  So you could simply append to the end of the file, but what you would really like is to insert your value at the expected position.

Example properties file

Throughout this article, we will use this example.properties.

server=127.0.0.1

# key commented out
# port=8080

dir=/my path/subfolder

Pulling a value

Using sed with a regular expression (-r) and suppressing the printing of the pattern space (-n), we can pull out specific values:

$ sed -rn 's/^server=([^\n]+)$/\1/p' example.properties
127.0.0.1

# pulls value with spaces
$ sed -rn 's/^dir=([^\n]+)$/\1/p' example.properties
/my path/subfolder

# attempts pulls of commented out key, empty result which is expected
$ sed -rn 's/^port=([^\n]+)$/\1/p' example.properties

The regular expression essentially says to consider any character except the newline as part of the value, and since it is in parentheses as a capture group, we then refer to it as “\1” to isolate it.

Setting a value, even if commented out

Often, a properties file will have commented out values that start with a hash mark (#).  The idea is to show you the default the system will use, while at the same time giving you the option to override.

In our example.properties, “port” is an example of this pattern.  The property is commented out, but it tells us the system will use port 8080 as the default.

So when you set a value, you have to account for the idea that it may be or may not be commented out.  Here is a sed with a regex that takes care of this, and sets the port value to 9999.

sed -ir "s/^[#]*\s*port=.*/port=9999/" example.properties

The regex allows for an optional comment and whitespace prefacing the key.

Setting a value, append if key not found

Building on the last example, if a key is not found at all then you may want to append to the end of the file.  And if the key is found (even if commented out) then we set the value in place like the last example.

filename=example.properties
thekey="port"
newvalue="123"

if ! grep -R "^[#]*\s*${thekey}=.*" $filename > /dev/null; then
  echo "APPENDING because '${thekey}' not found"
  echo "$thekey=$newvalue" >> $filename
else
  echo "SETTING because '${thekey}' found already"
  sed -ir "s/^[#]*\s*${thekey}=.*/$thekey=$newvalue/" $filename
fi

Setting a value, before or after another property key

Another scenario is inserting a new property key in a particular place in the properties file.  Consider adding a new key ‘portnext=8081’ after our ‘port’ key.

This is building on another article I wrote called “Using sed to insert lines before or after a match“.

sed -r '/^[#]*\s*port=.*/a portnext=8081' example.properties

This would insert the “portnext=8081” key right after “port”.  You would need to add “-i” to make the replacement in place and have it saved.

And if you wanted to insert a key named “portprevious=8079” right before “port”, then it would look like.

sed -r '/^[#]*\s*port=.*/i portprevious=8079' example.properties

 

REFERENCES

man sed

fabianlee.org, using sed to insert lines before or after a match