如何在使用awk或grep匹配第一个关键字之前搜索第二个关键字的第一个匹配项?

时间:2016-04-29 23:24:54

标签: regex bash awk grep

我有一个这样的清单:

TAGDESCRIPTIONS example
TAGS            tmp
TAGS            line
TAGDESCRIPTIONS bar
TAGS            com                      
TAGS            foo     

获取TAGDESCRIPTIONS的匹配后,awk或grep中的正确命令是什么才能使foo行与foo行匹配?因此,在搜索bar时,会打印{{1}}。

3 个答案:

答案 0 :(得分:2)

$ awk '/TAGDESCRIPTIONS/{d=$2} /foo/{print d}' file
bar

答案 1 :(得分:1)

Grep不适用于此,因为它主要用于过滤特定的行,但您询问不同行之间的关系。 Grep可以强制通过(ab)使用-z标志来执行多行中的某些事物,该标志需要空字节分隔的行,但它通常不漂亮。

Awk 1 允许一个简单的解决方案:

$ awk 'BEGIN{RS="TAGDESCRIPTIONS"}/foo/{print $1}' infile
bar

这会将记录分隔符RS设置为TAGDESCRIPTIONS,因此输入被解释为三条记录(\n代表换行符):

<empty record>
 example\nTAGS            tmp\nTAGS            line\n
 bar\nTAGS            com\nTAGS            foo\n

第一个是空的,因为文件以记录分隔符开头。

对于每条记录,我们在第一个换行符之前的内容是标记描述。我们用

说什么
/foo/{print $1}

是这样的:如果记录与foo匹配,则打印记录的第一个字段(描述)。

这根本不是防弹的。如果描述由多个单词组成,则仅打印第一个单词。如果描述而不是标记匹配,那就是误报。如果记录包含foobar但不包含bar,则该记录仍会匹配。

这个输入示例将抛弃简单的解决方案:

TAGDESCRIPTIONS foo
TAGS            blah
TAGDESCRIPTIONS example
TAGS            tmp
TAGS            line
TAGS            foobar
TAGS            barfoo
TAGDESCRIPTIONS bar and more words
TAGS            com
TAGS            foo

标记说明包含foo,标记包含 foo,标记说明包含多个字词。

我们可以通过在新行分割记录,然后将除描述之外的每个元素与搜索字符串进行比较来解决所有问题:

awk '
BEGIN { RS = "TAGDESCRIPTIONS *" }

{
    # Split record at newlines, store in arr
    split($0, arr, "\n")

    # Skip first element (description), compare to 'foo'
    for (i = 2; i <= length(arr); ++i) {
        if (arr[i] ~ " +foo$") {

            # Matches - print description
            print arr[1]

            # No need to look at the rest of the record
            break
        }
    }
}' infile

导致

bar and more words

1 GNU awk,确切地说,由于多字符记录分隔符和length函数。

答案 2 :(得分:0)

我会试一试 我不知道grep或awk,但下面只是一个原始正则表达式 使用PCRE样式前瞻和内联修改器组。

(?ms)^TAGDESCRIPTIONS\s+(\w*)\s+(?:(?!^TAGDESCRIPTIONS).)+^TAGS\s+foo

扩展

 (?ms)
 ^ TAGDESCRIPTIONS \s+ 
 ( \w* )                       # (1)
 \s+ 
 (?:
      (?! ^ TAGDESCRIPTIONS )
      . 
 )+
 ^ TAGS \s+ foo

bar字在捕获组1中。根据需要充实正则表达式。

输出

 **  Grp 0 -  ( pos 68 , len 83 ) 
TAGDESCRIPTIONS bar
TAGS            com                      
TAGS            foo  
 **  Grp 1 -  ( pos 84 , len 3 ) 
bar