862

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

grep -ircl "foo=" *

目录中还有许多匹配的二进制文件"foo="。由于这些结果不相关并且会减慢搜索速度,因此我希望 grep 跳过搜索这些文件(主要是 JPEG 和 PNG 图像)。我该怎么做?

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

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

grep includegrep include excludegrep exclude和变体上搜索未找到任何相关内容

如果只有在某些文件中有更好的 grepping 方法,我完全赞成;移动有问题的文件不是一种选择。我不能只搜索某些目录(目录结构很乱,到处都是)。此外,我无法安装任何东西,所以我必须使用常用工具(如grep或建议的find)。

4

22 回答 22

874

使用 shell通配符语法

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

for 的语法--exclude是相同的。

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

2021-03-04 更新

我已经编辑了原始答案以删除使用大括号扩展,这是 Bash 和 zsh 等几个 shell 提供的一个功能,用于简化这样的模式;但请注意,大括号扩展不符合 POSIX shell。

原来的例子是:

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

搜索根目录中的.cpp所有文件。.hrootdir

于 2008-10-21T13:44:01.793 回答
229

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

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

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

于 2008-10-21T14:12:04.623 回答
72

请查看ack,它专为这些情况而设计。你的例子

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

用 ack 完成

ack -icl "foo="

因为默认情况下 ack 从不查找二进制文件,而 -r 默认情况下是打开的。如果你只想要 CPP 和 H 文件,那么就做

ack -icl --cpp "foo="
于 2008-10-21T14:18:19.400 回答
36

grep 2.5.3 引入了--exclude-dir可以按照您想要的方式工作的参数。

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

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

不过,我会支持安迪对ack的投票,这是最好的。

于 2009-02-04T18:41:39.567 回答
30

很长一段时间后我发现了这一点,您可以添加多个包含和排除,例如:

grep "z-index" . --include=*.js --exclude=*js/lib/* --exclude=*.min.js
于 2012-12-20T04:54:44.537 回答
13

建议的命令:

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

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

于 2008-12-17T18:56:38.317 回答
11

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

export GREP_OPTIONS="--exclude=\*.svn\*"
于 2010-04-01T10:13:14.727 回答
8

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

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

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

于 2008-10-21T13:44:45.973 回答
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

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

在第 2 行和第 3 行,使用"*.png", "*.gif", "*.jpg", 等等。尽可能多地使用这些-o -name "..." -prune结构,就像你有模式一样。

在第 4 行,你需要另一个-o(它指定“或”到find),你想要的模式,你需要一个-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

于 2011-11-14T20:41:29.233 回答
7

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

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

注意缺少等号“=”(否则,,,--include--excludeinclude-dir忽略--exclude-dir

于 2014-11-07T18:43:19.663 回答
6

git grep

使用git grep针对性能进行了优化,旨在搜索某些文件。

默认情况下,它会忽略二进制文件并尊重您的.gitignore. 如果你不使用 Git 结构,你仍然可以通过传递--no-index.

示例语法:

git grep --no-index "some_pattern"

有关更多示例,请参见:

于 2018-04-15T01:51:24.053 回答
5

我是一个外行,当然,但这是我的 ~/.bash_profile 的样子:

导出 GREP_OPTIONS="-orl --exclude-dir=.svn --exclude-dir=.cache --color=auto" GREP_COLOR='1;32'

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

于 2009-08-27T06:02:29.330 回答
4

目录中还有许多二进制文件。我不能只搜索某些目录(目录结构很乱)。是否有更好的方法仅在某些文件中进行 grepping?

ripgrep

这是设计用于递归搜索当前目录的最快工具之一。它是用Rust编写的,构建在Rust 的正则表达式引擎之上以实现最高效率。在这里查看详细分析

所以你可以运行:

rg "some_pattern"

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

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

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

在 macOS 上,您可以通过brew install ripgrep.

于 2018-04-15T01:45:38.767 回答
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

等等

正如评论中所指出的,如果某些文件的名称中可能包含空格,请使用-print0andxargs -0代替。

于 2008-10-21T13:45:26.893 回答
3

试试这个:

$查找。-name "*.txt" -type f -print | xargs 文件 | grep "foo=" | 剪切-d:-f1

在这里成立:http ://www.unix.com/shell-programming-scripting/42573-search-files- exclude-binary-files.html

于 2008-10-21T13:54:13.677 回答
3

如果您以非递归方式搜索,则可以使用glop 模式来匹配文件名。

grep "foo" *.{html,txt}

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

在子目录中搜索:

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

在子子目录中:

   grep "foo" */*/*.{html,txt}
于 2016-08-22T02:30:22.473 回答
2

那些脚本并不能解决所有问题......试试这个更好:

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

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

好好享受!在我的 linux shell 上找到了!XD

于 2008-11-05T08:30:45.060 回答
2

看@这个。

grep --exclude="*\.svn*" -rn "foo=" * | grep -v Binary | grep -v tags
于 2010-11-10T05:11:55.040 回答
1

--binary-files=without-matchGNU的选项grep让它跳过二进制文件。(相当于-I别处提到的开关。)

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

于 2009-04-06T11:15:46.977 回答
1

适用于 tcsh .alias 文件:

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

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

于 2012-04-02T17:33:44.170 回答
-1

忽略来自 grep 的所有二进制结果

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

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

于 2010-09-16T18:34:53.810 回答
-3

试试这个:

  1. 在 currdir ..下创建一个名为“ --F”的文件夹 ..(或链接另一个文件夹重命名为“ --F”即double-minus-F
  2. #> grep -i --exclude-dir="\-\-F" "pattern" *
于 2010-11-10T23:50:26.257 回答