How to best use SED to comment out a config value while adding a new config value right after it?

I don't know if it's "the best practice", but sed code for this is relatively simple:

sed '/^foo_option / {s/^/#/; a\
foo_option /new/opt
}' /path/to/conf.file

It solves the example 1. To solve the example 2 you need to replace each occurrence of foo_option (there are two occurrences, and note the trailing space) with foo_option= in the sed code.

Universal code that solves both examples is more complicated because what you append depends on the presence of = in the old line; therefore you cannot use a with a fixed string. Try this:

sed '/^foo_option[= ]/ {
  h; s/^/#/; p
  g; s|\([= ]\).*|\1/new/opt|
}' /path/to/conf.file

The above code uses the original line twice. First it copies the line from the pattern space to the hold space (h), adds # in front and prints the pattern space (p). Next it copies back from the hold space (g) and places /new/opt in the right place; this time the pattern space gets printed because sed (without -n) prints by default when it's done processing the line (no p needed).

Notes:

  • I used | in the second s, not /, because /new/opt contains /. Your attempt with s/^foo_option .*$/foo_option /new/opt/ was invalid, too many / characters. In general you can use almost any character.

  • In your tries you used ^foo_option inside the pattern of s to match the right line; then you needed it in the replacement (as \1 or literal foo_option ). A better way is to address the line by using a regex match, like I did: /^foo_option / or so. Then the following command (or { } block) does not need to check if it's the right line, you know it is. You can use commands other than s; and s often can be simplified greatly. Even in a simple case of adding # I prefer /^foo_option / s/^/#/ to s/\(^foo_option \)/#\1/. The former code is more readable and it's the Right Way.

  • In regular expressions * is greedy, so .*$ (you used it) does not really need $.