【问题标题】:Use grep to print only the context使用 grep 仅打印上下文
【发布时间】:2016-11-09 16:16:21
【问题描述】:

使用grep,您可以打印与您的搜索查询匹配的行。添加-C 选项将打印两行周围的上下文,如下所示:

> grep -C 2 'lorem'
some context
some other context
**lorem ipsum**
another line
yet another line

同样,您可以使用grep -B 2grep -A 2 分别打印具有前两行或后两行的匹配行,例如:

> grep -A 2 'lorem'
**lorem ipsum**
another line
yet another line

是否可以跳过匹配行而只打印上下文?具体来说,我只想打印恰好在匹配上方 2 行的行,如下所示:

> <some magic command>
some context

【问题讨论】:

  • 不在我所知道的grep 中。像这样使用awkprinting with sed or awk a line following a matching pattern
  • @fedorqui 这适用于以下几行,但我可以修改它以获得前面的几行吗?以前从未使用过 awk。
  • 使用tac 向后打印文件。
  • 然后可以使用-v 排除匹配线吗?
  • 如果你可以允许grep的两个实例被使用,你可以试试grep -v "lorem" &lt; &lt;(grep -A2 "lorem" file)

标签: bash shell awk grep


【解决方案1】:

awk,正如其他人所说,是你的朋友。不过,您不需要复杂的循环或数组或其他垃圾;基本模式就足够了。

当您使用-B N(和--no-group-separator 标志)时,您将获得M=N+1 行组的输出。要精确选择其中一行(在您的问题中,您想要该组中的第一行),您可以使用模运算(使用 GNU awk 测试)。

awk -vm=3 -vx=1 'NR%m==x{print}'

您可以想象这样对行进行编号:它们一直计数,直到您到达匹配项,此时它们又归零。因此将m 设置为N+1,将x 设置为您要提取的行。

1 some context
2 some other context
0 **lorem ipsum**

所以最后的命令是

grep -B2 --no-group-separator lorem $input | awk -vm=3 -vx=1 'NR%m==x{print}'

【讨论】:

    【解决方案2】:

    纯粹通过grep 命令是无法做到这一点的。如果文本中只有一个lorem 实例,您可以通过head 管道输出。

    grep -B2 lorem t | head -1
    

    如果lorem可能出现多次,你可以使用awk

    awk '{second_previous=previous; previous=current_line; current_line=$0}; /lorem/ { print second_previous; }'
    

    这个 awk 命令将每一行(连同前一行和前一行)保存在变量中,因此当它遇到包含lorem 的行时,它会打印倒数第二行。如果lorem 恰好出现在输入的第一行或第二行,则不会打印任何内容。

    【讨论】:

      【解决方案3】:

      如果您可以允许使用几个 grep 实例,您可以像我在 cmets 部分中提到的那样尝试。

      $ grep -v "lorem" < <(grep -A2 "lorem" file)
      another line
      yet another line
      
      $ grep -A2 "lorem" file | grep -v "lorem"
      another line
      yet another line
      

      如果您对awk 的剂量感兴趣,有一个很酷的方法可以做到这一点

      $ awk -v count=2 '{a[++i]=$0;}/lorem/{for(j=NR-count;j<NR;j++)print a[j];}' file
      another line
      yet another line
      

      它的工作原理是将整个文件存储在自己的数组中,并在搜索模式 lorem 后,存储行号 (NR) 的 awk 特殊变量指向找到模式的确切行.如果我们按照awk 变量-v count 的指示在它之前循环两行,我们可以打印所需的行。

      如果您也对打印模式感兴趣,只需将 for 循环中的条件更改为 j&lt;=NR 而不是 j&lt;NR。就是这样!

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2015-10-24
        • 2017-01-06
        • 1970-01-01
        • 2018-02-13
        • 2012-09-22
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多