如何使用grep命令排除某些模式?

107

我希望能够查找文件中包含某个模式但不包含另一个模式的行。例如,我需要查找所有包含 loom 但不包含 gloom 的文件/行。因此,我可以使用以下命令查找 loom

grep -n 'loom' ~/projects/**/trunk/src/**/*.@(h|cpp)
现在,我希望搜索 loom,但不包括 gloom。然而,以下两个命令均失败:
grep -v 'gloom' -n 'loom' ~/projects/**/trunk/src/**/*.@(h|cpp)
grep -n 'loom' -v 'gloom' ~/projects/**/trunk/src/**/*.@(h|cpp)

我该做什么才能实现我的目标?

编辑1: 我的意思是 loomgloom 是字符序列(不一定是单词)。因此,例如,在命令输出中需要 bloomberg,而不需要 ungloomy

编辑2: 这是我的期望示例。以下两行都在命令输出中:

我面对着透过熏香的面纱隐现出来的图标。

阿蒂在阴沉的天气中缓缓移动。

以下两行都不在命令输出中:

这真是太可怕了 - 大片大片的云彩遮天蔽日。

在高高的点上西南方向的大厅里。


我正在寻找符合我的条件的行的文件。我想看到所有集合的文件名+匹配行数+匹配行本身的列表。 - Loom
如果这一行是 there is a loom in the gloom - 你想要打印出这一行吗?只是想了解您是否只寻找包含loom但不是作为gloom的一部分的行,还是即使loom在该行的其他位置上出现,您真的想要排除包含gloom的行。发布一些示例输入和预期输出将有所帮助。 - Ed Morton
1
@EdMorton - 是的,你说得对 - 我需要所有没有以 g 为前缀的包含 loom 的行。(抱歉,昨天我开始写评论,但从未完成。这个评论是意外发出的。) - Loom
在你的问题开头,你说你想要带有“织布机”但没有“忧郁”的行。但是如果看到你的编辑2,第二个样本输出中,既有slooming中的loom,也有gloomy天中的gloom,为什么呢? - Juto
@Juto - 是的,有些答案很好。但我还没有决定接受哪一个。 - Loom
显示剩余4条评论
10个回答

129

直接链式使用grep怎么样?

grep -n 'loom' ~/projects/**/trunk/src/**/*.@(h|cpp) | grep -v 'gloom'

16
及时到位。完美运行。-v选项用于排除。谢谢。 - Ravi Krishna P
5
从问题中得知,例如在命令输出中需要bloomberg,不需要ungloomy。如果一行文本包含了“...并且bloomberg对前景不感到沮丧...”,你应该删除这一行,但是如果这行包含了bloomberg,那么这一行是需要的。 - Jonathan Leffler

26

不使用链接 grep 的另一种解决方案:

egrep '(^|[^g])loom' ~/projects/**/trunk/src/**/*.@(h|cpp)

在方括号中,排除任何 loom 出现之前的字符 g,除非 loom 是行首的第一个字符。


对于像我这样的初学者,想知道什么是egrep:它是grep -E的别名(来源:man grep)。 - Pierre H.

11

有点老,但无所谓...

@houbysoft提供的得票最高的解决方案将不起作用,因为它会排除任何带有“gloom”的行,即使它有“loom”。根据OP的期望,我们需要包含具有“loom”的行,即使它们也带有“gloom”。这一行需要出现在输出中“Arty is slooming in a gloomy day.”,但是这将被类似串联的grep排除。

grep -n 'loom' ~/projects/**/trunk/src/**/*.@(h|cpp) | grep -v 'gloom'

相比之下,Bentoy13egrep正则表达式示例效果更好。

egrep '(^|[^g])loom' ~/projects/**/trunk/src/**/*.@(h|cpp)

因为它会包括任何具有“loom”的行,无论它是否有“gloom”。另一方面,如果只有“gloom”,那么它将不会被包括在内,这正是OP想要的行为。


9

只需使用 awk,相比于 grep ,它更简单,可以让您清楚地表示复合条件。

如果你想要跳过包含“loom”和“gloom”的行:

awk '/loom/ && !/gloom/{ print FILENAME, FNR, $0 }' ~/projects/**/trunk/src/**/*.@(h|cpp)

或者,如果你想打印它们:

awk '/(^|[^g])loom/{ print FILENAME, FNR, $0 }' ~/projects/**/trunk/src/**/*.@(h|cpp)

如果现实情况是你只想要出现loom单词本身这一行:

awk '/\<loom\>/{ print FILENAME, FNR, $0 }' ~/projects/**/trunk/src/**/*.@(h|cpp)

