1

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?

5
  • Remove the \ It escapes the meaning of $ Commented Jan 30, 2015 at 9:00
  • Thanks. I got confused by all the examples I found, always using c\ and not just c. Thought it was syntax. Commented Jan 30, 2015 at 9:01
  • If you would have researched a bit could have found the answer already. There are many such questions in SO for example stackoverflow.com/questions/7680504/…. Anyways all the best !! Commented Jan 30, 2015 at 9:03
  • The question is a bit different in my opinion, since I want to change the entire line and not use sed "s/foo/bar/" to only replace foo with bar. Commented Jan 30, 2015 at 9:05
  • Yeah I agree that it is different . But it clearly shows how you should be using bash variables in sed, since it was where you got stuck at Commented Jan 30, 2015 at 9:07

2 Answers 2

3

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.

Sign up to request clarification or add additional context in comments.

1 Comment

Thanks for a thorough explanation. I was not aware of the '/pattern/ {...}' syntax in awk. Will definitely start using that.
1

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

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.