Unexpected substitution for & with sed

2019-07-18 07:39发布

问题:

I have a CSV file containing some special characters and their HTML entity names

ex: htm.csv

À,À
Á,Á
Â,Â
Ã,Ã
É,É
Ê,Ê
Í,Í
Ó,Ó
Ô,Ô
Õ,Õ

and I have a number of .php files where these special characters are present. I have written a shell script

#!/bin/bash
IFS=","
while read orig html
do
   for fl in *.php; do
   mv $fl $fl.old
   sed 's/'$orig'/'$html'/g' $fl.old > $fl
   done
done< "htm.csv"

but the problem is when using the contents of $html, it is printing the contents of $orig instead of "&".

回答1:

& is a special character meaning "the whole matched string" in the s/// command. Use \&.



回答2:

Use any character as a command delimiter, here is an example:

sed -Ei "s|$k|$j|g" filename.txt


回答3:

In addition to the special characters you can also make the commands a bit safer and shorter:

  • There's no need for mv if your sed supports -i (in-place replacement)
  • To avoid setting IFS for the rest of the commands you can limit its scope
  • Escape & in $html

The result:

#!/bin/bash
while IFS="," read orig html
do
    for fl in *.php
    do
        sed -i 's/'$orig'/'${html//&/\\&}'/g' "$fl"
    done
done < "htm.csv"

Please add an example if it doesn't work for you. There could be other special characters which would have to be escaped.