提问人:merlin2011 提问时间:11/3/2023 最后编辑:Ed Mortonmerlin2011 更新时间:11/8/2023 访问量:59
是否可以从 *每个* grep 匹配中获取最后 N 行上下文?
Is it possible to grab the last N lines of context from *each* grep match?
问:
请考虑以下输入文件:
FixedHeader
Body1
Body2
BodyX
BodyY
BodyZ
Unrelated text111
Unrelated text551
Unrelated text111
Unrelated text551
FixedHeader
Body3
Body4
BodyX
BodyY
BodyZ
Unrelated text111
Unrelated text551
FixedHeader
Body5
Body6
BodyA
BodyB
BodyZC
我可以使用以下命令 grep 获取并拉动它后面的五行:FixedHeader
egrep -A5 "FixedHeader"
但是,我想做的是识别并始终抓住它后面的第 5 行,但不输出上下文的其余任何部分。预期输出:FixedHeader
BodyZ
BodyZ
BodyZC
有没有办法在 grep 匹配的上下文中向下输出 N 行?
我并不特别喜欢 grep,尽管如果存在单行代码,则更可取。
答:
3赞
merlin2011
11/3/2023
#1
我想出了如何做到这一点:awk
awk '/FixedHeader/ {target_line=NR + 5} NR==target_line' input.log
0赞
Timur Shtatland
11/3/2023
#2
使用这个 Perl 单行代码:
perl -ne '$i = $. + 5 if /FixedHeader/; print if $. == $i;' in_file
或者,如果模式间隔的频率高于每 5 行,请使用此解决方案(内存效率较低,因为它将整个文件加载到内存中):grep
perl -ne 'push @s, $_; push @i, ( $. - 1 ) if /FixedHeader/; END { @i = map { $i = $_ + 5; $i; } @i; print for @s[@i]; }' in_file
指纹:
BodyZ
BodyZ
BodyZC
Perl 单行代码使用以下命令行标志: :
告诉 Perl 以内联方式查找代码,而不是在文件中查找代码。
:一次循环一行输入,默认分配给输入。-e
-n
$_
$.
:当前输入行号。
另请参阅:
perldoc perlrun
: 如何执行 Perl 解释器: 命令行开关perldoc perlre
: Perl 正则表达式(正则表达式)perldoc perlrequick
: Perl 正则表达式快速入门
1赞
Ed Morton
11/8/2023
#3
在 printing-with-sed-or-awk-a-line-following-a-matching-pattern 上发布的成语样式中,您可以这样做:
$ awk 'c&&!--c; /FixedHeader/{c=5}' file
BodyZ
BodyZ
BodyZC
OP 在他们的答案中的内容对于这个特定问题很好,但上述内容除了更容易适应不同的要求之外并没有更好,但它的工作原理也不是很明显。
但是,或者,由于您的输入中有空行分隔的段落,因此您可以在段落模式下使用 awk,字段由空格分隔,而不是任何空格:\n
$ awk -v RS= -F'\n' '/^FixedHeader/{print $6}' file
BodyZ
BodyZ
BodyZC
与上一个的区别在于,如果打印空行后少于 5 行,而已经讨论过的 2 个解决方案可以从下一段打印出一行,例如:FixedHeader
$ cat file
FixedHeader
Body1
Body2
Unrelated text111
Unrelated text551
Unrelated text111
Unrelated text551
$ awk '/FixedHeader/ {target_line=NR + 5} NR==target_line' file
Unrelated text551
$
$ awk 'c&&!--c; /FixedHeader/{c=5}' file
Unrelated text551
$
$ awk -v RS= -F'\n' '/^FixedHeader/{print $6}' file
$
0赞
Paul Hodges
11/8/2023
#4
嵌套范围也可以解决很多这样的问题。sed
$: sed -n '/^FixedHeader/,+5{ # on a header and the next five lines
/^FixedHeader/,+4d # ignore the header and the next FOUR lines
p # print the desired line per header
}' infile
BodyZ
BodyZ
BodyZC
...但是 Ed 的段落模式解决方案是你更好的选择,因为他给出了原因。awk
评论