使用grep --exclude /-include语法不对某些文件进行grep


779

我正在寻找foo=目录树中文本文件中的字符串。在普通的Linux机器上,我有bash shell:

grep -ircl "foo=" *

目录中还包含许多匹配“ foo =“的二进制文件。由于这些结果无关紧要,并且拖慢了搜索速度,因此我希望grep跳过对这些文件(主要是JPEG和PNG图像)的搜索。我该怎么做?

我知道有--exclude=PATTERN--include=PATTERN选项,但是模式格式是什么?grep的手册页显示:

--include=PATTERN     Recurse in directories only searching file matching PATTERN.
--exclude=PATTERN     Recurse in directories skip file matching PATTERN.

搜索grep包含grep包含排除grep排除和变体未找到任何相关内容

如果只在某些文件中有一种更好的grepping方式,我全力以赴。移动有问题的文件不是一种选择。我无法仅搜索某些目录(目录结构混乱不堪,到处都是东西)。另外,我什么也无法安装,因此必须使用通用工具(例如grep或建议的find)。


13
仅供参考,使用的参数为:-c计算文件中的匹配项-i不区分大小写-l仅显示匹配的文件-r递归
Piskvor于

68
排除svn dirs的更快方法是--exclude-dir=.svn,因此grep根本不会加入它们
orip

25
人们可能需要了解以下几个学问点:1.请注意,这里的glob周围缺少引号:--exclude =' 。{png,jpg}'不起作用(至少对于我的GNU grep版本而言),因为grep不支持{}。上面的内容被shell扩展为'--exclude = .png --exclude = *。jpg'(假设cwd中没有文件匹配-极不可能,因为您通常不以'--exclude ='开头文件名) grep喜欢就好。2. --exclude是GNU扩展,不是POSIX定义的grep的一部分,因此,如果您使用此脚本编写脚本,请注意它们不一定会在非GNU系统上运行。
ijw 2011年

2
排除目录用法的完整示例:grep -r --exclude-dir=var "pattern" .
Tisch

Answers:


766

使用shell全局语法:

grep pattern -r --include=\*.{cpp,h} rootdir

的语法--exclude相同。

请注意,该星号以反斜杠转义,以防止它被外壳扩展(引用,例如--include="*.{cpp,h}",也可以正常工作)。否则,如果当前工作目录中有任何与模式匹配的文件,则命令行将扩展为grep pattern -r --include=foo.cpp --include=bar.h rootdir,仅搜索名为foo.cpp和的文件bar.h,这很可能不是您想要的。


8
我不知道为什么,但是我不得不引用这样的包含模式:grep pattern -r --include="*.{cpp,h}" rootdir
topek 2011年

6
@topek:好点-如果当前目录中有任何.cpp / .h文件,那么外壳程序将在调用grep之前扩展glob,因此您将得到一个类似的命令行grep pattern -r --include=foo.cpp --include=bar.h rootdir,该命令行仅搜索文件命名为foo.cppbar.h。如果在当前目录中没有与glob匹配的文件,那么外壳程序会将glob传递给grep,grep会正确解释它。
亚当·罗森菲尔德

6
我刚刚意识到,该glob仅用于匹配文件名。要排除整个目录,需要一个--exclude-dir选项。尽管有相同的规则。仅匹配目录文件名,不匹配路径。
KrzysztofJabłoński2015年

3
--include之后似乎没有工作--exclude。我想尝试一下甚至没有任何意义,只是我有一个aliasto grep带有一长串--excludeand --exclude-dir,我用它来搜索代码,忽略库以及交换文件和其他东西。我希望它能grep -r --exclude='*.foo' --include='*.bar'起作用,所以我可以将其限制alias--include='*.bar'only,但是它似乎忽略了,--include并包含了所有不是.foo文件的内容。交换--include--exclude工程的顺序,但是可惜,这对我没有帮助alias
Michael Scheper

1
我们如何才能读懂某人的想法以获取规则PATTERN。半小时我找不到他们在等什么的描述
Arkady '18

221

如果您只想跳过二进制文件,建议您查看-I(大写i)选项。它忽略二进制文件。我经常使用以下命令:

grep -rI --exclude-dir="\.svn" "pattern" *

对于我想要的任何模式,它都会递归搜索,忽略二进制文件,并且不会在Subversion隐藏文件夹中查找。在工作中,我将其别名为“ grepsvn”。


