假设我有一个文件:
# file: 'test.txt'
foobar bash 1
bash
foobar happy
foobar
我只想知道“foobar”后面出现什么单词,所以我可以使用这个正则表达式:
"foobar \(\w\+\)"
括号表明我对 foobar 之后的单词特别感兴趣。但是当我执行 a 时grep "foobar \(\w\+\)" test.txt
,我得到与整个正则表达式匹配的整行,而不仅仅是“foobar 之后的单词”:
foobar bash 1
foobar happy
我更希望该命令的输出如下所示:
bash
happy
有没有办法告诉 grep 仅输出与正则表达式中的分组(或特定分组)匹配的项目?
答案1
GNU grep 具有-P
perl 风格的正则表达式选项,以及-o
仅打印与模式匹配的选项。这些可以使用环视断言进行组合(如下所述perlre 联机帮助页中的扩展模式) 从确定为 目的匹配的内容中删除部分 grep 模式-o
。
$ grep -oP 'foobar \K\w+' test.txt
bash
happy
$
这\K
是一种简短形式(也是更有效的形式),(?<=pattern)
您可以将其用作要输出的文本之前的零宽度后向断言。(?=pattern)
可以用作要输出的文本之后的零宽度先行断言。
例如,如果您想匹配foo
和之间的单词bar
,您可以使用:
$ grep -oP 'foo \K\w+(?= bar)' test.txt
或(为了对称)
$ grep -oP '(?<=foo )\w+(?= bar)' test.txt
答案2
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
答案3
标准 grep 无法做到这一点,但是最新版本的 GNU grep 可以。您可以转向 sed、awk 或 perl。以下是一些示例,可以对示例输入执行您想要的操作;它们在极端情况下的行为略有不同。
替换foobar word other stuff
为word
,仅在替换完成后才打印。
sed -n -e 's/^foobar \([[:alnum:]]\+\).*/\1/p'
如果第一个单词是foobar
,则打印第二个单词。
awk '$1 == "foobar" {print $2}'
foobar
如果它是第一个单词,则将其删除,否则跳过该行;然后删除第一个空格后的所有内容并打印。
perl -lne 's/^foobar\s+// or next; s/\s.*//; print'
答案4
好吧,如果您知道 foobar 始终是第一个单词或第一个行,那么您可以使用 cut。就像这样:
grep "foobar" test.file | cut -d" " -f2