【问题标题】:Use grep --exclude/--include syntax to not grep through certain files使用 grep --exclude/--include 语法不通过某些文件 grep
【发布时间】:2021-06-20 09:04:06
【问题描述】:

我正在目录树的文本文件中查找字符串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 includegrep include excludegrep exclude 和变体上搜索未找到任何相关内容

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

【问题讨论】:

  • 仅供参考,使用的参数: -c 计算文件中的匹配 -i 不区分大小写 -l 只显示匹配的文件 -r 递归
  • 排除 svn 目录的更快方法是--exclude-dir=.svn,所以 grep 根本不会进入它们
  • 人们可能需要知道的几个迂腐点: 1. 请注意此处全局缺少引号:--exclude='.{png,jpg}' 不起作用(至少在我的 GNU grep 版本中)因为 grep 在其 glob 中不支持 {}。以上是外壳扩展为 '--exclude=.png --exclude=*.jpg' (假设 cwd 中没有文件匹配 - 极不可能,因为您通常不以 '--exclude 开头的文件名=') grep 喜欢就好了。 2. --exclude 是 GNU 扩展,不是 POSIX 对 grep 定义的一部分,所以如果您使用它编写脚本,请注意它们不一定会在非 GNU 系统上运行。
  • exclude-dir 使用的完整示例:grep -r --exclude-dir=var "pattern" .

标签: unix search shell command-line grep


【解决方案1】:

使用外壳globbing syntax:

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

--exclude 的语法相同。

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

2021-03-04 更新

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

原来的例子是:

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

搜索位于目录rootdir 中的所有.cpp.h 文件。

【讨论】:

  • 我不知道为什么,但我不得不像这样引用包含模式:grep pattern -r --include="*.{cpp,h}" rootdir
  • @topek: 好点——如果你的当前目录中有任何 .cpp/.h 文件,那么 shell 会在调用 grep 之前扩展 glob,所以你最终会得到一个命令像grep pattern -r --include=foo.cpp --include=bar.h rootdir 这样的行,它只会搜索名为foo.cppbar.h 的文件。如果当前目录中没有任何与 glob 匹配的文件,则 shell 会将 glob 传递给 grep,grep 会正确解释它。
  • 我刚刚意识到 glob 仅用于匹配文件名。要排除整个目录需要--exclude-dir 选项。但同样的规则适用。仅匹配目录文件名,而不是路径。
  • --include--exclude 之后似乎不起作用。我想即使尝试也没有意义,除了我有一个alias grep 和一长串--exclude--exclude-dir,我用它来搜索代码,忽略库和交换文件和东西。我希望grep -r --exclude='*.foo' --include='*.bar' 可以工作,所以我可以将我的alias 限制为仅--include='*.bar',但它似乎忽略了--include 并包含所有不是.foo 文件的内容。交换--include--exclude 的顺序是可行的,但是,这对我的alias 没有帮助。
  • 我们怎样才能读懂某人的想法来获得这个PATTERN的规则。半个小时我找不到任何关于他们在那里等什么的描述
【解决方案2】:

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

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

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

我将第二次Andy's 投票给ack,但这是最好的。

【讨论】:

  • +1 用于提及确切的版本号;我有 grep 2.5.1 并且 exclude-dir 选项不可用
【解决方案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

等等

正如 cmets 中所指出的,如果某些文件的名称中可能包含空格,请改用 -print0xargs -0

【讨论】:

  • 这不适用于带有空格的文件名,但是通过使用 print0 而不是 print 并将 -0 选项添加到 xargs 可以轻松解决该问题。
【解决方案4】:

目录中还有很多二进制文件。我不能只搜索某些目录(目录结构很乱)。是否有更好的方式仅在某些文件中进行 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 安装。

