grep可以仅显示与搜索模式匹配的单词吗?


684

有没有办法使grep输出与搜索表达式匹配的文件中的“单词”?

如果我想在许多文件中找到“ th”的所有实例,则可以执行以下操作:

grep "th" *

但是输出将是这样的(我大胆);

一些文本文件:猫坐在垫子  
一些-其他文本文件:敏捷的棕色狐狸  
另一个文本文件:我希望彻底解释它 

使用相同的搜索,我希望它输出的是:

the
the
the
this
thoroughly

使用grep可以吗?还是使用其他工具组合?


2
丹·米德伍德(Dan Midwood)的解决方案运行完美,值得赞扬。
hakish

有没有一种方法可以打印那些匹配的单词而无需更改行。而是匹配的字符串应保留在同一行?
语言学家

Answers:


951

试试grep -o

grep -oh "\w*th\w*" *

编辑:从菲尔的评论匹配

文档

-h, --no-filename
    Suppress the prefixing of file names on output. This is the default
    when there is only  one  file  (or only standard input) to search.
-o, --only-matching
    Print  only  the matched (non-empty) parts of a matching line,
    with each such part on a separate output line.

9
@ user181548,grep -o选项仅适用于GNU grep。因此,如果您不使用GNU grep,则它可能对您不起作用。
ksinkar 2014年

5
@ABB这取决于您是否要显示匹配文件的名称。我不确定在什么条件下它会显示什么,但不会显示,但是我确实知道,当我在多个目录中使用grep时,它确实显示了所有匹配文件的完整文件路径,而使用-h时,它只会显示匹配的单词,没有任何有关文件的说明。因此,为了匹配原始问题,我认为在某些情况下是必要的。
LokMac '17

1
我需要解释什么"\w*th\w*" *意思,所以我认为应该发表。\w是[_ [:alnum:]],因此它基本上匹配任何包含'th'的“单词”(因为\w不包含空格)。引用部分后面的*是该文件的全局名称(即,匹配该目录中的所有文件)
jeremysprofile

1
\w通常不便于携带grep -E; 为了获得适当的可移植性,请改用POSIX字符类名称[[:alnum:]](或者[_[:alnum:]]如果您也确实需要下划线;或者尝试grep -P在平台上使用下划线)。
Tripleee '18

@ABB鉴于OP显示的所需输出,-h我完全有必要说..?
El Ronnoco

80

交叉分发安全答案(包括Windows minGW?)

grep -h "[[:alpha:]]*th[[:alpha:]]*" 'filename' | tr ' ' '\n' | grep -h "[[:alpha:]]*th[[:alpha:]]*"

如果您使用的旧版grep(例如2.4.2)不包含-o选项。使用上面的。否则,使用下面更简单的维护版本。

Linux交叉分发安全答案

grep -oh "[[:alpha:]]*th[[:alpha:]]*" 'filename'

要汇总-oh输出正则表达式匹配到文件内容(而不是文件名)的方法,就像您希望正则表达式在vim / etc中工作一样...然后您要搜索的单词或正则表达式取决于您!只要您继续使用POSIX而不是perl语法(请参阅下文)

grep手册中的更多内容

