每个grep结果后如何显示2-4行?


39

我正在解析一个邮箱文件,该邮箱文件存储了未成功发送的电子邮件的电子邮件服务器报告。我希望提取错误的电子邮件地址,以便将其从系统中删除。日志文件如下所示:

...some content...
                   The mail system

<slavicatomic118@hotmail.com>: host mx1.hotmail.com[65.54.188.94] said: 550
    Requested action not taken: mailbox unavailable (in reply to RCPT TO
    command)

...some content...
                   The mail system

<oki88@optimumpro.net>: host viking.optimumpro.net[79.101.51.82] said: 550
    Unknown user (in reply to RCPT TO command)

...some content...
                   The mail system

<sigirna_luka@yahoo.com>: host mta5.am0.yahoodns.net[74.6.140.64] said: 554
    delivery error: dd This user doesn't have a yahoo.com account
    (sigirna_luka@yahoo.com) [0] - mta1172.mail.sk1.yahoo.com (in reply to end
    of DATA command)

...etc.

电子邮件地址在“邮件系统”行的后面两行。像这样使用grep可以给我“邮件系统”行和接下来的两行:

grep -A 2 "The mail system" mbox_file

但是,我不知道如何从此输出中删除“邮件系统”行和第二个空行。我想我可以编写PHP / Perl / Python脚本来做到这一点,但是我不知道grep或其他一些标准工具是否可以做到这一点。我试图给负负偏移量-B参数:

grep -A 2 -B -2 "The mail system" mbox_file

但是grep抱怨:

grep: -2: invalid context length argument

有没有办法用grep做到这一点?


3
-B像-A一样接受数字,并且它将显示比赛之前的前几行。
Nikhil Mulley

3
是的,的确如此,但米兰对比赛开始前的情况不感兴趣...他遇到的问题是-A和-B仅接受正值...而且无论如何,-A和-B可以就像他试图做的那样,不能彼此相对使用。
Peter.O 2012年

1
哼,只是为了确保:这些是您没有(直接)从获得的文件中提取出来的伪地址,对吗?
Matthieu M. 2012年

1
@Matthieu M.不,它们来自真实的日志文件。我发现由于它们仍然是无效地址,因此发明可能有效的虚拟地址有什么意义?
米兰Babuškov2012年

Answers:


29

解决这个问题的最简单方法grepgrep在末端再倒置一个管道。例如:

grep -A 4 "The mail system" temp.txt | grep -v "The mail system" | grep -v '^\d*$'

28

如果您不习惯使用grep,请尝试sed...

sed -n '/The mail system/{n;n;p}' 

当找到包含“邮件系统”的行时,它会通过读取下一行两次,从而n;n;丢弃前一行。
这样会将组的第三行留在图案空间中,然后通过sed的p命令进行-n打印。前导选项可防止所有其他打印。

要同时打印下两行,只不过是next 的情况,再打印n;p两次。

sed -n '/The mail system/{n; n;p; n;p; n;p}'   

可以累积下一行所需要的行的读取内容,并将其打印在一个只有一个的块中p…… N读取下一行并将其追加到模式空间中,

这是最终的精简版...

sed -n '/The mail system/{n;n;N;N;p}'   

如果您想要一个组分隔符(类似于grep会输出的内容),则可以使用sed的insert命令i(该命令必须是一行中的最后一个命令)...

这是包含组分隔符的语法

sed -n '/The mail system/{n;n;N;N;p;i--
       }' > output-file  # or | ...

这是第一个匹配项的输出:

<slavicatomic118@hotmail.com>: host mx1.hotmail.com[65.54.188.94] said: 550
    Requested action not taken: mailbox unavailable (in reply to RCPT TO
    command)                                                                    
--

+1。谢谢。在这种情况下,我不需要它,但是如果我要处理更复杂的内容,则将其保留为书签。
米兰Babuškov2012年

这是一个很好的答案!
dotancohen

9
grep -A 2 -B -2 "The mail system" mbox_file

-B 是用于前几行的,因此无需给出负值。

grep -A 2 -B 2 "The mail system" mbox_file   # This will work please check

这不能回答问题。-A 2 -B 2从上下文前两行打印到上下文后两行。问题是从上下文后的2行打印到上下文后的4行。
daniel.neumann

1

我认为仅使用grep没有任何意义,除非这是一个严格的约束。一次调用grep无法完成此操作。

grep -A 2 "The mail system" mbox_file | tail -n +3
  • grep:找到该行并在其后输出2行,
  • 尾巴:剪掉前两行(即从第三行开始)。

2
这仅在只有一条匹配行的情况下才有效,这可能不是问题要问的内容。
2012年

问题没什么要问的,但在我现在的情况下可以帮助我:-)。
daniel.neumann

1
@ daniel.neumann我知道,但是我正好在你的鞋子里,还以为别人的Google-fu也将在这里领导。
TWiStErRob

0

这将使用Perl在regexp匹配之后打印下1行

perl -ne 'print if( (/The mail system/ && ($end=1))..!$end-- )' 
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.