2

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.

  • 1
    That looks like a Perl regex to me (lazy modifiers? zero-width lookarounds?). – muru Sep 26 '18 at 2:38
  • sed does not support PCRE. – Kusalananda Sep 26 '18 at 6:34
5

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
  • good one, especially the point about partial match – Sundeep Sep 26 '18 at 6:53
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

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.