-o      Print each match, but only the match, not the entire line.
-h      Never print filename headers (i.e. filenames) with output lines.
-w      The expression is searched for as a word (as if surrounded by
         `[[:<:]]' and `[[:>:]]';

原始答案不适用于所有人的原因

\w平台的用法因平台的“ perl”扩展语法而异。因此,仅限用于POSIX字符类的grep安装使用[[:alpha:]],而不使用其perl等效项\w有关更多信息,请参见Wikipedia页面。

最终,无论grep的平台(是原始版本)如何,上述POSIX答案都将更加可靠

对于不带-o选项的grep支持,第一个grep输出相关行,tr将空格拆分为新行,最后的grep过滤器仅针对各个行。

(PS:我知道到目前为止,大多数平台都已经为\ w ....进行了修补,但是总是有些滞后)

感谢@AdamRosenfield答案中的“ -o”解决方法


1
-o仅在GNU grep中工作(如ksinkar在对已接受答案的评论中提到的)怎么办?
Brilliand

@Brilliand hmm,我在查找不支持“ -o”的linux实现时遇到了麻烦,如果我知道要检查哪个平台,我可以寻找解决方法。
PicoCreator 2015年

@pico该-o选项在git软件包(minGW?)安装的Windows grep中不存在: "c:\Program Files (x86)\Git\bin\grep" --version grep (GNU grep) 2.4.2
Bruce Peterson

@BrucePeterson我在-Ro的AdamRosenfield解决方法中添加了答案:帮助我检查Windows git是否包含tr / sed及其版本。因此,我可以检查此替代方法是否有效
PicoCreator 2015年

@pico:适用于GIT:GNU sed版本4.2.1,tr(GNU textutils)2.0
Bruce Peterson

45

这比您想像的要简单。尝试这个:

egrep -wo 'th.[a-z]*' filename.txt #### (Case Sensitive)

egrep -iwo 'th.[a-z]*' filename.txt  ### (Case Insensitive)

哪里,

 egrep: Grep will work with extended regular expression.
 w    : Matches only word/words instead of substring.
 o    : Display only matched pattern instead of whole line.
 i    : If u want to ignore case sensitivity.

2
这似乎并没有为4年前的现有答案添加任何内容。
三人房

3
@tripleee我发现我的方法更好,更简单,所以我发布了这个。
Abhinandan prasad

42

您可以将空格转换为换行符,然后进行grep转换,例如:

cat * | tr ' ' '\n' | grep th

18
不用猫 tr'''\ n'<文件| grep th。大文件速度慢。
ghostdog74

这没用。输出仍然包含文件名和包含匹配项的文件的整行。无论如何,提供的其他解决方案之一是可行的。感谢您的输入。
尼尔·鲍德温

@ ghostdog74:很好,尽管如果文件多,则需要使用cat。@Neil Baldwin:您确定输入正确吗?当只有一个输入文件(在这种情况下为stdin)时,grep不会打印文件名。
亚当·罗森菲尔德2009年

@Adam-是的,对不起,亚当,它只处理一个文件,但不能处理多个文件。
尼尔·鲍德温

4
@ ghostdog74如果最慢的部分是因为tr,那么他可以grep首先执行,因此tr仅适用于匹配的行:grep th filename | tr ' ' '\n' | grep th
Carcamano 2015年

37

只是awk,不需要工具的组合。

# awk '{for(i=1;i<=NF;i++){if($i~/^th/){print $i}}}' file
the
the
the
this
thoroughly

8
@AjeetGanga好吧,它的名字是
Daerdemandt

11

grep命令仅用于匹配和perl

grep -o -P 'th.*? ' filename

3
只显示匹配组怎么办?
比什瓦斯·米什拉

这行不通;它只会找到,th因为您请求了最短的重复通配符。
三月

@tripleee-不会有问题,因为正则表达式的末尾包含一个空格。但是,它将遗漏在其后没有空格的单词,例如在行尾。
肯·威廉姆斯

8

我对awk难以记住的语法不满意,但是我喜欢使用一个实用程序来执行此操作的想法。

似乎ack(如果使用Ubuntu,则为ack-grep)可以轻松做到这一点:

# ack-grep -ho "\bth.*?\b" *

the
the
the
this
thoroughly

如果省略-h标志,则会得到:

# ack-grep -o "\bth.*?\b" *

some-other-text-file
1:the

some-text-file
1:the
the

yet-another-text-file
1:this
thoroughly

另外,您可以使用--output标志使用我发现的最简单的语法来执行更复杂的搜索:

# echo "bug: 1, id: 5, time: 12/27/2010" > test-file
# ack-grep -ho "bug: (\d*), id: (\d*), time: (.*)" --output '$1, $2, $3' test-file

1, 5, 12/27/2010


4

要搜索所有以“ icon-”开头的单词,可以使用以下命令。我在这里使用的Ack与grep类似,但具有更好的选项和良好的格式。

ack -oh --type=html "\w*icon-\w*" | sort | uniq

3

您也可以尝试pcregrepgrep中还有一个-w选项,但是在某些情况下,它不能按预期工作。

来自维基百科

cat fruitlist.txt
apple
apples
pineapple
apple-
apple-fruit
fruit-apple

grep -w apple fruitlist.txt
apple
apple-
apple-fruit
fruit-apple

3

我有一个类似的问题,正在寻找grep / pattern regex和“找到匹配的模式”作为输出。

最后,我使用了egrep(在grep -e或-G上的正则表达式没有给我相同的egrep结果)和-o选项

所以,我认为这可能类似于(我不是正则表达式大师):

egrep -o "the*|this{1}|thoroughly{1}" filename

{1}应当删除无用的量词。或者,如果你想成为一致的,t{1}h{1}e{1}等等
tripleee

可以用同一行打印吗?
吴毅凡2016年

-1

您可以将grep输出通过管道传输到Perl中,如下所示:

grep "th" * | perl -n -e'while(/(\w*th\w*)/g) {print "$1\n"}'

9
那不会给出正确的结果。另外,如果使用Perl,则无需使用grep。在Perl中做所有事情。
ghostdog74

感谢您指出错误,ghostdog74。我将其更改为在行上打印所有单词,而不仅仅是第一个。

就像我说的,grep是没有必要的。perl -n -e'while(/(\ s + th \ w *)/ g){print“ $ 1 \ n”}'文件
ghostdog74,2009年

7
由你决定。我只是说明一点。如果没有必要,请不要这样做。多余的“ |” 将使您多花费一个过程。
ghostdog74

1
在Perl 5.10或更高版本中:perl -nE'@a = /(regexp)/ ig; 说加入“ \ n”,@ a'–
Photon教授

-1
$ grep -w

摘自grep手册页:

-w:仅选择那些包含组成整个单词的匹配项的行。测试是匹配的子字符串必须在该行的开头,或者必须在非单词组成字符之前。


1
那仍然会打印出包含匹配项的整行。它限制了实际匹配,因此the不再匹配例如“这些”或“沐浴”。
2014年

-6

ripgrep

以下是使用示例ripgrep

rg -o "(\w+)?th(\w+)?"

它将匹配所有匹配的单词th

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.