假设我有一个文件:

# 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


是否有办法告诉grep只输出与分组中的分组(或特定分组)匹配的项目?正则表达式?

评论

对于不需要grep的用户:perl -lne'如果/ foobar(\ w +)/则打印$ 1'
为什么需要转义括号和+?

表示正则表达式分组并匹配1个或多个字符,而不是搜索实际的字符(,)和+。

#1 楼

GNU grep对于perl样式的正则表达式具有-P选项,而-o选项仅用于打印与模式匹配的内容。可以使用环顾断言(在perlre联机帮助页中的扩展模式下进行描述)将它们组合在一起,以从确定为-o的目的已匹配的内容中删除部分grep模式。 />
\K(?<=pattern)的缩写形式(更有效的形式),您可以在要输出的文本之前将其用作零宽度后向断言。 (?=pattern)可以用作要输出的文本后的零宽度超前断言。

例如,如果要在foobar之间匹配单词,则可以使用:

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


或(对称)

$ grep -oP 'foo \K\w+(?= bar)' test.txt


评论


如果您的正则表达式包含多个分组,您该怎么办? (如标题所示?)

– barracel
13年3月21日在7:52

@barracel:我不相信你可以。 sed时间(1)

– camh
13年3月22日在22:51

@camh我刚刚测试了grep -oP'foobar \ K \ w +'test.txt与OP的test.txt没有任何输出。 grep版本是2.5.1。有什么问题吗? O_O

– SOUser
2014年7月24日14:19在

@XichenLi:我不能说。我刚刚建立了grep v2.5.1(它很老-从2006年开始),它对我有用。

– camh
2014年7月25日上午10:18

似乎-P标志至少在Mac El Capitan上不起作用

– OZZIE
18年1月25日在10:39

#2 楼

    sed -n "s/^.*foobar\s*\(\S*\).*$//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
     substitute everything with the 1st capture group
p      print it


评论


sed示例的+1似乎比grep更好。一个评论,^和$是多余的,因为。*是贪婪的匹配。但是,包括它们可能有助于阐明正则表达式的意图。

–托尼
18年5月30日在21:22

对我来说,开始时以。*为首。否则,它还会捕获foobar之前的内容。

–aerijman
2月19日18:37



由于某种原因,这似乎不适用于macOS sed:echo“ foobar bash 1” | sed -n“ s /^.* foobar \ s * \(\ S * \)。* $ / \ 1 / p”不输出任何内容。

– Frederik
11月27日15:57

#3 楼

标准grep无法做到这一点,但是GNU grep的最新版本可以做到。您可以转向sed,awk或perl。这里有一些示例,您可以根据自己的示例输入进行操作。它们在极端情况下的行为略有不同。如果是foobar word other stuff,请打印第二个单词。

sed -n -e 's/^foobar \([[:alnum:]]\+\).*//p'


如果是第一个单词,请粘贴word,否则跳过该行;然后在第一个空格之后剥离所有内容并打印。

awk ' == "foobar" {print }'


评论


太棒了!我以为我可以使用sed来做到这一点,但是我以前从未使用过它,而是希望可以使用熟悉的grep。但是,由于我熟悉vim样式的搜索和替换+正则表达式,因此这些命令的语法实际上看起来非常熟悉。万分感谢。

– Cory Klein
2011年5月19日23:51

不对,吉尔斯。请参阅我的答案以获取GNU grep解决方案。

– camh
2011年5月20日下午1:33

@camh:啊,我不知道GNU grep现在有完整的PCRE支持。我已经纠正了我的回答,谢谢。

–吉尔斯'所以-不再是邪恶的'
2011年5月20日7:14



由于Busybox grep不支持PCRE,因此该答案对于嵌入式Linux特别有用。

–克雷格·麦昆(Craig McQueen)
16 Mar 17 '16 at 0:12

显然,有多种方法可以完成所介绍的同一任务,但是,如果OP要求使用grep,为什么还要回答其他问题呢?另外,您的第一段是不正确的:是的,grep可以做到。

–fcm
19年3月11日在13:31

#4 楼

好吧,如果您知道foobar始终是第一个单词或行,那么可以使用cut。像这样:

grep "foobar" test.file | cut -d" " -f2


评论


grep上的-o开关得到了广泛的实现(比Gnu grep扩展还要多),因此使用grep -o“ foobar” test.file | cut -d“” -f2将提高此解决方案的有效性,比使用后向断言更可移植。

– dubiousjim
2012年4月19日在21:04



我相信您将需要grep -o“ foobar。*”或grep -o“ foobar \ w +”。

– G-Man说“恢复莫妮卡”
18年4月14日在7:20

如果值中还有另一个空格则中断

–mvmn
19/12/27在15:17

#5 楼

pcregrep具有更智能的-o选项
,使您可以选择要输出的捕获组。
因此,使用您的示例文件,

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


评论


哇,这对我来说很神奇,非常感谢。我在MacOS上,并尝试以某种方式使用匹配组。我一直尝试zegrep的原因是因为我压缩了一个大的zip文件,但还发现pcregrep将(从pcregrep --help页面):使用zlib读取名称以.gz结尾的文件。因此,我可以立即在zip文件中使用它。再次感谢!

– Samjewell
4月6日15:11



#6 楼

如果不支持PCRE,则可以通过两次调用grep获得相同的结果。例如,要在foobar之后抓单词,请执行以下操作: >
<test.txt grep -o 'foobar  *[^ ]*' | grep -o '[^ ]*$'


输出:

i=1
<test.txt egrep -o 'foobar +([^ ]+ +){'$i'}[^ ]+' | grep -o '[^ ]*$'


请注意,索引i是从零开始的。

#7 楼

使用grep不跨平台兼容,因为-P / --perl-regexp仅在GNU grep上可用,而不在BSD grep上可用。
这里是使用ripgrep的解决方案:
$ rg -o "foobar (\w+)" -r '' <test.txt
bash
happy


man rg

-r / --replace REPLACEMENT_TEXT用给定的文本替换每个匹配项。
替换字符串支持捕获组索引(例如)和名称(例如$foo)。 >
相关:GH-462。

评论


但是可以在BSD发行版上安装gnugrep。

–bparker
5月13日20:50

#8 楼

我发现@jgshawkey的答案非常有帮助。 grep并不是一个很好的工具,但sed是,尽管这里有一个使用grep抓取相关行的示例。

如果您不习惯sed的正则表达式语法,则它是特殊的。

这是另一个示例:该示例解析xinput的输出以获得ID整数

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


我想要19

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


请注意类语法:

[[:digit:]]


并需要转义以下+

我假设只有一行匹配。

评论


这正是我试图做的。谢谢!

–詹姆斯
19年5月12日在0:07

| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | sed -nE“ s /.* TouchPad。+ id =([0-9] +)。* / \ 1 / p”

–阿米特·奈杜(Amit Naidu)
19年5月19日在5:10