写脚本时遇到的一个问题,在此分享一下
首先我利用awk命令取出某文件中的一个字段,并赋给了一个变量aaa,awk命令如下:
aaa=` awk '{if($0~"inst.stage2=hd")print}' ~/test`
此句我是以“inst.stage2=hd”为参考,在~/test文件中,找出匹配的字段
(awk命令不做详细解释,具体可以参考:https://www.runoob.com/linux/linux-comm-awk.html)
awk命令运行后查找字段结果如下:
我直接利用sed -i ‘s/原字符/替换后字符/g’ 命令对awk查找出来的字段进行修改,会出现错误
出现错误的原因是sed ‘s///g’ 中间填入的原字符和替换字符处,特殊字符必须转义,上图中的/dev/sda1 的两个“/”没有转义
正确语句应为
sed -i "s/inst.stage2=hd:LABEL=\/dev\/sda1/inst.stage2=hd:LABEL=KYLIN-BACKUP/g" ~/test (1-1)
也就是\/dev\/sda1 , “\”为转义字符,是不同于目录的字符,要注意分清
上面的部分只是简单的用awk命令加上sed命令在命令行中进行简单的查找和替换,但如果我的awk查找命令,将结果赋给了一个变量aaa,如果直接使用做替换
sed -i "s/$aaa/inst.stage2=hd:LABEL=KYLIN-BACKUP/g" ~/test
结果不会报错,但是发现test文件并没有按要求进行修改,相关字段仍为【inst.stage2=hd:LABEL=/dev/sda1】
原因:
此时字段通过aaa变量获取,但仍存在字符转义问题,需要对aaa这个变量稍加修改,使sed 运行时得到的结果为带有转义字符,如语句(1-1)所示
解决:
我将变量aaa的内容赋给了第二个变量,取名为a,将里面的“/”都替换为“\/” ,代码如下
a=` echo $aaa | sed 's#\/#\\\/#g'`
解释一下 ,此处的sed 框架是用的 sed 's#原字符#替换后字符#g' ,此时以“#”作为分隔符,为了不与目录的分隔符起冲突,作用其实一样
这里一共六个\ / 这样的字符我们暂时称为【字符1-6】,下面分别解释一下都是什么意思 (手写数字难看,大家忽略~)
1、转义字符“\” (在回车的上面),是为了将【字符2】的 “ / ” 进行转义;
2、原本字符 “ / ”,表示目录的意思,是被【字符1】转义的字符,【字符1】与【字符2】组合在一起 “ \ / ” 放在sed的第一组# #内,对照【sed 's#原字符#替换后字符#g' 】,也就是匹配原句中的两个 “ / ”
3/4/5/6、 想要达到的效果是,替换后的字符变成 “ \ / ” ,但是这两个字符又都是特殊字符,需要转义,将 \ 转义后是 \\ ,将 / 转义后是\ / , 所以连起来就是 \\\/
综上,最后将三个语句连起来,写入脚本
#!/bin/sh aaa=` awk '{if($0~"inst.stage2=hd")print}' ~/test` a=` echo $aaa | sed 's#\/#\\\/#g'` sed -i "s/$a/inst.stage2=hd:LABEL=KYLIN-BACKUP/g" ~/test
第一行是awk取到对应字段
第二行是将取到内容中含有 “ / ” 的字符 都替换为“ \ / ”
第三行是将含有转义字符的变量a,替换成【inst.stage2=hd:LABEL=KYLIN-BACKUP】并写入~/test中(sed -i ,-i这个参数,不加就是不写入,但可以看结果,加 i 就是直接写入到原文件)
结果:
替换前文件内容:
执行脚本后文件内容:
END