-->

Assigning a value having semicolon (';') t

2019-02-26 04:35发布

问题:

I'm trying to escape ('\') a semicolon (';') in a string on unix shell (bash) with sed. It works when I do it directly without assigning the value to a variable. That is,

$ echo "hello;" | sed 's/\([^\\]\);/\1\\;/g'
hello\;
$

However, it doesn't appear to work when the above command is assigned to a variable:

$ result=`echo "hello;" | sed 's/\([^\\]\);/\1\\;/g'`
$ 
$ echo $result
hello; 
$

Any idea why?

I tried by using the value enclosed with and without quotes but that didn't help. Any clue greatly appreciated.

btw, I first thought the semicolon at the end of the string was somehow acting as a terminator and hence the shell didn't continue executing the sed (if that made any sense). However, that doesn't appear to be an issue. I tried by using the semicolon not at the end of the string (somewhere in between). I still see the same result as before. That is,

$ echo "hel;lo" | sed 's/\([^\\]\);/\1\\;/g'
hel\;lo
$
$ result=`echo "hel;lo" | sed 's/\([^\\]\);/\1\\;/g'`
$
$ echo $result
hel;lo
$

回答1:

I find it interesting that the use of back-ticks gives one result (your result) and the use of $(...) gives another result (the wanted result):

$ echo "hello;" | sed 's/\([^\\]\);/\1\\;/g'
hello\;
$ z1=$(echo "hello;" | sed 's/\([^\\]\);/\1\\;/g')
$ z2=`echo "hello;" | sed 's/\([^\\]\);/\1\\;/g'`
$ printf "%s\n" "$z1" "$z2"
hello\;
hello;
$

If ever you needed an argument for using the modern x=$(...) notation in preference to the older x=`...` notation, this is probably it. The shell does an extra round of backslash interpretation with the back-ticks. I can demonstrate this with a little program I use when debugging shell scripts called al (for 'argument list'); you can simulate it with printf "%s\n":

$ z2=`echo "hello;" | al sed 's/\([^\\]\);/\1\\;/g'`
$ echo "$z2"
sed
s/\([^\]\);/\1\;/g
$ z1=$(echo "hello;" | al sed 's/\([^\\]\);/\1\\;/g')
$ echo "$z1"
sed
s/\([^\\]\);/\1\\;/g
$ z1=$(echo "hello;" | printf "%s\n" sed 's/\([^\\]\);/\1\\;/g')
$ echo "$z1"
sed
s/\([^\\]\);/\1\\;/g
$ 

As you can see, the script executed by sed differs depending on whether you use x=$(...) notation or x=`...` notation.

s/\([^\]\);/\1\;/g            # ``
s/\([^\\]\);/\1\\;/g          # $()

Summary

Use $(...); it is easier to understand.



回答2:

You don't need sed (or any other regex engine) for this at all:

s='hello;'
echo "${s//;/\;}"

This is a parameter expansion which replaces ; with \;.

That said -- why are you trying to do this? In most cases, you don't want escape characters (which are syntax) to be inside of scalar variables (which are data); they only matter if you're parsing your data as syntax (such as using eval), which is a bad idea for other reasons, and best avoided (or done programatically, as via printf %q).



回答3:

You need to use four (three also work). I guess its because it's interpreted twice, first one by the sed command and the second one by the shell when reading the content of the variable:

result=`echo "hello;" | sed 's/\([^\\]\);/\1\\\\;/g'`

And

echo "$result"

yields:

hello\;