如何根据匹配的后续行从文件的行中提取特定字段

如何根据匹配的后续行从文件的行中提取特定字段

我正在尝试复制工作场所的问题。我有一个如下所示的 xml 文件

[~]$ less -N sample.xml
  1     <SOURCE BUSINESSNAME ="" NAME ="TABLE1" FOO="ABCD"..... >
  2         <SOURCEFIELD BUSINESSNAME ="" NAME ="COL_XYZ" />
  3         <SOURCEFIELD BUSINESSNAME ="" NAME ="COL_ABCD" />
  4         ...
  5                 ...
  6     </SOURCE>
  7     <SOURCE BUSINESSNAME ="" NAME ="TABLE2" ....... >
  8             <SOURCEFIELD BUSINESSNAME ="" NAME ="COL_ABCD" />
  9         <SOURCEFIELD BUSINESSNAME ="" NAME ="COL_XYZABC" />    
 10         ...
 11                 ...
 12     </SOURCE>
 13         <SOURCE BUSINESSNAME ="" NAME ="TABLE3" .... >
 14         <SOURCEFIELD BUSINESSNAME ="" NAME ="COL_PQR" />
 15         <SOURCEFIELD BUSINESSNAME ="" NAME ="COL_ABCD" />
 16         ...
 17                 ...
 18     </SOURCE>

现在我想要其中任何一个都类似于 的NAME字段的值。SOURCEFIELD NAMEXYZ

例如,在给定的示例中,我需要TABLE1第 2 行包含COL_XYZ.而且我们也TABLE29COL_XYZABC

我正在考虑某种方式,将行1,2,7,9,13作为输出,然后grep -B1 XYZ|grep -w SOURCE在字段中仅获取1,7输出中的行。

Expected Output:
TABLE1
TABLE2

到目前为止我尝试过的

  • 执行 grepSOURCE不起作用,因为每一行至少有其中一个。
  • 做 aegrep -w "SOURCE|XYZ"不符合我的需要XYZABC将无法满足其条件。

有人可以建议我可以尝试得到想要的结果吗?我在用Linux 2.6.18-371.el5

答案1

您可以使用hold space的功能来完成此操作sed

sed使用-n禁止自动打印输入行的选项运行。

<SOURCE当看到包含的行时,保存价值NAME属性的.sedhold space

当看到<SOURCEFIELD包含的行时XYZ,打印 的内容hold space

#!/bin/sh

sed -n '
    /<SOURCE / {              # execute block {} on lines matching "<SOURCE "
        s/.* NAME *="//       # remove everything upto NAME attribute value
        s/".*//               # remove everything after attribute value
        h                     # copy pattern space to the hold space
    }
    /<SOURCEFIELD.*XYZ/ {     # SOURCEFIELD contains XYZ, execute {} block
        g                     # copy hold space to pattern space
        p                     # print
    }
' "$@"

答案2

sed -netP -eH            -e'# Hold every line and test for s///uccess' \
    -e'\|<[^F]*[ >]|!d'  -e'# if < then F before [ >]: delete'         \
-ex -e'\|_XYZ[^_]*>|!d'  -e'# first exchange buffers; if !XYZ: delete' \
    -e's|[^"]*|\n&\n|4'  -e'# wrap 4th no quotes series in newlines'   \
    -e'D;:P' -eP         -e'# Delete up to first newline, :Print if true'

TABLE1
TABLE2

...当我添加一个XYZ到第三个列表中的最后一个字段,TABLE3打印也...

答案3

谢谢罗伯特·L为了这回答

我还想出了一种组合来grep/awk/sed实现相同的目的,但显然速度较慢。只是想把它放在那里。

egrep -w ""\<SOURCE"|"SOURCEFIELD.*XYZ.*"" sample.xml|grep -B1 XYZ|grep -w SOURCE|\                                                              
> awk -F" NAME =" '{print $2}'|awk '{print $1}'|sed 's/"//g'

相关内容