I have a file with a complex multi-line command and some unrelated text. I need to prepend certain paths (for example, /foo
) with a prefix /bar
. The script may ran more than once, but must not prepend multiple /bar
prefixes to the same path. For example, run the script once to get /bar/foo
, run it again, and still get /bar/foo
, not /bar/bar/foo
. I must use sed
for consistency with the existing code base.
I came up with the desired result (below), but my method seems cumbersome. Is there a better (shorter, less repetitive) way?
$ echo '/foo' > infile
$ cat infile
"/foo" /foo
# Replace once, change expected:
$ sed -i '\#bar/foo#!s#\(/foo\)#/bar\1#g' infile
$ cat infile
"/bar/foo" /bar/foo
# Replace twice - no change expected:
$ sed -i '\#bar/foo#!s#\(/foo\)#/bar\1#g' infile
$ cat infile
"/bar/foo" /bar/foo
EDIT: Do not use my "solution": it is wrong in an important edge case, see the comments below
CodePudding user response:
You may use this sed
solution with an optional group to replace /foo
with /bar/foo
but skip matching when /bar
is already there:
sed -E 's~(/bar)?(/foo)~/bar\2~g' file
Details:
(/bar)?
: Match optional/bar
in capture group #1(/foo)
: Match/foo
in capture group #2/bar\2
: Replacement to always put/bar
followed by value we captured in capture group #2