如何在 Linux 中使用 grep 或 awk 从 xml 中的字符串中提取值

如何在 Linux 中使用 grep 或 awk 从 xml 中的字符串中提取值

我有一个文件包含:

DEVICE="7" PGMNR="24" VCONF="800"

在此文件中,我想查找PGMNR="24"并且需要不带".

可以PGMNR="24"位于行中的任意位置。行的开头、中间或末尾。

我不知道如何获得该值。

来自评论的 XML 示例:

<?xml version="1.0" encoding="utf-8"?>
<NT3Config>
  <System
      Dev="7"
      PGMNR="24"
      VCONF="800 800"
  />
  <WA-NT
      info="23 1 1 1 61 17 00"
      name="Soja T#1"
  />
  <WA-NT
      info="23 2 2 1 61 17 00"
      name="MatadorM"
  />
  <SCALE
      AdNr="0"
      Calib="0 0 0 0 0 0"
      Setting="0 0 0 0 0 0 0"
  />
  <SCALE
      AdNr="1"
      Calib="0 0 0 0 0 0"
      Setting="0 0 0 0 0 0 0"
  />
  <SCALE
      AdNr="2"
      Calib="0 0 0 0 0 0"
      Setting="0 0 0 0 0 0 0"
  />
  <GSM
      PIN=""
      PORT="0"
      TLF=""
  />
</NT3Config>

答案1

您可以grep与 PCRE ( -P) 一起使用:

