【问题标题】:How do I find files that do not contain a given string pattern?如何查找不包含给定字符串模式的文件?
【发布时间】:2010-12-17 09:57:46
【问题描述】:

如何找出当前目录中文件包含单词foo(使用grep)?

【问题讨论】:

    标签: file grep directory find


    【解决方案1】:

    如果您的 grep 有 -L(或 --files-without-match)选项:

    $ grep -L "foo" *
    

    【讨论】:

    • 正如在别处指出的那样,默认情况下 ack 有助于避免使用 .svn (subversion) 文件。
    • @GuruM 这可以在 GNU grep 中通过导出变量 GREP_OPTIONS='--exclude-dir=.svn --exclude-dir=.git' 来完成 :^)
    • 或使用ag的等价物:ag -L 'foo'
    • 如果您想查找名称中没有多个内容的文件怎么办。 grep -L "foo,bar,baz" * ?
    • 像魔术一样工作!提示:使用-rL 而不是-L 来匹配子目录
    【解决方案2】:

    您可以单独使用 grep(无需查找)。

    grep -riL "foo" .
    

    这是grep上使用的参数说明

         -L, --files-without-match
                 each file processed.
         -R, -r, --recursive
                 Recursively search subdirectories listed.
    
         -i, --ignore-case
                 Perform case insensitive matching.
    

    如果你使用l(小写)你会得到相反的(匹配的文件)

         -l, --files-with-matches
                 Only the names of files containing selected lines are written
    

    【讨论】:

      【解决方案3】:

      看看ack。它会自动为您排除 .svn,为您提供 Perl 正则表达式,并且是单个 Perl 程序的简单下载。

      ack 中应该是您要查找的内容:

      ack -L foo
      

      【讨论】:

        【解决方案4】:

        下面的命令给了我所有不包含foo模式的文件:

        find .  -not  -ipath '.*svn*' -exec  grep  -H -E -o -c  "foo"  {} \; | grep 0
        

        【讨论】:

        • 您希望将末尾的 grep 0 更改为 grep 0$(否则您会在文件名中包含字符 0 的文件上得到错误匹配)。
        • @clouseau 基本上是正确的......但是,grep '0$' 也会匹配 10 行的倍数的文件!最后需要grep ':0$' 来检查行尾是否有明确的':0'。那么你只会得到零行匹配的文件。
        • 我使用的 UNIX 没有带有这些选项的 find 或 grep 版本,所以我不得不使用其他 cmets 中建议的“ack”命令。
        • 非常低效,因为 find 必须查找所有文件,包括那些包含“foo”的文件,然后在第二个进程中丢弃它们。对于正在寻找的大量文件将无法正常工作。应该提供使用内置 find 参数的解决方案。
        【解决方案5】:

        以下命令不需要 find 使用第二个 grep 过滤掉 svn 文件夹。

        grep -rL "foo" ./* | grep -v "\.svn"
        

        【讨论】:

          【解决方案6】:

          如果你使用 git,这会搜索所有被跟踪的文件:

          git grep -L "foo"
          

          如果您打开了 ** 子目录通配符,您可以在跟踪文件的子集中搜索(.bashrc 中的shopt -s globstar,请参阅this):

          git grep -L "foo" -- **/*.cpp
          

          【讨论】:

            【解决方案7】:

            你实际上需要:

            find .  -not  -ipath '.*svn*' -exec  grep  -H -E -o -c  "foo"  {} \; | grep :0\$
            

            【讨论】:

              【解决方案8】:

              我运气不错

              grep -H -E -o -c "foo" */*/*.ext | grep ext:0
              

              我对@9​​87654322@ 的尝试只是给了我所有没有“foo”的行。

              【讨论】:

                【解决方案9】:

                问题

                我需要重构一个使用 .phtml 文件的大型项目,以使用内联 PHP 代码写出 HTML。我想改用Mustache 模板。我想找到任何不包含字符串new Mustache.phtml giles,因为这些仍然需要重写。

                解决方案

                find . -iname '*.phtml' -exec grep -H -E -o -c 'new Mustache' {} \; | grep :0$ | sed 's/..$//'

                说明

                在管道之前:

                查找

                find .递归查找文件,从这个目录开始

                -iname '*.phtml' 文件名必须包含 .phtmli 使其不区分大小写)

                -exec 'grep -H -E -o -c 'new Mustache' {}' 在每个匹配的路径上运行grep 命令

                Grep

                -H 总是打印带有输出行的文件名标题。

                -E 将模式解释为扩展的正则表达式(即强制 grep 表现得像 egrep)。

                -o 仅打印行的匹配部分。

                -c 仅将选定的行数写入标准输出。


                这将为我提供以.phtml 结尾的所有文件路径的列表,并计算字符串new Mustache 在每个路径中出现的次数。

                $> find . -iname '*.phtml$' -exec 'grep -H -E -o -c 'new Mustache' {}'\;
                
                ./app/MyApp/Customer/View/Account/quickcodemanagestore.phtml:0
                ./app/MyApp/Customer/View/Account/studio.phtml:0
                ./app/MyApp/Customer/View/Account/orders.phtml:1
                ./app/MyApp/Customer/View/Account/banking.phtml:1
                ./app/MyApp/Customer/View/Account/applycomplete.phtml:1
                ./app/MyApp/Customer/View/Account/catalogue.phtml:1
                ./app/MyApp/Customer/View/Account/classadd.phtml:0
                ./app/MyApp/Customer/View/Account/orders-trade.phtml:0
                

                第一个管道 grep :0$ 过滤此列表以仅包含以 :0 结尾的行:

                $> find . -iname '*.phtml' -exec grep -H -E -o -c 'new Mustache' {} \; | grep :0$
                
                ./app/MyApp/Customer/View/Account/quickcodemanagestore.phtml:0
                ./app/MyApp/Customer/View/Account/studio.phtml:0
                ./app/MyApp/Customer/View/Account/classadd.phtml:0
                ./app/MyApp/Customer/View/Account/orders-trade.phtml:0
                

                第二个管道sed 's/..$//' 去掉每行的最后两个字符,只留下文件路径。

                $> find . -iname '*.phtml' -exec grep -H -E -o -c 'new Mustache' {} \; | grep :0$ | sed 's/..$//'
                
                ./app/MyApp/Customer/View/Account/quickcodemanagestore.phtml
                ./app/MyApp/Customer/View/Account/studio.phtml
                ./app/MyApp/Customer/View/Account/classadd.phtml
                ./app/MyApp/Customer/View/Account/orders-trade.phtml
                

                【讨论】:

                  【解决方案10】:

                  当您使用 find 时,您有两个基本选项:在 find 完成搜索后过滤掉结果,或者使用一些内置选项来阻止 find 考虑那些与给定模式匹配的文件和目录。

                  如果您对大量文件和目录使用前一种方法。您将使用大量 CPU 和 RAM 来将结果传递给第二个进程,而第二个进程又会使用大量资源过滤掉结果。

                  如果您使用作为查找参数的 -not 关键字,您将阻止考虑与后面的 -name 或 -regex 参数上的字符串匹配的任何路径,这将更加有效。

                  find . -not -regex ".*/foo/.*" -regex ".*"
                  

                  然后,任何未被 -not 过滤掉的路径都将被后续的 -regex 参数捕获。

                  【讨论】:

                  • 这会搜索不包含特定模式的文件 names,对吗?我认为 OP 的意思是文件 contents 不包含某种模式
                  • 嗯,这个问题本身有点含糊,我就是这么解释的。有些人在寻找排除文件名时肯定会找到这个线程。
                  【解决方案11】:

                  我的 grep 没有任何 -L 选项。我确实找到了解决方法来实现这一点。

                  这些想法是:

                  1. 将所有包含应得字符串的文件名转储到 txt1.txt。
                  2. 将目录中的所有文件名转储到一个txt2.txt中。
                  3. 用diff命令区分2个转储文件。

                    grep 'foo' *.log | cut -c1-14 | uniq > txt1.txt
                    grep * *.log | cut -c1-14 | uniq > txt2.txt
                    diff txt1.txt txt2.txt | grep ">"
                    

                  【讨论】:

                  • 我忘记了命令,但不是转储文件名,您实际上可以在两个输出流之间执行diff(我认为您将命令用括号括起来,并且在某处也有一个尖括号),如果您的系统支持它,我想这是个问题,因为它不支持 grep -L
                  【解决方案12】:

                  find *20161109* -mtime -2|grep -vwE "(TRIGGER)"

                  您可以在“find”下指定过滤器,在“grep -vwE”下指定排除字符串。如果您还需要过滤修改后的时间,请在 find 下使用 mtime。

                  【讨论】:

                  • 这似乎向我显示了没有字符串的所有行,OP 只要求提供文件名。
                  【解决方案13】:

                  打开错误报告

                  正如@tukan 评论的那样,有一个针对 Ag 的关于 -L/--files-without-matches 标志的开放错误报告:

                  由于错误报告几乎没有进展,所以下面提到的-L 选项不应依赖,只要错误尚未解决。请改用此线程中介绍的不同方法。引用错误报告的评论[强调我的]:

                  这方面有什么更新吗? -L 完全忽略文件第一行的匹配项。似乎如果这个问题不会很快得到解决,应该完全删除该标志,因为它根本不像宣传的那样有效


                  Silver Searcher - Ag(预期功能 - 参见错误报告)

                  作为grep 的强大替代品,您可以使用The Silver Searcher - Ag

                  类似ack的代码搜索工具,重点是速度。

                  查看man ag,我们发现-L--files-without-matches 选项:

                  ...
                  
                  OPTIONS
                      ...
                  
                      -L --files-without-matches
                             Only print the names of files that don´t contain matches.
                  

                  即,递归从当前目录中搜索与foo 不匹配的文件:

                  ag -L foo
                  

                  要仅在 当前 目录中搜索与 foo 不匹配的文件,只需为递归指定 --depth=0

                  ag -L foo --depth 0
                  

                  【讨论】:

                  【解决方案14】:

                  当 grep 没有 -L 选项时的另一种选择(例如 IBM AIX),只有 grep 和 shell:

                  for file in * ; do grep -q 'my_pattern' $file || echo $file ; done
                  

                  【讨论】:

                    【解决方案15】:

                    这可能对其他人有所帮助。我混合了文件Gotest 文件。但我只需要.go 文件。所以我用了

                    ls *.go | grep -v "_test.go"
                    

                    -v, --invert-match 选择不匹配的行见https://stackoverflow.com/a/3548465

                    也可以使用 vscode 来从终端打开所有文件

                    code $(ls *.go | grep -v "_test.go")
                    

                    【讨论】:

                      【解决方案16】:
                      grep -irnw "filepath" -ve "pattern"
                      

                      grep -ve "pattern" < file
                      

                      上面的命令会给我们结果,因为 -v 会找到正在搜索的模式的逆向

                      【讨论】:

                      • 这将打印不包含模式的行。您可以添加-l 选项以仅打印文件名;但这仍然会打印包含不包含模式的 any 行的任何文件的名称。我相信 OP 想要找到不包含任何包含该模式的行的文件。
                      • 您提供的命令列出了“文件路径”中的文件及其所有不包含“模式”的行。
                      【解决方案17】:

                      以下命令可以帮助您过滤包含子字符串“foo”的行。

                      cat file | grep -v "foo"
                      

                      【讨论】:

                      • 这将打印不匹配的行,而不是在任何行上不包含匹配的文件的名称。雪上加霜,写成useless use of cat
                      猜你喜欢
                      • 1970-01-01
                      • 1970-01-01
                      • 2015-12-27
                      • 2014-10-20
                      • 1970-01-01
                      • 1970-01-01
                      • 2016-05-06
                      • 2013-05-13
                      • 1970-01-01
                      相关资源
                      最近更新 更多