4

There is a file with following text:

CXX_FLAGS = -fPIC -Wall -Wextra -Wno-missing-braces -ffloat-store -pthread -std=gnu++17

To replace the string "-std=gnu++17" with "-std=c++17 -std=gnu++17", I tried:

sed -i -e 's/\-std\=gnu\+\+17/\-std=c\+\+17 \-std=gnu\+\+17/g' filename

That however does not work, until I remove the \ escape from frst + sign in search expression. So these seem to be OK:

sed -i -e 's/\-std\=gnu++17/\-std=c\+\+17 \-std=gnu\+\+17/g' filename
sed -i -e 's/\-std\=gnu+\+17/\-std=c\+\+17 \-std=gnu\+\+17/g' filename
sed -i -e 's/\-std\=gnu..17/\-std=c\+\+17 \-std=gnu\+\+17/g' filename

I understand the + must be escaped when not in character class, but I thought one can prefix any character with backslash in regex. Why does escaping the + sign here cause the search-replace to fail?

The OS is Ubuntu 20.04 LTS.

Wiktor Stribiżew
  • 607,720
  • 39
  • 448
  • 563
  • 1
    wrt `I understand the + must be escaped when not in character class` - no, it doesn't in a BRE. wrt `I thought one can prefix any character with backslash in regex` - no, one can't as doing so can turn a literal char into a meta-char. See [is-it-possible-to-escape-regex-metacharacters-reliably-with-sed](https://stackoverflow.com/questions/29613304/is-it-possible-to-escape-regex-metacharacters-reliably-with-sed) for which chars can/must be escaped and how each has to be handled. – Ed Morton Sep 17 '20 at 22:40

1 Answers1

4

You have not used -r nor -E option, so you tell sed to parse the regex pattern as a POSIX BRE expression. In GNU sed, in a POSIX BRE expression, \+ is a quantifier matching 1 or more occurrences of the quantified pattern. Run sed -e 's/\-std\=gnu\+\+17/\-std=c\+\+17 \-std=gnu\+\+17/g' <<< '-std=gnuuuu17' and the result will be -std=c++17 -std=gnu++17. To match +, you just need to use +.

Note you overescaped a lot of chars and your command is unnecessarily long because you repeated the pattern in both the LHS and RHS.

You may use the following POSIX BRE sed command with GNU sed:

sed -i 's/-std=gnu++17/-std=c++17 &/' filename

See the sed online demo:

s='CXX_FLAGS = -fPIC -Wall -Wextra -Wno-missing-braces -ffloat-store -pthread -std=gnu++17'
sed 's/-std=gnu++17/-std=c++17 &/' <<< "$s"
# => CXX_FLAGS = -fPIC -Wall -Wextra -Wno-missing-braces -ffloat-store -pthread -std=c++17 -std=gnu++17

Details

  • -std=gnu++17 - the string pattern matches -std=gnu++17 string exactly
  • -std=c++17 & - the replacement pattern is -std=c++17, space and & stands for the whole match, -std=gnu++17.
Wiktor Stribiżew
  • 607,720
  • 39
  • 448
  • 563