【讨论】:

    【解决方案5】:

    git grep

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

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

    示例语法:

    git grep --no-index "some_pattern"
    

    更多示例,请参见:

    【讨论】:

      【解决方案6】:

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

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

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

      【讨论】:

      • --exclude-dir 并非随处可用。我使用 GNU grep 2.5.1 的 RH 盒子没有它。
      • --exclude-dir 不可用时有什么建议吗?在我所有的尝试中,--exclude 似乎不符合要求。
      • 您可以随时从 GNU 下载最新的 grep 源代码,然后进行 'configure;制作;须藤使安装'。这是我在 Mac 或更早版本的 Linux 发行版上做的第一件事。
      • 正是我需要的。实际上,我使用 git。所以,--exclude-dir="\.git"。 :-)
      • @IonicăBizău git 有一个 grep 包装器,它仅搜索在您的存储库中编入索引的文件:git-scm.com/docs/git-grep
      【解决方案7】:

      如果您进行非递归搜索,您可以使用glop patterns 来匹配文件名。

      grep "foo" *.{html,txt}
      

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

      在子目录中搜索:

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

      在子子目录中:

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

      【讨论】:

        【解决方案8】:

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

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

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

        【讨论】:

          【解决方案9】:

          找了好久才发现这个,可以添加多个includes和excludes,比如:

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

          【讨论】:

          • 最好将它们组合在一个列表中,例如:--exclude={pattern1,pattern2,pattern3}
          【解决方案10】:

          试试这个:

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

          【讨论】:

            【解决方案11】:

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

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

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

            【讨论】:

              【解决方案12】:

              适用于 tcsh .alias 文件:

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

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

              【讨论】:

                【解决方案13】:

                看@这个。

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

                【讨论】:

                • 其他帖子已经介绍了大致实现这一点的事情;更重要的是,这是错误的,因为设置了各种布局选项,它会弄乱行号之类的东西,或者排除所需的上下文行。
                【解决方案14】:

                如果您不反对使用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 第四行就完成了。

                最后,在第 5 行是到 xargs 的管道,它获取每个结果文件并将它们存储在变量 FILENAME 中。然后它通过grep-IR标志,"pattern",然后FILENAMExargs扩展成为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 ...
                【解决方案15】:

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

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

                【讨论】:

                  【解决方案16】:

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

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

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

                  【讨论】:

                  • 来自遥远死者的死灵评论.... GREP_OPTIONS 现在已被弃用,所以我认为这些使用它的答案不再有效。嘿,我知道已经晚了,但这对我来说是个新闻。 :)
                  【解决方案17】:

                  GNU grep--binary-files=without-match 选项让它跳过二进制文件。 (相当于其他地方提到的-I 开关。)

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

                  【讨论】:

                    【解决方案18】:

                    建议的命令:

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

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

                    【讨论】:

                    • 是的,它对我来说根本不起作用。对我有用的是: exclude-dir=.svn
                    • @Nicola 谢谢!我一直在为为什么这行不通而烦恼。告诉我,有没有办法从手册页中发现这个?它所说的只是它与“PATTERN”匹配。 EDIT 手册页上写着“文件”,如此处所述fixunix.com/unix/…
                    【解决方案19】:

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

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

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

                    尽情享受吧! 在我的 linux shell 上找到了!呵呵

                    【讨论】:

                      【解决方案20】:

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

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

                      用 ack as 完成

                      ack -icl "foo="
                      

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

                      ack -icl --cpp "foo="
                      

                      【讨论】:

                      • 看起来不错,下次试试独立的 Perl 版本,谢谢。
                      • 好电话,没有ack我活不下去了。
                      • stackoverflow.com/questions/667471/… - 如果您正在运行 grep,这将允许您在 Windows 上获得确认。
                      • @Chance 也许你想要 silversearcher-ag,在 Ubuntu 中只需要 apt-get :)
                      • Ripgrep 也可以这样做 - 默认情况下忽略二进制文件和 git 忽略文件。要排除文件类型,请使用rg --type-not cpp,仅搜索使用rg --type cpp 的文件类型。您可以只下载一个可执行文件并运行它。
                      【解决方案21】:

                      试试这个:

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

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

                      【讨论】:

                      • 这不适用于带有空格的文件名,但是通过使用 print0 而不是 print 并将 -0 选项添加到 xargs 可以轻松解决该问题。
                      【解决方案22】:

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

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

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

                      【讨论】:

                      • 您可以使用grep -I 跳过二进制文件。
                      • 我年轻的时候也做过……现在我知道得更好了,当遇到问题时,第一件事就是 RTFM
                      • grepping grep 将删除颜色亮点。
                      猜你喜欢
                      • 2010-09-18
                      • 1970-01-01
                      • 1970-01-01
                      • 2014-10-13
                      • 1970-01-01
                      • 2012-11-22
                      • 1970-01-01
                      • 1970-01-01
                      • 2013-08-23
                      相关资源
                      最近更新 更多