Cor*_*ein 442 grep text-processing regular-expression
说我有一个文件:
# file: 'test.txt'
foobar bash 1
bash
foobar happy
foobar
Run Code Online (Sandbox Code Playgroud)
我只想知道“foobar”后面出现什么词,所以我可以使用这个正则表达式:
"foobar \(\w\+\)"
Run Code Online (Sandbox Code Playgroud)
括号表示我对 foobar 后面的单词特别感兴趣。但是当我执行 a 时grep "foobar \(\w\+\)" test.txt,我得到了与整个正则表达式匹配的整行,而不仅仅是“foobar 之后的单词”:
foobar bash 1
foobar happy
Run Code Online (Sandbox Code Playgroud)
我更希望该命令的输出如下所示:
bash
happy
Run Code Online (Sandbox Code Playgroud)
有没有办法告诉 grep 只输出与正则表达式中的分组(或特定分组)匹配的项目?
cam*_*amh 491
GNU grep 可以-P选择 perl 样式的正则表达式,并且-o可以选择只打印与模式匹配的内容。可以使用环视断言(在 perlre 联机帮助页中的扩展模式下描述)组合这些断言,以从确定为 的目的匹配的内容中删除部分 grep 模式-o。
$ grep -oP 'foobar \K\w+' test.txt
bash
happy
$
Run Code Online (Sandbox Code Playgroud)
这\K是(?<=pattern)您在要输出的文本之前用作零宽度后视断言的简短形式(和更有效的形式)。(?=pattern)可以在要输出的文本之后用作零宽度前瞻断言。
举例来说,如果你想要的字匹配foo和bar,你可以使用:
$ grep -oP 'foo \K\w+(?= bar)' test.txt
Run Code Online (Sandbox Code Playgroud)
或(为了对称)
$ grep -oP '(?<=foo )\w+(?= bar)' test.txt
Run Code Online (Sandbox Code Playgroud)
小智 89
sed -n "s/^.*foobar\s*\(\S*\).*$/\1/p"
-n suppress printing
s substitute
^.* anything before foobar
foobar initial search match
\s* any white space character (space)
\( start capture group
\S* capture any non-white space character (word)
\) end capture group
.*$ anything after the capture group
\1 substitute everything with the 1st capture group
p print it
Run Code Online (Sandbox Code Playgroud)
Gil*_*il' 62
标准 grep 不能这样做,但最新版本的 GNU grep 可以。您可以使用 sed、awk 或 perl。以下是一些示例,它们可以对示例输入执行您想要的操作;它们在极端情况下的行为略有不同。
替换foobar word other stuff为word,仅在替换完成时打印。
sed -n -e 's/^foobar \([[:alnum:]]\+\).*/\1/p'
Run Code Online (Sandbox Code Playgroud)
如果第一个单词是foobar,则打印第二个单词。
awk '$1 == "foobar" {print $2}'
Run Code Online (Sandbox Code Playgroud)
剥去foobar如果它是第一个字,并跳过线除外; 然后在第一个空格之后去除所有内容并打印。
perl -lne 's/^foobar\s+// or next; s/\s.*//; print'
Run Code Online (Sandbox Code Playgroud)
小智 26
好吧,如果您知道 foobar 始终是第一个单词或行,那么您可以使用 cut。像这样:
grep "foobar" test.file | cut -d" " -f2
Run Code Online (Sandbox Code Playgroud)
G-M*_*ca' 23
pcregrep有一个更智能的-o选项,可让您选择要输出的捕获组。因此,使用您的示例文件,
$ pcregrep -o1 "foobar (\w+)" test.txt
bash
happy
Run Code Online (Sandbox Code Playgroud)
Tho*_*hor 10
如果不支持 PCRE,您可以通过两次调用 grep 获得相同的结果。例如要在foobar之后抓取单词,请执行以下操作:
<test.txt grep -o 'foobar *[^ ]*' | grep -o '[^ ]*$'
Run Code Online (Sandbox Code Playgroud)
这可以像这样在foobar之后扩展为任意单词(使用 ERE 以提高可读性):
i=1
<test.txt egrep -o 'foobar +([^ ]+ +){'$i'}[^ ]+' | grep -o '[^ ]*$'
Run Code Online (Sandbox Code Playgroud)
输出:
1
Run Code Online (Sandbox Code Playgroud)
请注意,该索引i是从零开始的。