Home > OS >  sed: Nested group with inverse lookahead matching
sed: Nested group with inverse lookahead matching

Time:12-01

I am trying to replace the image tag for all URLs except the URL with image bar. But, it says that the regular expression is invalid.
Checking just the regular expression (image:(?!.*bar).*:).* on regex101.com looked fine. The error comes while replacing the 2nd part of the sed expression with the group (image:(?!.*bar).*:).

$ echo '
image: mydomain/subdomain/foo:old_tag
image: mydomain/subdomain/bar:dont_update_me_tag
image: mydomain/subdomain/baz:old_tag
' | sed --regexp-extended "s|(image:(?!.*bar).*:).*|\1new_tag|g"
sed: -e expression #1, char 36: Invalid preceding regular expression

The expected end result is:

image: mydomain/subdomain/foo:new_tag
image: mydomain/subdomain/bar:dont_update_me_tag
image: mydomain/subdomain/baz:new_tag

Explanation of the regex (image:(?!.*bar).*:).*
Search for all lines containing image:.*:.* except those containingimage:.*bar

CodePudding user response:

POSIX ERE still does not support lookarounds. Fortunately, you can match a line with a certain pattern and skip it, and then match whatever you need:

sed -E "/image:.*bar/!s/(image:.*:).*/\1new_tag/g"

See the online demo:

echo '
image: mydomain/subdomain/foo:old_tag
image: mydomain/subdomain/bar:dont_update_me_tag
image: mydomain/subdomain/baz:old_tag
' | sed -E "/image:.*bar/!s/(image:.*:).*/\1new_tag/g"

Output:

image: mydomain/subdomain/foo:new_tag
image: mydomain/subdomain/bar:dont_update_me_tag
image: mydomain/subdomain/baz:new_tag

CodePudding user response:

This might work for you (GNU sed):

sed -E 's/^/\n/
       :a;ta
       s/\n(image: \S*bar\S*)/\1\n/;ta
       s/\n(image: \S*:)\S*/\1new_tag\n/;ta
       s/\n(.)/\1\n/;ta
       s/\n$//' file

Process a line at a time.

Introduce a newline at the start of the line.

If the string following the newline is an image with bar in it, skip passed it, shift the newline and repeat.

If the string following the newline is an image without bar in it, replace it with the new tag, shift the newline and repeat.

Otherwise, shift the newline passed the next character and repeat.

When the newline can no longer be shifted, remove it, print the current line and repeat.

N.B. The g flag of the substitution command can not be utilised as each instance of an image must be compared separately. If there is one image per line and nothing else then use @Wiktor Stribiżew solution.

  • Related