Drux
Drux

Reputation: 12650

Simple replacement with sed inside bash not working

Why is this simple replacement with sed inside bash not working?

echo '[a](!)' | sed 's/[a](!)/[a]/'

It returns [a](!) instead of [a]. But why, given that only three characters need to be escaped in a sed replacement string?

If I account for the case that additional characters need to be replaced in the regex string and try

echo '[a](!)' | sed 's/\[a\]\(!\)/[a]/'

it is still not working.

Upvotes: 0

Views: 71

Answers (3)

John Goofy
John Goofy

Reputation: 1419

man echo tells that the command echo display a line of text. So [ and ( with their closing brackets are just text.

If you read man grep and type there /^\ *Character Classes and Bracket Expressions and /^\ *Basic vs Extended Regular Expressions you can read the difference. sed and other tools that use regex interprets this as Character Classes and Bracket Expressions.

You can try this

$ echo '[a](!)' | sed 's/(!)//'

Upvotes: -1

Ed Morton
Ed Morton

Reputation: 203129

sed uses BREs by default and EREs can be enabled by escaping individual ERE metacharaters or by using the -E argument. [ and ] are BRE metacharacters, ( and ) are ERE metacharacters. When you wrote:

echo '[a](!)' | sed 's/\[a\]\(!\)/[a]/'

you were turning the [ and ] BRE metacharacters into literals, which is good, but you were turning the literal ( and ) into ERE metacharacters, which is bad. This is what you were trying to do:

echo '[a](!)' | sed 's/\[a\](!)/[a]/'

which you'd probably really want to write using a capture group:

echo '[a](!)' | sed 's/\(\[a\]\)(!)/\1/'

to avoid duplicating [a] on both sides of the substitution. With EREs enabled using the -E argument that last would be:

echo '[a](!)' | sed -E 's/(\[a\])\(!\)/\1/'

Read the sed man page and a regexp tutorial.

Upvotes: 1

Wiktor Stribiżew
Wiktor Stribiżew

Reputation: 626689

The point is that [a] in the regex pattern does not match square brackets that form a bracket expression. Escape the first [ for it to be parsed as a literal [ symbol, and your replacement will work:

echo '[a](!)' | sed 's/\[a](!)/[a]/'
                       ^^

See this demo

Upvotes: 3

Related Questions