use sed to match on string but not remove anything past any number of specific characters then a character

Viewed 42

Here is an example file called "config_file.txt":

setting01 = 0          # Comment for setting 01
setting02 = 1          # Comment for setting 02
setting03 = "./folder" # Comment for setting 03
setting04 = "string"   # Comment for setting 04
setting05 = 1          # Comment for setting 05

I need to replace each setting but not affect anything after the setting . This means do not remove any white space after setting, a "#", and anything after the "#".

I tried the following to replace "setting01"

sed -i "s/setting01\\ =\\ .*#/setting01\\ = 1/g" conf_file.txt

However that resulted in this:

setting01 = 1 Comment for setting 01
setting02 = 1          # Comment for setting 02
setting03 = "./folder" # Comment for setting 03
setting04 = "string"   # Comment for setting 04
setting05 = 1          # Comment for setting 05

When I want this:

setting01 = 1          # Comment for setting 01
setting02 = 1          # Comment for setting 02
setting03 = "./folder" # Comment for setting 03
setting04 = "string"   # Comment for setting 04
setting05 = 1          # Comment for setting 05

How can I accomplish this?

2 Answers

You can use

sed -i -E 's/(setting01 = )("[^"]*"|[^[:space:]]+)/\11/g' conf_file.txt

Details:

  • -E - enable POSIX ERE regex syntax
  • (setting01 = ) - Group 1: setting01 =
  • ("[^"]*"|[^[:space:]]+) - Group 2:
    • "[^"]*" - a ", then zero or more chars other than " and then a "
    • | - or
    • [^[:space:]]+ - one or more non-whitespace chars

The \11 replaces the match with Group 1 value and 1 (as there can be no more than \9 backreferences in a POSIX regex, \11 is not parsed by sed as the 11th backreference).

See the online demo:

#!/bin/bash
s='setting01 = 0          # Comment for setting 01
setting02 = 1          # Comment for setting 02
setting03 = "./folder" # Comment for setting 03
setting04 = "string"   # Comment for setting 04
setting05 = 1          # Comment for setting 05'
 
sed -E 's/(setting01 = )("[^"]*"|[^[:space:]]+)/\11/g'  <<< "$s"

Output:

setting01 = 1          # Comment for setting 01
setting02 = 1          # Comment for setting 02
setting03 = "./folder" # Comment for setting 03
setting04 = "string"   # Comment for setting 04
setting05 = 1          # Comment for setting 05

This might work for you (GNU sed):

sed -E '/^(setting03 = )(\S+)/{s//\1\nXXX\n\2/
         :a;ta;s/(\n.*\n *)[^ #]/\1 /;ta
         :b;tb;s/\n(\S)(.*\n) /\1\n\2/;tb
         s/\n#([^\n]*)$/ #\1/;s/\n//g;s/ +$//}' file

Turn on extended regexps by setting the -E command line option.

Replace the value of setting03, prepending a newline marker and appending another newline marker and the original value (to be used as a template).

Replace the template by spaces and then superimpose the new value over it.

Remove newline markers and if the new value is larger than spaces before the comment, append an additional space to separate it from the comment.

Lastly if the original line did not have a comment, remove space artifacts.

Related