1
谢谢,这对于我遇到的其他情况非常有用。
Piskvor于

25
--exclude-dir并非到处都有。我与GNU grep 2.5.1一起使用的RH盒没有它。
gcb 2012年

关于什么时候--exclude-dir不可用该使用什么建议?在我所有的尝试中,--exclude似乎都不符合要求。
JMTyler 2014年

您始终可以从GNU下载最新的grep源,然后执行“配置”;使; sudo make install”。这是我在Mac或更旧的Linunx发行版上要做的第一件事。
乔纳森·哈特利

3
正是我所需要的。实际上,我使用git。因此,--exclude-dir="\.git"。:-)
尼卡比曹

66

请看看ack,它是专门为这些情况而设计的。您的例子

grep -ircl --exclude=*.{png,jpg} "foo=" *

用ack完成

ack -icl "foo="

因为ack缺省情况下不会在二进制文件中查找,而-r缺省情况下处于打开状态。如果只需要CPP和H文件,则只需执行

ack -icl --cpp "foo="

看起来不错,下次将尝试独立的Perl版本。
Piskvor于

5
好电话,我不能再没有ack了。
机会

1
stackoverflow.com/questions/667471/…-如果您从此处运行grep,它将允许您在Windows上进行确认。
TamusJRoyce 2010年

@Chance也许您只需要在Ubuntu中使用silversearcher-agapt-get :)
Justme0 '16

不要与awk
jasonleonhard

35

grep 2.5.3引入了--exclude-dir参数,该参数将按您希望的方式工作。

grep -rI --exclude-dir=\.svn PATTERN .

您还可以设置环境变量:GREP_OPTIONS =“-exclude-dir = .svn”

我将第二安迪的投票ACK虽然,这是最好的。


7
+1提及确切的版本号;我有grep 2.5.1,但exclude-dir选项不可用
James

25

很久以后我发现了这一点,您可以添加多个包含和排除对象,例如:

grep "z-index" . --include=*.js --exclude=*js/lib/* --exclude=*.min.js

5
最好将它们合并在一个列表中,例如:
exclude

12

建议的命令:

grep -Ir --exclude="*\.svn*" "pattern" *

从概念上讲是错误的,因为--exclude在基本名称上起作用。换句话说,它将仅跳过当前目录中的.svn。


3
是的,对我来说根本不起作用。对我有用的是:exclude-dir = .svn
Taryn East

2
@Nicola谢谢!我一直在想为什么不起作用。告诉我,有没有一种方法可以从联机帮助页中找到它?它只说匹配“ PATTERN”。 编辑手册页说:“文件”,这里解释fixunix.com/unix/...
13ren

11

在grep 2.5.1中,您必须将此行添加到〜/ .bashrc或〜/ .bash配置文件中

export GREP_OPTIONS="--exclude=\*.svn\*"

9

我发现grep的grep输出有时会很有帮助:

grep -rn "foo=" . | grep -v "Binary file"

但是,这实际上并不能阻止它搜索二进制文件。


10
您可以grep -I用来跳过二进制文件。
内森·费尔曼

我还很小的时候就做过...现在我知道了,遇到了问题时,第一件事就是RTFM
gcb 2012年

grepping grep将删除突出显示的颜色。
马克斯·李

7

如果您不find喜欢使用,我喜欢它的-prune功能:

find [directory] \
        -name "pattern_to_exclude" -prune \
     -o -name "another_pattern_to_exclude" -prune \
     -o -name "pattern_to_INCLUDE" -print0 \
| xargs -0 -I FILENAME grep -IR "pattern" FILENAME

在第一行,您指定要搜索的目录。 .(当前目录)是有效路径。

在第二和第三线,使用"*.png""*.gif""*.jpg",等等。根据需要使用尽可能多的这些-o -name "..." -prune构造。

在第四行,您需要另一个-o(它在中指定“或” find),您想要的模式,并且在其末尾需要a -print-print0。如果你只是想“一切”是修剪后的遗体*.gif*.png等图像,然后用 -o -print0和你与4号线实现。

最后,在第5行是xargs将所有这些结果文件存储到变量中的管道FILENAME。然后,它传递grep-IR标志,"pattern"以及随后FILENAME被扩展xargs成为文件名的该列表中发现find

对于您的特定问题,该语句可能类似于:

find . \
     -name "*.png" -prune \
     -o -name "*.gif" -prune \
     -o -name "*.svn" -prune \
     -o -print0 | xargs -0 -I FILES grep -IR "foo=" FILES


我建议的一项修正:-false在每次-prune-print0exec-name "*.png" -prune -false -o name "*.gif -prune -false
删除

7

在CentOS 6.6 / Grep 2.6.3上,我必须像这样使用它:

grep "term" -Hnir --include \*.php --exclude-dir "*excluded_dir*"

注意缺乏等号“=”(否则--include--excludeinclude-dir--exclude-dir被忽略)



5

我是公认的,但这是我的〜/ .bash_profile的样子:

export GREP_OPTIONS =“-orl --exclude-dir = .svn --exclude-dir = .cache --color = auto” GREP_COLOR ='1; 32'

请注意,要排除两个目录,我必须使用--exclude-dir两次。



3

如果您非递归搜索,则可以使用组合样式来匹配文件名。

grep "foo" *.{html,txt}

包括html和txt。它仅在当前目录中搜索。

要搜索子目录:

   grep "foo" */*.{html,txt}

