我知道 xml 解析器是这里的理想方式,但没有一个可用或能够添加到我的环境中。
让我们采用遵循以下结构的 XML:
<CONTAINER>
<FOLDER NAME="I_RS_INT">
</FOLDER>
<FOLDER NAME="I_R_INR">
</FOLDER>
<FOLDER NAME="I_RS_TRN">
</FOLDER>
</CONTAINER>
在 bash 脚本中,我希望删除匹配的所有节点<FOLDER NAME=
或*RS*
删除其中的所有节点<FOLDER NAME != $var_folder
非常感谢任何帮助!
答案1
这应该可以做到:
cat /tmp/xml | sed -e '/<FOLDER NAME=.*RS.*>/ { N; d; }'
对于与两个/
字符之间的模式匹配的每一行,都会执行 {} 中的代码。 N 也将下一行放入模式空间,然后 d 在继续下一行之前删除整个内容。这适用于任何 POSIX 兼容的sed
.
尝试以下操作删除<FOLDER NAME=.*RS.*>
和之间的每一行</FOLDER.>
:
awk '/<FOLDER NAME=.*RS.*>/,/<\/FOLDER>/ {next} {print}' xmlfile
该next
命令停止当前匹配的处理。接下来是一个简单的print
.
答案2
您应该使用 XML 解析器来完成此操作。例如,使用XML小星在命令行上:
$ xmlstarlet ed -d '/CONTAINER/FOLDER[contains(@NAME, "RS")]' data.xml
<?xml version="1.0"?>
<CONTAINER>
<FOLDER NAME="I_R_INR">
</FOLDER>
</CONTAINER>
或者,
$ var="I_R_INR"
$ xmlstarlet ed -d "/CONTAINER/FOLDER[@NAME != '$var']" data.xml
<?xml version="1.0"?>
<CONTAINER>
<FOLDER NAME="I_R_INR">
</FOLDER>
</CONTAINER>
请注意,这两个示例并不等效,因为第一个示例执行子字符串匹配,而第二个示例执行精确匹配。
有了xq
包装纸jq
:
$ xq -x --arg substring "RS" 'del(.CONTAINER.FOLDER[] | select(."@NAME" | contains($substring)))' file.xml
<CONTAINER>
<FOLDER NAME="I_R_INR"></FOLDER>
</CONTAINER>
$ xq -x --arg name "I_R_INR" 'del(.CONTAINER.FOLDER[] | select(."@NAME" != $name))' file.xml
<CONTAINER>
<FOLDER NAME="I_R_INR"></FOLDER>
</CONTAINER>
答案3
好吧,说真的 - 用正则表达式解析 XML 是坏消息。 XML 不是正则语言,因此没有正则表达式可以正确处理它。因此,你写的任何东西都会变得很糟糕且脆弱。
但是,XML
确实有类似于正则表达式的东西,称为xpath
.
为了解决你的问题,我会这样做:
#!/usr/bin/env perl
use strict;
use warnings;
use XML::Twig;
#process the file as XML
my $twig = XML::Twig -> parsefile ( 'your_file.xml' );
#iterate 'FOLDER' elements
foreach my $folder ( $twig -> get_xpath ('//FOLDER' ) ) {
#delete any that regex match /RS/
if ( $folder -> att('NAME') =~ m/RS/ ) {
$folder -> delete;
}
}
#print the result.
$twig -> set_pretty_print('indented_a');
$twig -> print;
答案4
sed -r '/<FOLDER NAME=.*RS.*>/{ :X N; /<\/FOLDER>/d; bX }' file
<CONTAINER>
<FOLDER NAME="I_R_INR">
</FOLDER>
</CONTAINER>