【问题标题】:Advanced grep unix高级grep unix
【发布时间】:2010-12-13 17:29:26
【问题描述】:

通常 grep 命令用于显示包含指定模式的行。有没有办法在包含指定模式的行之前和之后显示 n 行?

这可以使用 awk 来实现吗?

【问题讨论】:

  • @Artelius,我不能依赖其他软件。
  • 请尝试我的 awk 解决方案,如果它有效,请告诉我们。
  • 它不工作,我得到了类似 awk: 第 1 行附近的语法错误 awk: 在第 1 行附近退出
  • 搜索 nawk 看看你有没有。如果你有它,那就用它来代替。

标签: unix aix


【解决方案1】:

是的,使用

grep -B num1 -A num2 

在匹配前包含 num1 行上下文,在匹配后包含 num2 行上下文。

编辑:

似乎 OP 正在使用 AIX。这有一组不同的选项,不包括 -B 和 -A

this link 描述了 AIX 4.3 上的 grep(看起来不太乐观

Matt 的 perl 脚本可能是更好的解决方案。

【讨论】:

  • 它在我的系统上不起作用 grep -B 3 -A 2 Sunny sachin grep: 非法选项 - B 用法:grep -hblcnsviw 模式文件。 . .
  • 我已经重新标记了这个问题。我希望 AIX 专家能来。
【解决方案2】:

这是我通常在 AIX 上做的事情:

before=2  << The number of lines to be shown Before >>
after=2   << The number of lines to be shown After >>
grep -n <pattern> <filename> | cut -d':' -f1 |  xargs  -n1 -I % awk "NR<=%+$after && NR>=%-$before" <filename>

如果您不想要额外的 2 个变量,您可以随时使用它一行:

grep -n <pattern> <filename> | cut -d':' -f1 |  xargs  -n1 -I % awk 'NR<=%+<<after>> && NR>=%-<<before>>' <filename>

假设我有一个模式“堆栈”并且文件名是 flow.txt 我想要 2 行之前和 3 行之后。命令如下:

grep -n 'stack' flow.txt | cut -d':' -f1 |  xargs  -n1 -I % awk 'NR<=%+3 && NR>=%-2' flow.txt

我只想要 2 行之前 - 命令将是这样的:

grep -n 'stack' flow.txt | cut -d':' -f1 |  xargs  -n1 -I % awk 'NR<=% && NR>=%-2' flow.txt

我只想要 3 行之后 - 命令将是:

grep -n 'stack' flow.txt | cut -d':' -f1 |  xargs  -n1 -I % awk 'NR<=%+3 && NR>=%' flow.txt

多个文件 - 将其更改为 awk 和 grep。从上面看,文件名为 flow.* 的模式“堆栈” - 前 2 行,后 3 行。该命令将类似于:

    awk 'BEGIN { 
    before=1; after=3; pattern="stack";
    i=0; hold[before]=""; afterprints=0}
    { 
    #Print the lines from the previous Match
    if (afterprints > 0)
      {
      print FILENAME ":" FNR ":" $0
      afterprints-- #keep a track of the lines to print after - this can be reset if a match is found
      if (afterprints == 0) print "---"
      }
    #Look for the pattern in current line
    if ( match($0, pattern) > 0 )
      {
      # print the lines in the hold round robin buffer from the current line to line-1
      #  if (before >0)  => user wants lines before avoid divide by 0 in %
      #  and afterprints => 0 - we have not printed the line already
      for(j=i; j < i+before && before > 0 && afterprints == 0 ; j++)
        print hold[j%before]
      if (afterprints == 0) #  print the line if we have not printed the line already
        print FILENAME ":" FNR ":" $0
      afterprints=after
      }
    if (before > 0) # Store the lines in the round robin hold buffer
      { hold[i]=FILENAME ":" FNR ":" $0
        i=(i+1)%before }
  }' flow.*

【讨论】:

  • 当我想匹配更多像flow这样的文件时,我应该如何重写它。*
  • 您可以在 2 个地方用 flow.* 替换 flow.txt,一次用于 grep,一次用于 awk。例如 - 对于模式“堆栈”,文件名是 flow.* - 前 2 行,后 3 行。该命令将类似于:grep -n 'stack' flow.* | cut -d':' -f1 | xargs -n1 -I % awk 'NR&lt;=%+3 &amp;&amp; NR&gt;=%-2' flow.*
  • 为了清晰起见更新了上面的帖子。
  • 我不认为它会起作用,因为 cut 现在返回文件名并且没有出现行
  • 是的,你是对的。我们可以使用 -f2 cut -d':' -f2 告诉我它是否有效。
【解决方案3】:

从标签来看,系统可能有一个不支持提供上下文的 grep(Solaris 是一个不支持提供上下文的系统,我不记得有关 AIX 的信息)。如果是这种情况,http://www.sun.com/bigadmin/jsp/descFile.jsp?url=descAll/cgrep__context_grep 有一个 perl 脚本可能会有所帮助。

【讨论】:

    【解决方案4】:

    如果你有 sed 你可以使用这个 shell 脚本

    BEFORE=2
    AFTER=3
    FILE=file.txt
    PATTERN=pattern
    for i in $(grep -n $PATTERN $FILE | sed -e 's/\:.*//')
      do head -n $(($AFTER+$i)) $FILE | tail -n $(($AFTER+$BEFORE+1))
    done
    

    它的作用是, grep -n 为每个匹配项加上它所在的行的前缀,sed 删除除它所在的行之外的所有匹配项。然后,您使用 head 将行向上找到它所在的行加上额外的 $AFTER 行。然后将其通过管道传输到尾部以获得 $BEFORE + $AFTER + 1 行(即匹配的行加上之前和之后的行数)

    【讨论】:

    • 这是最接近 GNU grep -A -B -C 输出的版本(除了它不输出组分隔符 (--))。
    【解决方案5】:

    当然有(来自 grep 手册页):

       -B NUM, --before-context=NUM
              Print  NUM  lines  of  leading  context  before  matching lines.
              Places  a  line  containing  a  group  separator  (--)   between
              contiguous  groups  of  matches.  With the -o or --only-matching
              option, this has no effect and a warning is given.
    
       -A NUM, --after-context=NUM
              Print NUM  lines  of  trailing  context  after  matching  lines.
              Places   a  line  containing  a  group  separator  (--)  between
              contiguous groups of matches.  With the  -o  or  --only-matching
              option, this has no effect and a warning is given.
    

    如果你想在匹配之前和之后的行数相同,请使用:

       -C NUM, -NUM, --context=NUM
              Print NUM lines of output context.  Places a line  containing  a
              group separator (--) between contiguous groups of matches.  With
              the -o or --only-matching option,  this  has  no  effect  and  a
              warning is given.
    

    【讨论】:

    • 它不适用于 AIX,我很抱歉我没有提到这个问题在 AIX 上。
    • 检查我的其他答案,它应该适用于 AIX,因为 AIX 支持 -n 参数。
    • 我们能否为此提供一些标准或 awk 的组合
    【解决方案6】:

    你可以使用 awk

    awk 'BEGIN{t=4}
    c--&&c>=0
    /pattern/{ c=t; for(i=NR;i<NR+t;i++)print a[i%t] }
    { a[NR%t]=$0}
    ' file
    

    输出

    $ more file
    1
    2
    3
    4
    5
    pattern
    6
    7
    8
    9
    10
    11
    
    $ ./shell.sh
    2
    3
    4
    5
    6
    7
    8
    9
    

    【讨论】:

    • 是的,我试过了,但它不起作用,出现错误 awk: 第 1 行附近的语法错误 awk: 在第 1 行附近退出
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多