bartimar
bartimar

Reputation: 3534

Bash - quoted variable expansion mixed with sed yields bad substitution

I have problem with this sed oneliner

sed -i -n "1h; 1!H; ${g; :a s/\(Name=\"$key\".*<\!\[CDATA\[\"\)$val\(\"\]\]>\)/\1$deval\2/;ta p}"

Obviously I need to expand variable key, val and deval in sed. So I need the " around sed command.

With this command I get

bash: !H: event not found

escaping the ! corrects it

sed -i -n "1h; 1\!H; ${g; :a s/\(Name=\"$key\".*<\!\[CDATA\[\"\)$val(\"\]\]>\)/\1$deval\2/;ta p}"

With this I get

bash: sed -i -n "1h; 1\!H; ${g; :a s/\(Name=\"$key\".*<\!\[CDATA\[\"\)$val\(\"\]\]>\)/\1$deval\2/;ta p}" :bad substitution

So I guess the { is a problem. Trying to fix it like this

sed -i -n "1h; 1\!H; $\{g; :a s/\(Name=\"$key\".*<\!\[CDATA\[\"\)$val(\"\]\]>\)/\1$deval\2/;ta p}"

yields

sed: -e expression 1, char 6: unknown command: "\"

What is going on here? How can I make this work?

Upvotes: 3

Views: 1767

Answers (2)

tom
tom

Reputation: 22969

You can use separate single-quoted strings:

sed -i -n '1h; 1!H; ${g; :a s/\(Name='"$key"'.*<\!\[CDATA\[\"\)'"$val"'\(\"\]\]>\)/\1'"$deval"'\2/;ta p}'

Upvotes: 2

that other guy
that other guy

Reputation: 123470

event not found is only a problem in interactive shells because histexpand is enabled by default. If you either run set +H first or put it in a script and run it from there, Bash will leave your !s alone.

${..} is variable substitution syntax (so a mangled value gives bad substitution). Let sed treat it as a block of commands to do on the final line by escaping the $, as in \${ .. }.

In full:

set +H
key="foo"
val="bar"
deval="puppies"
echo 'Name="foo" <![CDATA["bar"]]>' > file
sed -i -n "1h; 1!H; \${g; :a s/\(Name=\"$key\".*<!\[CDATA\[\"\)$val\(\"\]\]>\)/\1$deval\2/;ta p}" file
cat file

Will print Name="foo" <![CDATA["puppies"]]>

Upvotes: 4

Related Questions