2

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

subtleseeker
  • 4,415
  • 5
  • 29
  • 41

2 Answers2

1

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/"

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/"

Output:

image: mydomain/subdomain/foo:new_tag
image: mydomain/subdomain/bar:dont_update_me_tag
image: mydomain/subdomain/baz:new_tag
Wiktor Stribiżew
  • 607,720
  • 39
  • 448
  • 563
  • 1
    Perhaps you should remove the `g` flag as you make use of the `.*` regexp and the non-matching address of the substitution command is global throughout the line. – potong Dec 01 '21 at 09:23
  • @potong It is a remainder from the OP command. I think there is no harm even if `g` is there , but it definitely makes no sense to keep it there. – Wiktor Stribiżew Dec 01 '21 at 09:25
1

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.

potong
  • 55,640
  • 6
  • 51
  • 83
  • Thanks for sharing detailed explanation with answer. could you please do let me know if `\n` only recognized by GNU `sed`? OR there are other sed versions which do recognize it? – RavinderSingh13 Dec 01 '21 at 09:48
  • 1
    @RavinderSingh13 I only ever use GNU sed and I am aware other seds do present problems and that is why I always (probably!) qualify my solutions as above. Another [question](https://stackoverflow.com/questions/24275070/sed-not-giving-me-correct-substitute-operation-for-newline-with-mac-difference/) might throw more light on the problem. – potong Dec 01 '21 at 10:40