在子目录中:

   grep "foo" */*/*.{html,txt}

3

目录中还有许多二进制文件。我无法仅搜索某些目录(目录结构非常混乱)。仅在某些文件中有更好的grepping方法吗?

ripgrep

这是旨在递归搜索当前目录的最快工具之一。它是用Rust编写的,构建在Rust的regex引擎之上,以实现最高效率。在此处检查详细分析

这样就可以运行:

rg "some_pattern"

它尊重你 .gitignore并自动跳过隐藏的文件/目录和二进制文件。

您仍然可以使用-g/ 自定义包含或排除文件和目录--glob。通配规则与通配符匹配.gitignore。检查man rg帮助。

有关更多示例,请参见:如何使用grep排除与某些扩展名不匹配的某些文件?

在macOS上,您可以通过进行安装brew install ripgrep


3

find和xargs是您的朋友。使用它们来过滤文件列表,而不是grep的--exclude

尝试类似

find . -not -name '*.png' -o -type f -print | xargs grep -icl "foo="

习惯于此的优点是,它可以扩展到其他用例,例如,计算所有非png文件中的行数:

find . -not -name '*.png' -o -type f -print | xargs wc -l

要删除所有非png文件:

find . -not -name '*.png' -o -type f -print | xargs rm

等等

如注释中所指出,如果某些文件的名称中可能有空格,请使用-print0xargs -0代替。


1
这不适用于带空格的文件名,但是可以通过使用print0而不是print并将-0选项添加到xargs来轻松解决该问题。
亚当·罗森菲尔德

2

这些脚本无法解决所有问题...请尝试以下更好的方法:

du -ha | grep -i -o "\./.*" | grep -v "\.svn\|another_file\|another_folder" | xargs grep -i -n "$1"

此脚本更好,因为它使用“真实”正则表达式来避免搜索目录。只需用“ \ |”分隔文件夹或文件名 在grep -v上

好好享受!在我的Linux Shell上找到!XD


2

看@这个。

grep --exclude="*\.svn*" -rn "foo=" * | grep -v Binary | grep -v tags

2
其他职位还介绍了可以实现上述目标的事情;而且,这是错误的,因为设置了各种布局选项,它将使行号和类似内容弄乱,或者排除所需的上下文行。
克里斯·摩根

如何同时使用多个“ -v”选项?
打开方式

1

--binary-files=without-matchGNU 的选项grep使它可以跳过二进制文件。(等效于-I其他地方提到的开关。)

(这可能grep至少需要2.5.3 的最新版本。)


1

适用于tcsh .alias文件:

alias gisrc 'grep -I -r -i --exclude="*\.svn*" --include="*\."{mm,m,h,cc,c} \!* *'

花了我一段时间才弄清楚{mm,m,h,cc,c}部分不应放在引号内。〜基思


0

忽略grep的所有二进制结果

grep -Ri "pattern" * | awk '{if($1 != "Binary") print $0}'

awk部分将过滤掉所有二进制文件foo匹配的行


-2

尝试这个:

  1. --F在currdir ..下创建一个名为“ ” 的文件夹(或链接另一个重命名为“ --F”的文件夹double-minus-F
  2. #> grep -i --exclude-dir="\-\-F" "pattern" *
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.