我正在目录树的文本文件中查找字符串 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 include、grep include exclude、grep exclude 和变体上搜索未找到任何相关内容
如果只有在某些文件中有更好的 grepping 方法,我完全赞成;移动有问题的文件不是一种选择。我不能只搜索某些目录(目录结构很乱,到处都是)。此外,我无法安装任何东西,所以我必须使用常用工具(如 grep 或建议的 find)。
--exclude-dir=.svn
,因此 grep 根本不会进入它们
grep -r --exclude-dir=var "pattern" .
使用外壳 globbing syntax:
grep pattern -r --include=\*.cpp --include=\*.h rootdir
--exclude
的语法相同。
请注意,星号用反斜杠转义,以防止它被 shell 扩展(引用它,例如 --include="*.cpp"
,也可以)。否则,如果当前工作目录中有任何与该模式匹配的文件,则命令行将扩展为 grep pattern -r --include=foo.cpp --include=bar.cpp rootdir
之类的内容,它只会搜索名为 foo.cpp
和 bar.cpp
的文件,这很可能不是您的通缉。
2021-03-04 更新
我已经编辑了原始答案以删除 brace expansion 的使用,这是 Bash 和 zsh 等几个 shell 提供的一个功能,用于简化这样的模式;但请注意,大括号扩展不符合 POSIX shell。
原来的例子是:
grep pattern -r --include=\*.{cpp,h} rootdir
搜索根目录 rootdir
中的所有 .cpp
和 .h
文件。
如果您只想跳过二进制文件,我建议您查看 -I
(大写 i)选项。它忽略二进制文件。我经常使用以下命令:
grep -rI --exclude-dir="\.svn" "pattern" *
它递归搜索,忽略二进制文件,并且不会在 Subversion 隐藏文件夹中查找我想要的任何模式。我在工作的盒子上将它别名为“grepsvn”。
--exclude-dir
并非随处可用。我使用 GNU grep 2.5.1 的 RH 盒子没有它。
--exclude-dir
不可用时使用什么的任何建议?在我所有的尝试中,--exclude
似乎都不符合要求。
--exclude-dir="\.git"
。 :-)
请查看ack,它正是为这些情况而设计的。你的例子
grep -ircl --exclude=*.{png,jpg} "foo=" *
用 ack 完成
ack -icl "foo="
因为默认情况下 ack 从不查找二进制文件,而 -r 默认情况下是打开的。如果你只想要 CPP 和 H 文件,那么就做
ack -icl --cpp "foo="
apt-get
:)
rg --type-not cpp
,仅搜索您使用的文件类型 rg --type cpp
。您可以只下载一个可执行文件并运行它。
很长一段时间后我发现了这一点,您可以添加多个包含和排除,例如:
grep "z-index" . --include=*.js --exclude=*js/lib/* --exclude=*.min.js
建议的命令:
grep -Ir --exclude="*\.svn*" "pattern" *
在概念上是错误的,因为 --exclude 对基本名称起作用。换句话说,它只会跳过当前目录中的 .svn。
在 grep 2.5.1 中,您必须将此行添加到 ~/.bashrc 或 ~/.bash 配置文件
export GREP_OPTIONS="--exclude=\*.svn\*"
我发现 grepping grep 的输出有时很有帮助:
grep -rn "foo=" . | grep -v "Binary file"
不过,这实际上并不能阻止它搜索二进制文件。
grep -I
跳过二进制文件。
如果您不反对使用 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
-prune
之后立即包含 -false
,因此忘记使用 -print0
或某种 exec
命令实际上不会打印您想要排除的文件:-name "*.png" -prune -false -o name "*.gif -prune -false
...
在 CentOS 6.6/Grep 2.6.3 上,我必须像这样使用它:
grep "term" -Hnir --include \*.php --exclude-dir "*excluded_dir*"
请注意缺少等号“=”(否则 --include
、--exclude
、include-dir
和 --exclude-dir
将被忽略)
git grep
使用针对性能进行了优化并旨在搜索特定文件的 git grep
。
默认情况下,它会忽略二进制文件并尊重您的 .gitignore
。如果您不使用 Git 结构,您仍然可以通过传递 --no-index
来使用它。
示例语法:
git grep --no-index "some_pattern"
有关更多示例,请参见:
如何从 git grep 搜索中排除某些目录/文件。
检查文件中是否存在所有多个字符串或正则表达式
我是一个外行,当然,但这是我的 ~/.bash_profile 的样子:
export GREP_OPTIONS="-orl --exclude-dir=.svn --exclude-dir=.cache --color=auto" GREP_COLOR='1;32'
请注意,要排除两个目录,我必须使用 --exclude-dir 两次。
如果您进行非递归搜索,您可以使用 glop patterns 来匹配文件名。
grep "foo" *.{html,txt}
包括html和txt。它仅在当前目录中搜索。
在子目录中搜索:
grep "foo" */*.{html,txt}
在子子目录中:
grep "foo" */*/*.{html,txt}
目录中还有许多二进制文件。我不能只搜索某些目录(目录结构很乱)。是否有更好的方法仅在某些文件中进行 grepping?
ripgrep
这是设计用于递归搜索当前目录的最快工具之一。它是用 Rust 编写的,构建在 Rust's regex engine 之上以实现最高效率。检查 detailed analysis here。
所以你可以运行:
rg "some_pattern"
它尊重您的 .gitignore
并自动跳过隐藏文件/目录和二进制文件。
您仍然可以使用 -g
/--glob
自定义包含或排除文件和目录。通配符规则匹配 .gitignore
个 glob。检查 man rg
寻求帮助。
有关更多示例,请参阅:How to exclude some files not matching certain extensions with grep?
在 macOS 上,您可以通过 brew install ripgrep
安装。
试试这个:
$ find . -name "*.txt" -type f -print | xargs file | grep "foo=" | cut -d: -f1
在此成立:http://www.unix.com/shell-programming-scripting/42573-search-files-excluding-binary-files.html
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
等等
正如评论中所指出的,如果某些文件的名称中可能包含空格,请改用 -print0
和 xargs -0
。
那些脚本并不能解决所有问题......试试这个更好:
du -ha | grep -i -o "\./.*" | grep -v "\.svn\|another_file\|another_folder" | xargs grep -i -n "$1"
这个脚本更好,因为它使用“真正的”正则表达式来避免搜索目录。只需用“\|”分隔文件夹或文件名在 grep -v
好好享受!在我的 linux shell 上找到了! XD
看@这个。
grep --exclude="*\.svn*" -rn "foo=" * | grep -v Binary | grep -v tags
GNU grep
的 --binary-files=without-match
选项使其跳过二进制文件。 (相当于别处提到的 -I
开关。)
(这可能需要最新版本的 grep
;至少 2.5.3 有它。)
适用于 tcsh .alias 文件:
alias gisrc 'grep -I -r -i --exclude="*\.svn*" --include="*\."{mm,m,h,cc,c} \!* *'
我花了一段时间才弄清楚 {mm,m,h,cc,c} 部分不应该在引号内。 〜基思
忽略来自 grep 的所有二进制结果
grep -Ri "pattern" * | awk '{if($1 != "Binary") print $0}'
awk 部分将过滤掉所有二进制文件 foo 匹配行
尝试这个:
在 currdir 下创建一个名为“--F”的文件夹 ..(或链接另一个文件夹重命名为“--F”,即双减-F。#> grep -i --exclude-dir="\-\-F “ “图案” *
grep pattern -r --include="*.{cpp,h}" rootdir
grep pattern -r --include=foo.cpp --include=bar.h rootdir
的命令行,这将仅搜索名为foo.cpp
或bar.h
的文件。如果当前目录中没有任何与 glob 匹配的文件,则 shell 会将 glob 传递给 grep,grep 会正确解释它。--exclude-dir
选项。但同样的规则适用。只有目录文件名匹配,而不是路径。--include
在--exclude
之后似乎不起作用。我想即使尝试也没有任何意义,除了我有一个alias
可以用一长串--exclude
和--exclude-dir
进行 grep,我用它来搜索代码、忽略库和交换文件和东西。我希望grep -r --exclude='*.foo' --include='*.bar'
可以工作,所以我可以将我的alias
限制为--include='*.bar'
,但它似乎忽略了--include
并包含所有不是 .foo 文件的内容。交换--include
和--exclude
的顺序是可行的,但是,这对我的alias
没有帮助。PATTERN
的规则。半个小时我找不到任何关于他们在那里等什么的描述