站在网络上其他人的伟大(对他们的道具),我跑过这个命令:
perl -0 -p -i -e 's|<nodeName>.*?</nodeName>|$&=~/this/?"":$&|gse' file
它将找到一个XML节点(在本例中为“nodeName”),查找特定字符串(在本例中为“this”),并删除整个节点。这很可爱。
使用此命令,文件如下所示:
<nodeName>
<subNode>those</subNode>
</nodeName>
<nodeName>
<subNode>this</subNode>
</nodeName>
<nodeName>
<subNode>that</subNode>
</nodeName>
<nodeName>
<subNode>these</subNode>
</nodeName>
看起来像这样:
<nodeName>
<subNode>those</subNode>
</nodeName>
<nodeName>
<subNode>that</subNode>
</nodeName>
<nodeName>
<subNode>these</subNode>
</nodeName>
但是,我需要它来查找“this”或“that”,如果找到,则删除整个节点。所以为此,我正在使用这个命令:
perl -0 -p -i -e 's|<nodeName>.*?</nodeName>|$&=~/this/?"":$&|gse' file;perl -0 -p -i -e 's|<nodeName>.*?</nodeName>|$&=~/that/?"":$&|gse' file
这基本上是“两次执行命令以寻找两个不同的东西,但执行相同的操作。”我的问题是,原始的perl命令是否可以简化为在一个命令中查找“this”或“that”?
我试过这个:
perl -0 -p -i -e 's|<nodeName>.*?</nodeName>|$&=~/(this|that)/?"":$&|gse' file
但我对perl有点绿。我认为这可以与此类似:
s/(dog|cat)s are (invited|welcome)/$1s are not $2/;
但事实并非如此。我不确定我希望能达到的目标是否可行。所以最后,我确实得到了一点点。重申一下这个问题:可以简化原始的perl命令,在一个命令中查找“this”或“that”吗?
提前谢谢。
注意:我正在处理未安装xmlstarlet的服务器,我无权安装它。
答案 0 :(得分:5)
由于您的外部正则表达式使用管道|
作为分隔符,因此在内部正则表达式中将管道用作or
时,您将破坏该模式。
perl -0 -p -i -e 's{<nodeName>.*?</nodeName>}{$&=~/(?:this|that)/?"":$&}gse' file
就像它应该工作。我用{}
替换了管道。我还添加了一个非捕获组,因为没有理由保持this|that
可用。
你当然也可以逃避内部|
,但上述解决方案更清晰。
perl -0 -p -i -e 's|<nodeName>.*?</nodeName>|$&=~/(this\|that)/?"":$&|gse' file
另请注意,它可能适用于每个行文件的一个标记,但如果XML更复杂,它将会中断。
答案 1 :(得分:2)
perl -i -0777pe's{
<nodeName>
(?: (?!</nodeName>). )*
(?: this | that )
(?: (?!</nodeName>). )*
</nodeName>
}{}xsg' file
答案 2 :(得分:2)
请 - 代表未来的系统管理员和维护程序员 - 改为使用解析器。
如果要删除包含文本'this'或'that'的'nodeName':
#!/usr/bin/env perl
use strict;
use warnings;
use XML::Twig;
XML::Twig->new(
'pretty_print' => 'indented_a',
'twig_handlers' => {
'nodeName' => sub { $_->delete if $_->text =~ m/this|that/ }
}
)->parse( \*DATA )->print;
__DATA__
<root>
<nodeName>
<subNode>those</subNode>
</nodeName>
<nodeName>
<subNode>this</subNode>
</nodeName>
<nodeName>
<subNode>that</subNode>
</nodeName>
<nodeName>
<subNode>these</subNode>
</nodeName>
</root>
这会设置一个“捕获”nodeName
的小枝处理程序,并在条件适用时删除。
如果你想要单行:
perl -MXML::Twig -e 'XML::Twig->new( 'pretty_print' => 'indented_a', 'twig_handlers' => {'nodeName' => sub { $_->delete if $_->text =~ m/this|that/ }})->parsefile( $ARGV[0] )->print;'
您也可以使用parsefile_inplace
更改原始源文件。