Reputation: 3018
I want to use sed to replace the entire line at a match with a bash variable. Replacing with plain text is fine.
$ echo -e "foo bar\nfooy bary\nfoot bart" | sed '/fooy/c\text'
foo bar
text
foot bart
If the text I want to replace with is stored in a bash variable, however, this does not work.
$ var="This is poetry."
$ echo -e "foo bar\nfooy bary\nfoot bart" | sed "/fooy/c\$var"
foo bar
$var
foot bart
How can I achieve this?
Upvotes: 1
Views: 5606
Reputation: 44023
If you want to do this with sed (which you shouldn't, see below), use
sed "/fooy/c\\$var"
This is a shell expansion problem. \$
in a doubly quoted string means a literal dollar, so $var
is not expanded. GNU sed also accepts
sed "/fooy/c$var"
as long as you don't specify --posix
, but BSD sed (as you may have on FreeBSD or MacOS X) will complain about it.
However, doing this with sed is not a good idea. Substituting shell variables into sed code is almost never a good idea, because it makes you vulnerable to code injection. Take, for example,
$ var=$(echo -e 'something\nd')
$ echo -e "foo bar\nfooy bary\nfoot bart" | sed --posix "/fooy/c\\$var"
something
That wasn't what we expected, was it? What happens here is that sed
, since it is unable do distinguish what you want it to treat as data ($var
) and code, treats $var
as code, and therefore it treats the d
after the \n
in it as a command (to delete the current line). A better way is to use awk
:
$ var=$(echo -e 'something\nd')
$ echo -e "foo bar\nfooy bary\nfoot bart" | awk -v var="$var" '/fooy/ { print var; next } 1'
foo bar
something
d
foot bart
This sidesteps the code injection issue by not treating $var
as code.
Upvotes: 3
Reputation: 174696
Don't escape the $
symbol. In bash, variables are referred by $variable-name
. If you do escaping the $
symbol, then the bash won't consider it as a variable. It would treat $var
as literal $var
.
$ echo -e "foo bar\nfooy bary\nfoot bart" | sed "/fooy/c$var"
foo bar
This is poetry.
foot bart
Upvotes: 1