我知道 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>