grep能否只输出指定的匹配分组?

说我有一个文件。

# file: 'test.txt'
foobar bash 1
bash
foobar happy
foobar

我只想知道在"foobar"之后出现了哪些词,所以我可以使用这个重合词。

"foobar \(\w\+\)"

括号表示我对紧跟在foobar之后的词有特殊兴趣。 但是当我做 "grep "foobar /(\w+)"test.txt "时,我得到的是与整个重码匹配的整行,而不仅仅是"foobar"后的单词。

foobar bash 1
foobar happy

我更希望该命令的输出是这样的。

bash
happy

有没有办法告诉grep只输出符合正则表达式中的分组(或特定分组)的项目?

对该问题的评论 (1)
解决办法

GNU grep有-P选项用于perl-style regexes,还有-o选项用于只打印符合模式的内容。这两个选项可以通过查找断言(在perlre manpage的[Extended Patterns][1]中描述)结合起来,将grep模式中的部分内容从-o的目的中确定为匹配的内容。

$ grep -oP 'foobar \K\w+' test.txt
bash
happy
$

K是`(?

评论(8)

标准grep不能这样做,但GNU grep的最新版本可以。你可以求助于sed、awk或perl。这里有几个例子,在你的输入样本上做你想做的事;它们在角落里的表现略有不同。

word替换foobar word other stuff,只在替换完成后打印。

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'
评论(5)
    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
评论(1)

好吧,如果你知道foobar总是第一个词或第一行,那么你可以使用cut。 像这样。

grep "foobar" test.file | cut -d" " -f2
评论(2)

如果不支持PCRE,你可以通过两次调用grep得到同样的结果。 例如,要抓取 foobar 后面的单词,可以这样做。

评论(0)

pcregrep有一个更聪明的-o选项。 让您选择您想要输出的捕获组。 所以,使用你的例子文件,

$ pcregrep -o1 "foobar (\w+)" test.txt
bash
happy
评论(0)

使用grep是不跨平台的,因为-P/--perl-regexp只能在[GNU grep][1]上使用,而不是[BSD grep][2]。

下面是使用 [ripgrep][3] 的解决方案。


$ rg -o "foobar (\w+)" -r '$1' 
评论(0)

我发现@jgshawkey的回答非常有用。 grep不是一个很好的工具,但是sed是,虽然这里我们有一个使用grep来抓取相关行的例子。

sed的Regex语法是特异性的,如果你不习惯它。

这里还有一个例子。 这个例子是解析xinput的输出,得到一个ID整数

⎜   ↳ SynPS/2 Synaptics TouchPad                id=19   [slave  pointer  (2)]

而我要19

export TouchPadID=$(xinput | grep 'TouchPad' | sed  -n "s/^.*id=\([[:digit:]]\+\).*$/\1/p")

注意类的语法。

[[:digit:]]

以及需要避开以下+的内容。

我假设只有一条线匹配。

评论(2)