我有下面的命令来查找下一行包含该行之后的所有.xml
文件。<active>true</active>
<codePool>community</codePool>
grep -rzl '<active>true</active>.*<codePool>community</codePool>' --include='*.xml' --color=always
现在如何将其与将标签内的字符串sed
替换为匹配行上的字符串相结合?true
<active>...
false
答案1
您应该使用 XML 解析工具来解析 XML 数据。xmlstarlet
是一个不错的选择。正则表达式不够强大(典范参考)
如果您的数据如下所示:
<root>
<foo>
<active>true</active>
<codePool>private</codePool>
</foo>
<foo>
<active>true</active>
<codePool>community</codePool>
</foo>
</root>
然后
xmlstarlet ed --update '//active[.="true" and ../codePool="community"]' -v false file.xml
生产
<?xml version="1.0"?>
<root>
<foo>
<active>true</active>
<codePool>private</codePool>
</foo>
<foo>
<active>false</active>
<codePool>community</codePool>
</foo>
</root>
这是一个 awk 程序,它可以执行您的请求。请记住,它很脆弱:如果输入发生变化,此代码将停止工作。它确实只使用普通的字符串操作。
awk '
BEGIN {
marker = "<codePool>community</codePool>"
srch = "<active>true</active>"
repl = "<active>false</active>"
}
index($0, marker) {
i = index(prev, srch)
if (i > 0)
prev = substr(prev, 1, i-1) repl substr(prev, i+length(srch))
}
{
if (prev) print prev
prev = $0
}
END {if (prev) print prev}
'
答案2
感谢@glennjackman 的回答,我也成功地用下面的代码实现了我的要求,如果输入发生变化,它很容易受到攻击,但它将保持一致,保持 Magento 的 xml 文件的固定目录结构和文件格式:
for filename in *.xml; do
if grep -q '<codePool>community</codePool>' "$filename"; then
if [[ $filename != *"Mage_"* ]]; then
sed -i.bak 's/<active>true<\/active>/<active>false<\/active>/g' "$filename"
fi
fi
done
这样,我还可以按照我想要的方式首先备份那些将要被修改的文件。
希望这可以简化事情,并重定向所有/尽可能多的人使用国内库,而不是安装不允许在远程 SSH/VPN 网络上安装的第三方工具。