grep -Po 'PGMNR=\"\K[^"]+(?=\")' file.txt
  • PGMNR=\"将匹配该PGMNR="部分,\K将放弃匹配

  • [^"]+将包含号码

  • 零宽度正向先行模式(?=\")将确保数字后面跟着一个"

答案2

我已经使用解析器回答了这个问题 - 我认为这是“正确的方法”。

这将是“错误的方式”,但应该使用最少量的 POSIX 工具来解决这个问题:

grep PGMNR $filename | sed -e 's/.*PGMNR=\"//' -e 's/\".*//'

答案3

拜托——不要。 XML 不能很好地与正则表达式和基于行的解析配合使用,因为您可以在 XML 中执行许多语义相同但具有不同“模式匹配”的操作。

xmlstarlet可以提取一个xpath表达式,为您提供价值。

或者我最喜欢的是使用 perl 来XML::Twig解析 XML,然后再次以这种方式获取您想要的值。

#!/usr/bin/env perl

use strict;
use warnings;

use XML::Twig;

my $twig = XML::Twig -> new ( 'pretty_print' => 'indented_a' ) ->  parse ( \*DATA );
print "PGMNR: ", $twig -> get_xpath('//System',0) -> att('PGMNR'),"\n";

__DATA__
<?xml version="1.0" encoding="utf-8"?>
<NT3Config>
<System Dev="7" PGMNR="24" VCONF="800 800" /> 
<WA-NT name="Soja T#1" info="23 1 1 1 61 17 00" />
<WA-NT name="MatadorM" info="23 2 2 1 61 17 00" />
<SCALE AdNr="0" Setting="0 0 0 0 0 0 0" Calib="0 0 0 0 0 0" />
<SCALE AdNr="1" Setting="0 0 0 0 0 0 0" Calib="0 0 0 0 0 0" />
<SCALE AdNr="2" Setting="0 0 0 0 0 0 0" Calib="0 0 0 0 0 0" />
<GSM TLF="" PIN="" PORT="0" />
</NT3Config>

如果需要的话,这可以是“一行”,或者您也可以xmlstarlet使用 XPATH。

perl -0777 -MXML::Twig -e 'print XML::Twig -> parse ( <> )-> get_xpath('//System',0) -> att('PGMNR');'

注意 - 我强烈反对基于正则表达式的解析的原因是因为这些都是呈现 XML 的完全有效的方式:

<?xml version="1.0" encoding="utf-8"?>
<NT3Config>
  <System
      Dev="7"
      PGMNR="24"
      VCONF="800 800"
  />
  <WA-NT
      info="23 1 1 1 61 17 00"
      name="Soja T#1"
  />
  <WA-NT
      info="23 2 2 1 61 17 00"
      name="MatadorM"
  />
  <SCALE
      AdNr="0"
      Calib="0 0 0 0 0 0"
      Setting="0 0 0 0 0 0 0"
  />
  <SCALE
      AdNr="1"
      Calib="0 0 0 0 0 0"
      Setting="0 0 0 0 0 0 0"
  />
  <SCALE
      AdNr="2"
      Calib="0 0 0 0 0 0"
      Setting="0 0 0 0 0 0 0"
  />
  <GSM
      PIN=""
      PORT="0"
      TLF=""
  />
</NT3Config>

和这个:

<?xml version="1.0" encoding="utf-8"?>
<NT3Config
><System
Dev="7"
PGMNR="24"
VCONF="800 800"
/><WA-NT
info="23 1 1 1 61 17 00"
name="Soja T#1"
/><WA-NT
info="23 2 2 1 61 17 00"
name="MatadorM"
/><SCALE
AdNr="0"
Calib="0 0 0 0 0 0"
Setting="0 0 0 0 0 0 0"
/><SCALE
AdNr="1"
Calib="0 0 0 0 0 0"
Setting="0 0 0 0 0 0 0"
/><SCALE
AdNr="2"
Calib="0 0 0 0 0 0"
Setting="0 0 0 0 0 0 0"
/><GSM
PIN=""
PORT="0"
TLF=""
/></NT3Config>

和这个:

<?xml version="1.0" encoding="utf-8"?>
<NT3Config><System Dev="7" PGMNR="24" VCONF="800 800"/><WA-NT info="23 1 1 1 61 17 00" name="Soja T#1"/><WA-NT info="23 2 2 1 61 17 00" name="MatadorM"/><SCALE AdNr="0" Calib="0 0 0 0 0 0" Setting="0 0 0 0 0 0 0"/><SCALE AdNr="1" Calib="0 0 0 0 0 0" Setting="0 0 0 0 0 0 0"/><SCALE AdNr="2" Calib="0 0 0 0 0 0" Setting="0 0 0 0 0 0 0"/><GSM PIN="" PORT="0" TLF=""/></NT3Config>

和这个:

<?xml version="1.0" encoding="utf-8"?>
<NT3Config>
  <System Dev="7" PGMNR="24" VCONF="800 800"/>
  <WA-NT info="23 1 1 1 61 17 00" name="Soja T#1"/>
  <WA-NT info="23 2 2 1 61 17 00" name="MatadorM"/>
  <SCALE AdNr="0" Calib="0 0 0 0 0 0" Setting="0 0 0 0 0 0 0"/>
  <SCALE AdNr="1" Calib="0 0 0 0 0 0" Setting="0 0 0 0 0 0 0"/>
  <SCALE AdNr="2" Calib="0 0 0 0 0 0" Setting="0 0 0 0 0 0 0"/>
  <GSM PIN="" PORT="0" TLF=""/>
</NT3Config>

您甚至可能会遇到上面的一些一元标签被显式关闭的情况:

<System Dev="7" PGMNR="24" VCONF="800 800"/>   

和:

<System Dev="7" PGMNR="24" VCONF="800 800"></System>

就 XML 而言,两者说的是同一件事。

纯粹是因为锁定系统的额外约束,这是一种非常肮脏的方法 - 但请注意上面的警告 - 我们不再解析 XML,我们正在处理纯文本,而且它很容易被破坏。 (脆弱的代码会让您的系统管理员感到难过)。

#!/usr/bin/env perl

use strict;
use warnings;

local $/;
my ( $PGMNR ) = <DATA> =~ m/PGMNR=\"(\d+)\"/; 
print $PGMNR;

__DATA__
<?xml version="1.0" encoding="utf-8"?>
<NT3Config>
<System Dev="7" PGMNR="24" VCONF="800 800" /> 
<WA-NT name="Soja T#1" info="23 1 1 1 61 17 00" />
<WA-NT name="MatadorM" info="23 2 2 1 61 17 00" />
<SCALE AdNr="0" Setting="0 0 0 0 0 0 0" Calib="0 0 0 0 0 0" />
<SCALE AdNr="1" Setting="0 0 0 0 0 0 0" Calib="0 0 0 0 0 0" />
<SCALE AdNr="2" Setting="0 0 0 0 0 0 0" Calib="0 0 0 0 0 0" />
<GSM TLF="" PIN="" PORT="0" />
</NT3Config>

或者用 perl 编写 oneliner:

perl -0777 -e 'print <> =~ m/PGMNR=\"(\d+)\"/;'

相关内容