如何在bash中从提到的文件格式中检索匹配的记录

时间:2016-12-02 22:13:56

标签: bash shell awk sed

XYZNA0000778800Z
16123000012300321000000008000000000000000
16124000012300322000000007000000000000000
17234000012300323000000005000000000000000
17345000012300324000000004000000000000000
17456000012300325000000003000000000000000
9
XYZNA0000778900Z
16123000012300321000000008000000000000000
16124000012300322000000007000000000000000
17234000012300323000000005000000000000000
17345000012300324000000004000000000000000
17456000012300325000000003000000000000000
9

我有以上文件格式,我想从中找到匹配的记录。例如,匹配从XYZ开始在线的数字(7789),并且一旦匹配,在下面的行中查找匹配的数字(7345),从1开始,直到它到达从9开始的行。检索整个行记录。如何使用shell脚本,awk,sed或任何组合来完成此任务。

预期产出:

 XYZNA0000778900Z
 17345000012300324000000004000000000000000

3 个答案:

答案 0 :(得分:1)

用sed可以做到:

$ sed -n '/^XYZ.*7789/,/^9$/{/^1.*7345/p}' file
17345000012300324000000004000000000000000

故障:

sed -n '                                ' # -n disabled automatic printing
        /^XYZ.*7789/,                     # Match line starting with XYZ, and
                                          # containing 7789
                            /^1.*7345/p   # Print line starting with 1 and
                                          # containing 7345, which is coming
                                          # after the previous match
                     /^9$/ {           }  # Match line that is 9

range { stuff }会在stuff内执行range,在这种情况下,范围从/^XYZ.*7789/开始,以/^9$/结尾。

.*将匹配除换行符之外的任何内容。

答案 1 :(得分:0)

我使用awk:

awk -v rid=7789 -v fid=7345 -v RS='\n9\n' -F '\n' 'index($1, rid) { for(i = 2; i < $NF; ++i) { if(index($i, fid)) { print $i; next } } }' filename

其工作原理如下:

  • -v RS='\n9\n'是整个事情的核心。 Awk将其输入分成记录(默认行)。这会将记录分隔符设置为\n9\n,这意味着记录由行分隔,并且单个9。这些记录进一步分为字段和
  • -F '\n'告诉awk记录中的字段由换行符分隔,以便记录中的每一行都成为一个字段。
  • -v rid=7789 -v fid=7345将两个awk变量ridfid(分别称为记录标识符和字段标识符。名称是任意的。)设置为搜索字符串。您可以直接在awk脚本中对这些进行编码,但这样可以更容易,更安全地将值替换为shell变量(我希望您可以这样做)。

然后是代码:

index($1, rid) {               # In records whose first field contains rid  
  for(i = 2; i < $NF; ++i) {   # Walk through the fields from the second
    if(index($i, fid)) {       # When you find one that contains fid
      print $i                 # Print it,
      next                     # and continue with the next record.
    }                          # Remove the "next" line if you want all matching
  }                            # fields.
}

请注意,POSIX awk并不严格要求使用多字符记录分隔符,并且我不确定BSD awk是否接受它。不过,GNU awk和mawk都可以。

编辑:第一次误读问题。

答案 2 :(得分:0)

这可能适合你(GNU sed):

sed -n '/^XYZ/h;//!H;/^9/!b;x;/^XYZ[^\n]*7789/!b;/7345/p' file

使用选项-n表示sed的grep-like性质。收集以XYZ开头并以9结尾的记录。拒绝标题中没有7789的所有记录。打印包含7345的所有剩余记录。

如果7345始终跟随标题,则可以缩短为:

sed -n '/^XYZ/h;//!H;/^9/!b;x;/^XYZ[^\n]*7789.*7345/p' file

如果所有记录格式正确(开始XYZ并以9结尾),请使用:

sed -n '/^XYZ/h;//!H;/^9/!b;x;/^[^\n]*7789.*7345/p' file