Home > OS >  How to prepend a PREFIX to paths only once (in an idempotent way) in `sed` (e.g., no PREFIXPREFIX)?
How to prepend a PREFIX to paths only once (in an idempotent way) in `sed` (e.g., no PREFIXPREFIX)?

Time:04-20

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

RegEx Demo

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
  • Related