将两个 grep 合并为一个命令

将两个 grep 合并为一个命令

我有一些 XML,看起来像这样:

    <artifactId>myproject</artifactId>
    <version>1.14.0-SNAPSHOT</version>

我想提取版本,即1.14.0-SNAPSHOT.我知道如何使用两个 grep 和一个管道来做到这一点:

$ grep -A1 "<artifactId>myproject</artifactId>" pom.xml | grep -Eo "\d+.\d+.\d+-SNAPSHOT"

我怎样才能将两者合而为一?我使用 awk 还是 sed 来完成这项任务会更好吗?

答案1

如果你确定<version>在下一行之后myproject

sed -n '
    \|<artifactId>myproject</artifactId>|{
        n                                           #get next line
        s|[[:blank:]]*</\?version>[[:blank:]]*||gp  #remove tags and print
    }
' pom.xml

或者如果你有正则表达式

grep -zoP '<artifactId>myproject</artifactId>\s*\n\s*<version>\K[^<]+' pom.xml

答案2

您在评论中提到您想要一些便携式的东西。这是令人钦佩的,但我真的劝你不要这样做。XML是一种上下文语言,而正则表达式不是。正则表达式根本无法正确解析 XML 结果。

最好的情况是,您得到了一个 hack,只有在 XML 保持相同格式的情况下才有效。但正如 XML 规范所说,格式可以偶然并保留相同的语义,这是一个危险的假设,并且会产生脆弱的代码。

我知道你有理由想要这样做——你已经有了一个答案,为你提供了一种方法。我建议解析器仍然是正确的回答。

但是使用 XML 解析器,您会得到xpath- 这很像正则表达式,但适用于分层信息。

像这样的东西:

#!/usr/bin/env perl
use strict;
use warnings;

use XML::Twig;

my $twig = XML::Twig -> parse ( \*DATA );

my $version = $twig -> get_xpath('//item/artifactId[string()="myproject"]/../version',0)->text;
print $version;

__DATA__
<xml>
  <item>
    <artifactId>myproject</artifactId>
    <version>1.14.0-SNAPSHOT</version>
  </item>
</xml>

希望您能看到它xpath是如何工作的?//item在结构内的任何位置查找项目。[string()=查询文本内容。您可以执行类似[@someAtt="fish"]检查属性之类的操作。

然后我们..向上 ( item) 并获取version元素。然后获取text值。

作为单行者:

perl -MXML::Twig -0777 -e 'print XML::Twig -> parse ( <> ) -> get_xpath('/item/artifactId[string()="myproject"]/../version',0)->text,"\n"    yourxmlfile.xml

现在,我建议是XML::Twig因为我认为它更容易学习。XML::LibXML也相当不错。

但它在 Windows 上与 Strawberry Perl 一起分发,并且可以在许多包管理器中轻松使用 - 或者从CPAN.

或者 -xmlstarlet应该允许你做同样的事情。

相关内容