高级 grep Unix

发布于 2024-08-10 10:22:10 字数 78 浏览 10 评论 0原文

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

这可以使用 awk 来实现吗?

Usually grep command is used to display the line contaning the specified pattern. Is there any way to display n lines before and after the line which contains the specified pattern?

Can this will be achieved using awk?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(6

五里雾 2024-08-17 10:22:10

是的,用于

grep -B num1 -A num2 

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

编辑:

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

此链接 描述了 AIX 4.3 上的 grep(它看起来不太有希望

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

Yes, use

grep -B num1 -A num2 

to include num1 lines of context before the match, and num2 lines of context after the match.

EDIT:

Seems the OP is using AIX. This has a different set of options which doesn't include -B and -A

this link describes grep on AIX 4.3 (it doesn't look promising)

Matt's perl script might be a better solution.

蓝戈者 2024-08-17 10:22:10

这是我在 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>

假设我有一个模式“stack”,文件名是 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。从上面的模式“stack”来看,文件名为 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.*

Here is what I usually do on 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>

If you do not want the extra 2 varialbles you can always use it an a one line:

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

Suppose I have a pattern 'stack' and the filename is flow.txt
I want 2 lines before and 3 lines after. The the command will be like:

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

I want 2 lines before and only - the the command will be like:

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

I want 3 lines after and only - the the command will be like:

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

Multiple Files - change it for Awk & grep. From above for the pattern 'stack' with the filename is flow.* - 2 lines before and 3 lines after. The the command will be like:

    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.*
垂暮老矣 2024-08-17 10:22:10

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

From the tags, it's likely that the system has a grep that may not support providing context (Solaris is one system that doesn't and I can't remember about AIX). If that is the case, there's a perl script that may help at http://www.sun.com/bigadmin/jsp/descFile.jsp?url=descAll/cgrep__context_grep.

丶情人眼里出诗心の 2024-08-17 10:22:10

如果你有 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 行。然后通过管道传输到 tail 以获取 $BEFORE + $AFTER + 1 行(即,您的匹配行加上之前和之后的行数)

If you have sed you could use this shell script

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

What it does is, grep -n prefixes each match with the line it was found at, the sed strips all but the line it was found at. Then you use head to get the lines up to the line it was found on plus an additional $AFTER lines. That's then piped to tail to just get $BEFORE + $AFTER + 1 lines (that is, your matching line plus the number of lines before and after)

心的位置 2024-08-17 10:22:10

当然有(来自 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.

Sure there is (from the grep man page):

   -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.

and if you want the same amount of lines before AND after the match, use:

   -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.
〃安静 2024-08-17 10:22:10

你可以使用 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

you can use 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

output

$ more file
1
2
3
4
5
pattern
6
7
8
9
10
11

$ ./shell.sh
2
3
4
5
6
7
8
9
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文