grep 可以只输出匹配的指定分组吗?

grep 可以只输出匹配的指定分组吗?

假设我有一个文件:

# 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 具有-Pperl 风格的正则表达式选项,以及-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 stuffword,仅在替换完成后才打印。

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

相关内容