Using sed, the simplest syntax:
sed \
-e '/^\(option=\).*/{s//\1value/;:a;n;ba;q}' \
-e '$aoption=value' filename
This would replace the parameter if it exists, else would add it to the bottom of the file.
Use the -i
option if you want to edit the file in-place.
If you want to accept and keep white spaces, and in addition to remove the comment, if the line already exists, but is commented out, write:
sed -i \
-e '/^#\?\(\s*option\s*=\s*\).*/{s//\1value/;:a;n;ba;q}' \
-e '$aoption=value' filename
Please note that neither option nor value must contain a slash /
, or you will have to escape it to \/
.
To use bash-variables $option
and $value
, you could write:
sed -i \
-e '/^#\?\(\s*'${option//\//\\/}'\s*=\s*\).*/{s//\1'${value//\//\\/}'/;:a;n;ba;q}' \
-e '$a'${option//\//\\/}'='${value//\//\\/} filename
The bash expression ${option//\//\\/}
quotes slashes, it replaces all /
with \/
.
Note: Just trapped into a problem. In bash you may quote "${option//\//\\/}"
, but in the sh of busybox, this does not work, so you should avoid the quotes, at least in non-bourne-shells.
All combined in a bash function:
# call option with parameters: $1=name $2=value $3=file
function option() {
name=${1//\//\\/}
value=${2//\//\\/}
sed -i \
-e '/^#\?\(\s*'"${name}"'\s*=\s*\).*/{s//\1'"${value}"'/;:a;n;ba;q}' \
-e '$a'"${name}"'='"${value}" $3
}
Explanation:
/^\(option=\).*/
: Match lines that start with option=
and (.*
) ignore everything after the =
. The \(
…\)
encloses the part we will reuse as \1
later.
- /^#?(\s*'"${option//////}"'\s*=\s*).*/: Ignore commented out code with
#
at the begin of line. \?
means «optional». The comment will be removed, because it is outside of the copied part in \(
…\)
. \s*
means «any number of white spaces» (space, tabulator). White spaces are copied, since they are within \(
…\)
, so you do not lose formatting.
/^\(option=\).*/{…}
: If matches a line /…/
, then execute the next command. Command to execute is not a single command, but a block {…}
.
s//…/
: Search and replace. Since the search term is empty //
, it applies to the last match, which was /^\(option=\).*/
.
s//\1value/: Replace the last match with everything in
(…), referenced by
\1and the text
value`
:a;n;ba;q
: Set label a
, then read next line n
, then branch b
(or goto) back to label a
, that means: read all lines up to the end of file, so after the first match, just fetch all following lines without further processing. Then q
quit and therefore ignore everything else.
$aoption=value
: At the end of file $
, append a
the text option=value
More information on sed
and a command overview is on my blog: