2

I would like to replace variations of a string using sed. The string pattern is required to match a set of optional repeatable characters ("../") and a mandatory string ("foo") For e.g. ../foo ../../foo ../../../foo

I can replace a single version such as ../../../foo using pattern which will yield using sed:

sed - 's/\.\.\/\.\.\/\.\.\/foo/foo1/'

=> foo1 but I want to extend to match any version so I get: ../foo => foo1 ../../foo => foo1 ../../../foo => foo1

How do I achieve this using sed?

Inian
  • 80,270
  • 14
  • 142
  • 161
Rubans
  • 4,188
  • 6
  • 40
  • 58

2 Answers2

2

With awk you could do it much easier form, just match the pattern and if its found then print the new value.

s='../foo
../../foo
../../../foo'
echo "$s" | awk 'match($0,/(\.\.)+\/foo/){print "foo1"}'

Explanation: Simple explanation would be:

  • First creating shell variable named s which has value of foo mentioned by OP in it.
  • Then printing its value by echo command and sending it as a standard input to awk program.
  • In awk program, using awk's match function to match regex (\.\.)+\/foo if mentioned regex matched then print new value foo2 in this case.

Explanation of regex:

(\.\.)+\/foo: match 2 literal dots(together) with 1 or more occurrences follows by /foo if match found then print the new value.

Output will be as follows:

foo1
foo1
foo1
RavinderSingh13
  • 130,504
  • 14
  • 57
  • 93
1

You can use

sed -E 's,(\.\./)+foo,foo1,' file > newfile

Note the -E option enables the POSIX ERE syntax and the (...) are parsed as a grouping construct and + is parsed as a quantifier that matches one or more occurrences of the quantified subpattern.

If you need to make sure the match occurs at the start of the string, add ^ at the beginning: 's,^(\.\./)+foo,foo1,'. Note that the comma is used as a regex delimiter here to avoid escaping the / char.

If the foo must be matched as a whole word and if it ends with a word character, add \> closing word boundary construct right after foo.

See the online demo:

s='../foo
../../foo
../../../foo'
sed -E 's,(\.\./)+foo,foo1,' <<< "$s"

Output:

foo1
foo1
foo1
Wiktor Stribiżew
  • 607,720
  • 39
  • 448
  • 563
  • this is great, any ideas how I can do inplace edit using expression at the same time? I tried sed -i -E [] on my macOS but didn't seem to work – Rubans Oct 18 '21 at 14:05
  • 1
    @Rubans Just use `.bak` or `''`: `sed -i '' -E 's,(\.\./)+foo,foo1,' file` or `sed -i.bak -E 's,(\.\./)+foo,foo1,' file`. See [In-place edits with sed on OS X](https://stackoverflow.com/q/7573368/3832970). – Wiktor Stribiżew Oct 18 '21 at 14:06