3

I am tring to write sed command to find and replace a key=value in a comma delimited string.

Example string in file: KEY_1=value_1,KEY_2=value_2,SOMEKEY=lastValue

The sed command used:

sed -r 's/KEY_2=.*?((?=,)|$)/KEY_2=new_value/' myFile.txt

If the Key exists replace it and its value with a new key=value. Most of the values will end with a comma ',' however the outlying case is the last key=value in the string will not have a ,.

Its giving me the following error message on RedHat Linux VM

sed: -e expression #1, char 55: Invalid preceding regular expression

which I believe is the last '/' I tried /g which would also be excptable as no key should be duplicated in the original string.

2 Answers2

6

The sed utility does not support Perl-like regular expressions.

Instead you may use

$ sed 's/KEY_2=[^,]*/KEY_2=new value/' file
KEY_1=value_1,KEY_2=new value,SOMEKEY=lastValue

or

$ sed 's/\(KEY_2\)=[^,]*/\1=new value/' file
KEY_1=value_1,KEY_2=new value,SOMEKEY=lastValue

Or, with awk (without using regular expressions and instead using exact string matches against the keys which prevents confusion when you have both KEY_2 and SOME_OTHER_KEY_2):

$ awk -F, -v OFS=, '{ for (i = 1; i <= NF; ++i)
                          if (split($i, a, "=") == 2 && a[1] == "KEY_2") {
                              $i = "KEY_2=new value"
                              break
                          } } 1' file
KEY_1=value_1,KEY_2=new value,SOMEKEY=lastValue
Kusalananda
  • 333,661
3

As mentioned in the comments, sed doesn't support PCRE style regular expressions (See also: Why does my regular expression work in X but not in Y?). You can use perl instead

$ s='KEY_1=value_1,KEY_2=value_2,SOMEKEY=lastValue'

$ echo "$s" | perl -pe 's/KEY_2=.*?((?=,)|$)/KEY_2=new_value/'
KEY_1=value_1,KEY_2=new_value,SOMEKEY=lastValue

$ echo "$s" | perl -pe 's/SOMEKEY=.*?((?=,)|$)/SOMEKEY=new_value/'
KEY_1=value_1,KEY_2=value_2,SOMEKEY=new_value

You could simplify the regex:

$ # -l needed to prevent deleting the newline character for last field
$ echo "$s" | perl -lpe 's/KEY_2=\K[^,]+/new_value/'
KEY_1=value_1,KEY_2=new_value,SOMEKEY=lastValue

$ # to prevent partial match
$ echo "$s" | perl -lpe 's/(?<![^,])KEY_2=\K[^,]+/new_value/'
KEY_1=value_1,KEY_2=new_value,SOMEKEY=lastValue

See perldoc Command Switches for explanations on command line options used here

Sundeep
  • 12,008