如何grep文件中的文本并显示包含文本的段落?


24

以下是文件中的文本:

Pseudo name=Apple
Code=42B
state=fault

Pseudo name=Prance
Code=43B
state=good

我需要grep为“ 42B”,并从上面的文本中获取输出,例如:

Pseudo name=Apple
Code=42B
state=fault

有谁知道如何使用grep/ awk/ 实现这一点sed


您仅用“ grep”标记了这个问题。那么,您是否仅在寻找“ grep”解决方案?在问题中,您还要指定awk和sed。我们可以添加这些标签吗?昨晚编辑问题时,我不确定您的意图。
slm

Answers:


38

awk

awk -v RS='' '/42B/' file

RS=将输入记录分隔符从换行更改为空行。如果记录中的任何字段包含/42B/打印记录。

''(空字符串)是一个神奇的值,用于根据POSIX表示空白行:

如果RS为空,则记录由由一个<newline>加一个或多个空行组成的序列分隔,前导或尾随空行在输入的开头或结尾不应导致空记录,并且a <newline>始终是字段分隔符,无论FS的价值是多少。

由于输出分隔符仍为单个换行符,因此不会分隔输出段落。为确保输出段落之间有空白行,请将输出记录分隔符设置为两个换行符:

awk -v RS='' -v ORS='\n\n' '/42B/' file

1
+1是一个优雅的解决方案。不过,您不需要重定向文件...
jasonwryan

手指在自动驾驶仪上。
llua 2013年

2
@jasonwryan,除非您需要访问awk(FILENAME)中的文件名,否则使用重定向不是一个坏主意,因为这样可以避免文件名包含=或以-(或为-)开头的问题,避免出现一致的错误消息,并避免运行awk或执行其他重定向(如果无法打开输入文件)。
斯特凡Chazelas

14

假设数据是结构化的,因此它始终是您想要的前后行,则可以使用grep的-A(之后)和-B(之前)开关来告诉它在比赛之前包含1行,在比赛之后包含1行:

$ grep -A 1 -B 1 "42B" sample.txt
Pseudo name=Apple
Code=42B
state=fault

如果要在搜索词前后添加相同的数字行,可以使用-C(上下文)开关:

$ grep -C 1 "42B" sample.txt
Pseudo name=Apple
Code=42B
state=fault

如果您希望在匹配多行时更加严格,可以使用工具pcregrep,在多行上匹配模式:

$ pcregrep -M 'Pseudo.*\n.*42B.*\nstate.*' sample.txt
Pseudo name=Apple
Code=42B
state=fault

上面的模式匹配如下:

  • -M -多行
  • 'Pseudo.*\n.*42B.*\nstate.*'-匹配一组字符串,其中第一个字符串以单词开头,"Pseudo"然后是直到行尾的\n所有字符,然后是直到字符串"42B"的任何字符,然后是直到行(\n)的另一端的所有字符,然后是字符串"state"其次是任何字符。

5
-C如果-A-B相同,则(上下文)可以用作快捷方式。
David Baggerman

@DavidBaggerman-谢谢。将其添加到答案。
slm

为什么要一票否决?这回答了问题。
slm

4

使用awk可能有类似的简单方法,但是在perl中:

cat file | perl -ne 'BEGIN { $/="\n\n" }; print if $_ =~ /42B/;'

基本上就是说,将文件拆分为用空白行分隔的块,然后仅打印与您的正则表达式匹配的那些块。


10
可以通过使用选项和速记来简化此操作,而不必浪费时间使用cat ;。perl -00 -ne 'print if /42B/' file
Tripleee

4

grepUnix的一些口味有-p对“段落”标志。我知道AIX可以

grep -p 42B <myfile>

完全可以满足您的要求。YMMV和GNU grep没有此标志。


拥有-p标志会很棒。特别是与-v一起使用时,可以从输出中排除整个段落。
IllvilJa

2

另一种perl解决方案,没有尾随空行:

perl -00ne 'if ($_ =~ /42B/) {chomp($_); printf "%s\n",$_}' foo

% perl -00ne 'if ($_ =~ /42B/) {chomp($_); printf "%s\n",$_}' foo
Pseudo name=Apple
Code=42B
state=fault

% cat foo
Pseudo name=Apple
Code=42B
state=fault

Pseudo name=Prance
Code=43B
state=good

1
或更短(因此更具可读性),如三元组在评论中写道: perl -00 -ne 'print if /42B/' file
mivk
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.