最近写脚本的时候碰到了这方面的问题,到网上搜了半天也没找到好一点的方案或总结。今天我把自己的摸索写一下。
首先是Sed里使用变量的问题
网上有人总结了四种方案:
1. eval sed 's/$a/$b/' filename
2. sed "s/$a/$b/" filename
3. .sed 's/'$a'/'$b'/' filename
4. .sed s/$a/$b/ filename
我比较喜欢第二种,也就是:Sed后面的表达式一般用单引号引起来('),当需要使用变量时就换用双引号(")。
关于单双引号的区别:
单引号:shell处理命令时,对其中的内容不做任何处理。即此时是引号内的内容是sed命令所定义的格式。
双引号:shell处理命令时,要对其中的内容进行算术扩展。如果想让shell扩展后得到sed命令所要的格式,使用命令:sed -n "/\\\\$/p" haha,扩展后得到的结果即\\$.
因此对于语句类似:
$Comfilename="/home/evan/sandbox/Main/"
1. echo $Comfilename | sed 's#\/#\\\/#g'
2. echo $Comfilename | sed "s#\/#\\\/#g"
第一个的结果是:\/home\/evan\/sandbox\/Main\/
而第二个还是:/home/evan/sandbox/Main/ 因为双引号会将“\/“解释为”/“,所以sed "s#\/#\\\/#g"被Shell解释成了sed s#/#\/#g 到sed里执行时又把”\/“转义为”/“了,这样相当于进行了了两次解释,就得不到想要的结果了。
这个例子告诉我当没必要用双引号的的时候就不要用,要不然说不定什么时候你就会很郁闷。当然单引号效率要比双引号高也是不要滥用双引号的原因之一。
言归正传,如何在sed的变量里使用那些特殊的需要转义的字符呢?
网上提出的一种方法是将sed里表示替换用的s后面的表示分隔用的字符换成别的变量里没有的字符这样就相当于变量里没有要转义的字符了。
如:
sed –i "s# $Comfilename#/Root/#" filename.list
这是一个好办法。但很不幸我需要的是删除“d”不是替换“s“。当我把同样的方法用于删除时似乎没有起到作用:sed –i "# $Comfilename#d" filename.list
于是只能自己手工先改写变量
$Comfilename="/home/evan/sandbox/Main/"
Tempname=` echo $Comfilename | sed 's#\/#\\\/#g'` (这里把反单引号执行的结果给临时变量,同样的方法可以改写其他需要转义的符号。)
sed –i "# $ Tempname #d" filename.list
个人感觉这种方法不是很好,但在网上找了半天也没找到更好的方法,只能感叹SHELL的博大精深,吾辈还得慢慢求索。