sed疑难杂症:关于shell变量替换

sed是linux下一个强大的工具,主要用于文本查找并替换,在shell编程中,我们会经常接触到sed命令,在网上已经有很多介绍sed使用的文章了,所以本文不会再介绍sed的使用细节(推荐一篇比较好的sed使用指南:Sed Tutorials)。

在这里分享一个自己实际工作中碰到的有关sed的疑难杂症的解决之道吧,以帮助后来者少走些弯路:

我们最常见的sed替换,如下面的例子:

# 例1:sed的静态替换
 ➜ ✗> echo 'year/month' | sed 's/month/2015/g' | sed 's/month/07/g'
 2015-07

然而,有的时候,这种静态替换不能满足需求,替换值有可能是一个shell变量,google下,发现已经有相应的解决办法了:

# 例2:替换值为shell变量
➜ ✗> year=$(echo '2015') && echo ${year}
2015
➜ ✗> echo 'year/month' | sed "s/year/${year}/g" | sed 's/month/07/g'
2015/07

如果要替换的字符串中包含了特殊字符(Special Characters),又该怎么办?看下面的例子:

# 例3:替换模式中包含特殊字符
➜ ✗> echo '$year/month' | sed 's/$year/2015/g' | sed 's/month/07/g'
$year/07
➜ ✗> echo '$year/month' | sed 's/\$year/2015/g' | sed 's/month/07/g'
2015/07

从以上例子,我们可以看出,特殊字符的替换可以通过转义特殊字符来解决。

Note:sed替换模式中的特殊字符包括:? \ . [ ] ^ $ /

生活似乎很美好,尽在我们的掌握中,但是,我们还可能会碰到一种比较特殊的情况(本人就碰到了,泪奔啊T^T):

除了替换的字符串中包含特殊字符dollar,需要转义外,替换值还是个shell变量,将例2和例3的解决办法合并之:

# 例5:替换的字符串中包含特殊字符dollar,且替换值还是个shell变量,错误版本
➜ ✗> echo '$year$/month' | sed "s/\$year\$/${year}/g" | sed 's/month/07/g'
$year$/07

结果发现,这种做法行不通,和我们的预期不符合,求助万能的google,然并卵,问题依旧没有解决,苦思无果,在行将放弃之际,突然灵机一动,会不会因为双引号解shell变量引用时,已经用掉dollar符号的转义,所以导致sed无法正确识别特殊字符dollar呢?抱着试一试的心态,修改下:

# 例5:替换的字符串中包含特殊字符dollar,且替换值还是个shell变量,正确版本
➜ ✗> echo '$year$/month' | sed "s/\\\$year\\\$/${year}/g" | sed 's/month/07/g'
$year$/07

哐,果然和我们猜想的一样,需要两次转义,问题解决之。

最后的结论

在shell编程中,对于dollar这种有非常特殊含义的字符,一定要谨慎选用,以免出现一些莫名其妙的问题。

Table of Contents