Bash - quoted variable expansion mixed with sed yields bad substitution
bash, sed
Solution
`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"]]>`
Problem
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?