4

SED command not replacing in bash under Debian, but works in command line.

Works in command line:

sed -i 's|/dev/disk/by-label/SR6D4|/dev/disk/by-label/SR4D4|g' /etc/my/config.xml

Not working in bash script, does not replace the string:

from="SR6D4"
to="SR4D4"
path_from="/dev/disk/by-label/${from}"
path_to="/dev/disk/by-label/${to}"
echo "sed -i 's|${path_from}|${path_to}|g' $file"
sed -i 's|${path_from}|${path_to}|g' $file

Why doesn't replace string in file when using sed in bash?

JdeBP
  • 68,745
klor
  • 404

2 Answers2

9

Shell variables won't get expanded in single quotes. (It's kind of what single quotes are for.)

sed -i "s|${path_from}|${path_to}|g" "$file"

should work better. (I've added double quotes around $file just in case your filename ever contains spaces.)

  • Uh, very cheap error :) I did not notice, that I used simple quotes for sed :-( Of course double quotes are interpolated, while single are not. Thank you for pointing the error. Accepting as solution. – klor Jan 22 '18 at 07:08
1

As mentioned earlier you have problem with quoting. But there are some opinions about string replacement in file. See below.

It's bad idea to replace string in file because it's unsafety. There is small probability to lost file's data while changing.

You could try to backup file before changing:

cp /path/to/file{,.backup}
sed -i 'place your pattern here' /path/to/file

and you will get file with name file.backup.

You need to remember: if your file will be damaged and you will delete and replace it - file will have different inode and will lost all hard links.

The second safety method:

mv /path/to/file{,.backup}; 
cat /path/to/file.backup | sed 'place your pattern here' > /path/to/file

The next point. As bashFAQ thinks:

Embedding shell variables in sed commands is never a good idea

Thats why you need to use awk with -v options instead. Your script may look like this:

from="SR6D4"
to="SR4D4"
path_from="/dev/disk/by-label/${from}"
path_to="/dev/disk/by-label/${to}"
sed -i 's|${path_from}|${path_to}|g' $file
mv $file{,.backup}
cat "${file}.backup" | awk -v awkfrom="$path_from" -v awkto="$path_to" '{gsub(awkfrom,awkto)}' > $file
  • Very detailed answer. But the OP was solved by the previous answer. So I select the other as solution. – klor Jan 22 '18 at 11:00
  • @klor, yes, of course. I am only supplemented the answer of Ulrich Schwarz – Egor Vasilyev Jan 22 '18 at 11:06
  • Your answer however gave me the idea to make backup of changed files. Thus I vote to your answer. – klor Jan 22 '18 at 11:10
  • BTW: where do I use shell variables? The script uses input arguments, but only locally, from command line. I don't see security risk here. – klor Jan 22 '18 at 11:17
  • filenames can contain new line symbols or something else. This symbols must be handled safely. – Egor Vasilyev Jan 22 '18 at 11:21