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
fabianlee.org, using sed to insert lines before or after a match