在多个 xml 文件中使用 grep 进行替换

在多个 xml 文件中使用 grep 进行替换

我有下面的命令来查找下一行包含该行之后的所有.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 网络上安装的第三方工具。

相关内容