137

I am using the below code for replacing a string inside a shell script.

echo $LINE | sed -e 's/12345678/"$replace"/g'

but it's getting replaced with $replace instead of the value of that variable.

Could anybody tell what went wrong?

fedorqui
  • 275,237
  • 103
  • 548
  • 598
Vijay
  • 65,327
  • 90
  • 227
  • 319
  • For the common related question about handling values with slashes in them, see http://stackoverflow.com/questions/5864146/use-slashes-in-sed-replace – tripleee Nov 30 '16 at 05:10
  • Does this answer your question? [Difference between single and double quotes in Bash](https://stackoverflow.com/questions/6697753/difference-between-single-and-double-quotes-in-bash) – user1934428 Nov 23 '20 at 14:13
  • Answered here: https://stackoverflow.com/a/70476292/925775 – Mihail H. Dec 25 '21 at 00:02

12 Answers12

197

If you want to interpret $replace, you should not use single quotes since they prevent variable substitution.

Try:

echo $LINE | sed -e "s/12345678/${replace}/g"

Transcript:

pax> export replace=987654321
pax> echo X123456789X | sed "s/123456789/${replace}/"
X987654321X
pax> _

Just be careful to ensure that ${replace} doesn't have any characters of significance to sed (like / for instance) since it will cause confusion unless escaped. But if, as you say, you're replacing one number with another, that shouldn't be a problem.

oguz ismail
  • 1
  • 16
  • 47
  • 69
paxdiablo
  • 854,327
  • 234
  • 1,573
  • 1,953
  • i dont want the quotes put in.i want one number to be replaced with other – Vijay Jul 22 '10 at 05:33
  • 1
    paxdiablo: `set` is also not necessary (and how were you going to use it anyway?). Just `replace=987654321`. – Roman Cheplyaka Jul 22 '10 at 20:26
  • I usually always use `export` to ensure that variables are set for children but, as you say, you could just as easily avoid it. However, the use or not of `export` is irrelevant here (a style issue) and has no effect on the actual answer, which is how to use variables within a `sed` command. – paxdiablo May 30 '14 at 04:22
  • This solution doesn't seem to be working with the `-i` option. Would you know why? or how to make it work? – Gabriel Oct 23 '15 at 02:59
  • @Gabriel, if you mean `sed -i`, that requirs an input file so it can do in-place editing. I'm hoping you're not trying to use `echo something | sed -i 'command'` since that has no input file to modify, just the input stream. You would have to use `sed -i 'command' some_file_name`. Suggest you open up another question with more detail if it's something other than that. – paxdiablo Oct 23 '15 at 03:07
  • 1
    Maybe also point out that switching from single to double quotes requires any `$` or `\`` in the `sed` script to be escaped with a backslash, to protect it from the shell's substitution mechanism for double-quoted strings. – tripleee Oct 02 '16 at 07:45
  • if line is delimited like this: `abc,123,def,456,ghi`, and i want to replace 4th element with a value from variable `$var`, how could it be done? – dcdum2018 Oct 28 '21 at 13:46
97

you can use the shell (bash/ksh).

$ var="12345678abc"
$ replace="test"
$ echo ${var//12345678/$replace}
testabc
ghostdog74
  • 327,991
  • 56
  • 259
  • 343
  • 4
    May want to mention that's bash-specific (and ksh?). Probably not of import to most people but some of us are still forced to work on ancient UNIXen :-) – paxdiablo Jul 22 '10 at 05:40
  • 10
    Beware, this also fails on dash, which is `/bin/sh` on many modern Linuxes. – phihag Oct 02 '15 at 10:02
  • why need two forward slashes after the "var"? one should be enough according to my test. – star Mar 25 '21 at 11:44
  • You need to slashes if you want global replace, rather than the first instance. – AdamC Jun 17 '22 at 22:59
39

Not specific to the question, but for folks who need the same kind of functionality expanded for clarity from previous answers:

# create some variables
str="someFileName.foo"
find=".foo"
replace=".bar"
# notice the the str isn't prefixed with $
#    this is just how this feature works :/
result=${str//$find/$replace}
echo $result    
# result is: someFileName.bar

str="someFileName.sally"
find=".foo"
replace=".bar"
result=${str//$find/$replace}
echo $result    
# result is: someFileName.sally because ".foo" was not found
bob
  • 7,539
  • 2
  • 46
  • 42
21

Found a graceful solution.

echo ${LINE//12345678/$replace}
Nicolae Iotu
  • 399
  • 3
  • 7
10

Single quotes are very strong. Once inside, there's nothing you can do to invoke variable substitution, until you leave. Use double quotes instead:

echo $LINE | sed -e "s/12345678/$replace/g"
Dave
  • 10,964
  • 3
  • 32
  • 54
9

Let me give you two examples.

  • Using sed:
#!/bin/bash
LINE="12345678HI"
replace="Hello"
echo $LINE | sed -e "s/12345678/$replace/g"
  • Without Using sed:
LINE="12345678HI"
str_to_replace="12345678"
replace_str="Hello"
result=${str//$str_to_replace/$replace_str}
echo $result

Hope you will find it helpful!

Md. Shahariar Hossen
  • 1,367
  • 10
  • 11
5
echo $LINE | sed -e 's/12345678/'$replace'/g'

you can still use single quotes, but you have to "open" them when you want the variable expanded at the right place. otherwise the string is taken "literally" (as @paxdiablo correctly stated, his answer is correct as well)

akira
  • 6,050
  • 29
  • 37
  • This has the problem that using `$replace` outside of any quotes will cause the shell to perform whitespace tokenization and wildcard expansion on the value. This will appear to work with simple values, but could blow up dramatically on nontrivial strings. Don't use this in production code. – tripleee Oct 02 '16 at 07:41
2

To let your shell expand the variable, you need to use double-quotes like

sed -i "s#12345678#$replace#g" file.txt

This will break if $replace contain special sed characters (#, \). But you can preprocess $replace to quote them:

replace_quoted=$(printf '%s' "$replace" | sed 's/[#\]/\\\0/g')
sed -i "s#12345678#$replace_quoted#g" file.txt
Matthieu Moy
  • 15,151
  • 5
  • 38
  • 65
1

use @ if you want to replace things like /. $ etc.

result=$(echo $str | sed "s@$oldstr@$newstr@g")

the above code will replace all occurrences of the specified replacement term if you want, remove the ending g which means that the only first occurrence will be replaced.

Somen Das
  • 366
  • 2
  • 7
0

I had a similar requirement to this but my replace var contained an ampersand. Escaping the ampersand like this solved my problem:

replace="salt & pepper"
echo "pass the salt" | sed "s/salt/${replace/&/\&}/g"
RSX
  • 376
  • 4
  • 14
-1

Use this instead

echo $LINE | sed -e 's/12345678/$replace/g'

this works for me just simply remove the quotes

Tunde Pizzle
  • 787
  • 1
  • 9
  • 18
-2

I prefer to use double quotes , as single quptes are very powerful as we used them if dont able to change anything inside it or can invoke the variable substituion .

so use double quotes instaed.

echo $LINE | sed -e "s/12345678/$replace/g"
Prasad Khode
  • 6,602
  • 11
  • 44
  • 59
SteveScm
  • 545
  • 1
  • 7
  • 15