我的目标是提取包含特定关键字的文本段落。不仅仅是包含关键字的行,而是整个段落。我的文本文件的规则是每个段落都以某种模式开头(例如 Pa0),该模式仅在段落开头在整个文本中使用。每个段落都以换行符结尾。
例如,假设我有以下文本:
Pa0
This is the first paragraph bla bla bla
This is another line in the same paragraph bla bla
This is a third line bla bla
Pa0
This is the second paragraph bla bla bla
Second line bla bla My keyword is here!
bla bla bla
bla
Pa0
Hey, third paragraph bla bla bla!
bla bla
Pa0
keyword keyword
keyword
Another line! bla
我的目标是提取这些包含“关键字”一词的段落。例如:
Pa0
This is the second paragraph bla bla bla
Second line bla bla My keyword is here!
bla bla bla
bla
Pa0
keyword keyword
keyword
Another line! bla
我可以使用例如grep 关键字和 -A、-B 或 -C 选项可获取关键字所在行之前和/或之后的恒定行数,但这似乎还不够,因为文本块的开头和结尾取决于分隔符“Pa0”和“ ”.
任何有关
grep
或其他工具(例如 awk、sed、perl)的建议都会有所帮助。
很简单
awk
:
awk '/keyword/' RS="\n\n" ORS="\n\n" input.txt
说明:
通常 awk 以每行为基础进行操作,因为记录分隔符
RS
的默认值是 \n
(单个新行)。通过将 RS
依次更改为两行(空行),我们可以轻松地在段落基础上进行操作。
/keyword/
是一个条件,一个正则表达式。由于条件 awk
之后没有任何操作,如果它包含 keyword
,将简单地打印未更改的记录(段落)。
将输出记录分隔符
ORS
设置为 \n\n
将会用空行分隔输出的段落,就像在输入中一样。
如果text.txt包含您想要的文本,则:
$ sed -e '/./{H;$!d;}' -e 'x;/keyword/!d;' text.txt
Pa0
This is the second paragraph bla bla bla
Second line bla bla My keyword is here!
bla bla bla
bla
Pa0
keyword keyword
keyword
Another line! bla
希望这会有所帮助
sed -n '/Pa0/,/^$/p' 文件名
cat 文件名 | sed -n '/Pa0/,/^$/p'
-n,抑制图案空间的自动打印
-p,打印当前图案空间
/Pa0/,以 Pa0 模式开始的段落
/^$/,以空行结尾的段落
^,行首
$,行尾
只要使用正确的命令行开关,使用 Perl 就可以轻松做到这一点:
perl -wn00e "print if /keyword/" input.txt
开关
-w00ne
可能看起来令人难以承受,所以让我们将其分解并一次检查一个开关。如果这对您来说更容易,可以将上面的命令重新编写,并将开关拆分为:
perl -w -n -00 -e "print if /keyword/" input.txt
这是四个开关:
perldoc perlrun
并搜索 -n
开关来了解更多信息。每一段执行的程序是:
print if /keyword/
这是一个非常短的程序,仅使用正则表达式来检查
keyword
是否包含在行/段落/记录中,如果找到,则打印该记录。
请注意,您可以在
i
的末尾添加 /keyword/
,使其成为不区分大小写的匹配,如下所示:
print if /keyword/i
事实上,您可以在 Perl 允许的常规
/keyword/
匹配之后放置任何修饰符。
还有一件事:如果你真的不喜欢把
m/.../
放在
/keyword/
之后(有些人出于某种原因这样做),你可以将程序重写为:print
但在我看来,
/keyword/ and print
读起来很愉快,因为短语“如果匹配则打印”遵循自然的英语语法。