3
思考如何编写一个grep命令来获取任意顺序包含“abc”、“def”和“ghi”的行。现在将其与“awk '/abc/ && /def/ && /ghi/'”进行比较。现在思考如何编写grep等效的命令“awk '/loom/ && !/gloom/'”,这个问题的答案在本页中已经被写出了。 - Ed Morton
我对awk不是很熟悉,显然有关于这个命令的书籍。目前我还可以使用grep,也许有一天我会和你说同样的话。 :) - Juto
3
awk是处理文本文件的标准UNX工具(即在所有UNIX安装中都可用)。这就是它被发明出来要做的事情,而且它非常擅长。如果你正在UNIX上解析文本文件,请从Arnold Robins的《Effective Awk Programming, Third Edition》学习awk。与awk语法相关的 {条件}{动作} 的小范式转换需要一些时间适应,但对于有任何C或其他Algol基础语言经验的人来说,就轻而易举了。 - Ed Morton
奖励:输出类似于 grep -Hn --color 的内容:awk '/loom/ && !/gloom/ { gsub(/loom/, color("1;31") "&" color(0)); print color(35) FILENAME color(36) ":" color(32) FNR color(36) ":" color(0) $0; }; function color(c) { return "\033[" c "m"; }' - tangle

7

-v 是“反向匹配”标志,因此管道是一种非常好的方式:

grep "loom" ~/projects/**/trunk/src/**/*.@(h|cpp)| grep -v "gloom"

注:原文已经是英文,并且包含了html标签,为了不造成混淆,我直接使用了原文。

6

只需简单使用!多次使用grep -v

#文件内容

[root@server]# cat file
1
2
3
4
5

#排除行或匹配

[root@server]# cat file |grep -v 3
1
2
4
5

#排除行或匹配多个

[root@server]# cat file |grep -v "3\|5"
1
2
4

是的,但是您如何遍历一组类似的文件?如果要检查1000个文件,我不想运行此命令1000次。 - Sky Scraper

5
/*您可能正在寻找类似以下的内容?*/
grep -vn "gloom" `grep -l "loom" ~/projects/**/trunk/src/**/*.@(h|cpp)`

BACKQUOTES(反引号)像括号一样用于命令中,所以在启用-l的情况下,在BACKQUOTES中的代码将返回文件名,然后使用-vn可以获得所需的:文件名、行号和实际行。 更新 或者使用xargs。
grep -l "loom" ~/projects/**/trunk/src/**/*.@(h|cpp) | xargs grep -vn "gloom"

希望这有所帮助。*/

请忽略我上面写的,都是废话。

grep -n "loom" `grep -l "loom" tt4.txt` | grep -v "gloom"

               #this part gets the filenames with "loom"
#this part gets the lines with "loom"
                                          #this part gets the linenumber,
                                          #filename and actual line

4
您可以使用支持Perl正则表达式的 `grep -P`(negative lookbehind):
grep -P '(?<!g)loom\b' ~/projects/**/trunk/src/**/*.@(h|cpp)

我为单词边界添加了\b

2
你不需要使用lookbehind,\([^g]\|^\)就可以工作。而且这不会排除同时包含loomgloom的行。 - Kevin
@Kevin:OP想要找到包含loom但不包含gloom的行。 - anubhava
没错。如果一行同时拥有这两个,他不想要它,但是这个还是会匹配到它。 - Kevin
@Kevin:这不会匹配"gloom",但会匹配"loom"(正如OP所需)。 - anubhava
从问题中:因此,我需要在命令输出中得到bloomberg,而不需要ungloomy 因此,单词边界是适得其反的。 - Jonathan Leffler

3
grep -n 'loom' ~/projects/**/trunk/src/**/*.@(h|cpp) | grep -v 'gloom'

从问题中得知:我需要在命令输出中得到 bloomberg,而不需要 ungloomy。如果一行文字包含了“...and bloomberg is ungloomy about the prospects…”,你会将其删除,但是这行文字是需要的(因为它包含了 bloomberg)。 - Jonathan Leffler
1
@JonathanLeffler “我需要找到所有包含loom的文件/行,但不包括带有gloom的文件/行。” - Jiminion

0

问题:搜索“织布机”,但不包括“忧郁”。
答案:

grep -w 'loom' ~/projects/**/trunk/src/**/*.@(h|cpp)

1
从问题中:所以,我需要在命令输出中得到bloomberg,而不需要ungloomy 我认为 -w 不是解决这个难题的方法。 - Jonathan Leffler

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接