Shell中sed替换文件cmd行结果异常,寻求解决办法
问题描述
我有一个sample.txt文件,内容如下:
# sample.txt adc=lalalala cmd="echo hihi && echo yoyo" cda=lolololo
我希望修改其中的cmd行,编写了如下脚本:
old=`cat ./sample.txt|grep cmd` app=' && echo dudu"' new=${old:0:-1}${app} sed -i "s/${old}/${new}/g" ./sample.txt
期望得到的结果是:
adc=lalalala cmd="echo hihi && echo yoyo && echo dudu" cda=lolololo
但实际执行后得到异常结果:
adc=lalalala cmd="echo hihi cmd="echo hihi && echo yoyo"cmd="echo hihi && echo yoyo" echo yoyo cmd="echo hihi && echo yoyo"cmd="echo hihi && echo yoyo" echo dudu" cda=lolololo
我也尝试了使用sed -i "s#${old}#${new}#g" ./sample.txt,但结果没有区别,希望能得到帮助。
问题原因
你的脚本出问题的核心是old变量里包含了sed的元字符——比如&。在sed的替换语法中,&代表匹配到的整个内容。你的old值是cmd="echo hihi && echo yoyo",里面的&&会被sed解析成两个“匹配内容占位符”,替换时每个&都会被替换成原来的old内容,直接导致字符串重复。
另外,变量里的双引号也会干扰sed的语法解析,进一步加剧混乱。
解决方案
不需要先提取整行再替换,直接用sed定位cmd行修改更简单可靠:
方案1:直接在cmd行末尾引号前追加内容
sed -i 's/^\(cmd=".*\)"$/\1 && echo dudu"/' sample.txt
解释:
^匹配行开头,确保只修改以cmd=开头的行\(cmd=".*\)捕获cmd="到最后一个引号前的所有内容(用括号分组,后续用\1引用)"$匹配行末尾的引号\1 && echo dudu"把捕获的内容加上要追加的部分,再补上闭合引号
方案2:用变量控制追加内容(动态修改场景)
如果需要动态指定要追加的内容,可以用变量实现:
append=' && echo dudu' sed -i "s/^\(cmd=\".*\)\"$/\1${append}\"/" sample.txt
方案3:直接替换cmd的完整值(非追加场景)
如果是要直接替换cmd的整个值,而非追加内容,可以用:
sed -i 's/^cmd=".*"/cmd="echo hello world"/' sample.txt
验证结果
执行上述任意一个方案后,sample.txt的内容会符合预期:
# sample.txt adc=lalalala cmd="echo hihi && echo yoyo && echo dudu" cda=lolololo
内容的提问来源于stack exchange,提问作者furynerd
相关产品推荐
相关产品推荐

