如何使用grep排除某些与某些扩展名不匹配的文件?


8

我想OK从目录中递归输出所有包含单词的行。但是我需要从结果中排除一些扩展:

*~
*.map
*.js except *.debug.js

我试过了:

grep -r --exclude={*~,*.map} "OK" /some/dir

除了我不知道如何从结果中删除所有那些非调试.js文件。

Answers:


7

我只是将其grep删除一秒钟:

grep -r --exclude={\*~,\*.map} "OK" bar/ | grep -vP '(?<!debug)\.js'

-v逆转的比赛中,打印不匹配的图案与线条-P使Perl兼容的正则表达式这让我们用负lookbehinds。这个特定的正则表达式,将匹配.js通过prececeded debug哪个装置(因为我们反转匹配),只有那些.js文件将被打印。

但是,正如@QuestionOverflow指出int注释一样,这可能会产生意外的副作用,即过滤掉包含和的,这是因为不仅应用于文件名,而且应用于整个输出。为了避免这种情况,只需添加一个冒号(这就是用来将文件名与文件内容分开的方法):OKjsgrep -vgrep

grep -r --exclude={*~,*.map} "OK" bar/ | grep -vP '(?<!debug).js:'

如果您的输入行包含foo.js:或文件名包含,那仍然会失败:。因此,可以肯定的是,请使用其他方法:

grep -Tr --exclude={*~,*.map} "OK" bar/ | grep -vP '(?<!debug).js\t'

在文件名和文件内容之间打印选项卡的-T原因grep。因此,如果我们仅\t在正则表达式的末尾添加a ,它将仅与文件名匹配,而不与行的内容匹配。

不过,无论如何,使用find可能更有意义。


1
我会在不经意间不计,我希望这些文件中的行,但包含OK.js在同一行?
问题溢出

@QuestionOverflow啊,是的,确实不错。查看最新答案。
terdon

很棒的答案。因为我特别要求grep,所以必须接受您的要求。谢谢。
问题溢出

@QuestionOverflow非常欢迎。总的来说,find这种事情可能会更好。grep如您所指出的,正确的选择可能很棘手:)。
terdon

如果failglob在shell中设置了选项,您的解决方案将失败: bash: no match: --exclude=*~ 您需要引用GLOB模式参数--exclude以将其从shell扩展中隐藏起来,例如--exclude={\*~,\*.map}
Ian D. Allen

7

我会find用来定位文件并通过管道传递结果xargs

$ find . -type f \! -name "*~" \
                 \! -name "*.map" \
                 \! \( -name "*.js" -and \! -name "*.debug.js" \) \
         -print0 | xargs -0 grep "OK"

这将搜索匹配“ *~”,“ *.map”或“ *.js但不匹配”的每个文件*.debug.js

使用find它可以轻松地搜索相当复杂的规则,并且这种方法可以避免意外删除误报(如double可能发生)grep


也是一个不错的答案:)
2014年

3
是的,这可能是最好的方法+1。您也可以使用 -exec grep OK {} +代替xargs并避免使用额外的程序。
terdon

2
@IDAllen不,请注意,我建议-exec +不要这样做-exec \;,那样将运行尽可能少的命令,就像xargs
terdon

4

有了zsh您就可以做到:

setopt extendedglob
grep OK some/dir/**/^(*~|*.map|(^*debug).js)

当然,要提供的参数列表不会太长,在这种情况下,您始终可以执行以下操作:

printf '%s\0' some/dir/**/^(*~|*.map|(^*debug).js) | xargs -0 grep OK

另外,您可以zshautoload zargszargs some/dir/**/^(*~|*.map|(^*debug).js) -- grep OK
只做

2

如果您不介意看到输出有点混乱(如果这样做,则可以对其进行排序):

grep -r --exclude={*~,*.map,*.js} "OK" /some/dir **/*.debug.js

这要求您的shell支持**递归glob:zsh开箱即用,bash在运行后运行shopt -s globstar,ksh93在运行后运行set -o globstar

如果没有**外壳支持,则可以使用两个grep命令:

grep -r --exclude={*~,*.map,*.js} "OK" /some/dir
grep -r --include=*.debug.js "OK" /some/dir

我的shell支持**,但是多余的参数似乎出了点问题**/*.debug.js,导致grep解释OK为目录。您是否尝试过运行它?
2014年

@QuestionOverflow我的错误,我调换了参数的顺序。
吉尔(Gilles)'所以

2

您可以使用ripgrep。默认情况下,它会忽略隐藏文件并尊重您的.gitignore文件。

您可以使用以下参数指定包含或排除规则:

-g/ --glob GLOB包含或排除与给定的glob相匹配的文件和目录。

-t/ --type TYPE仅搜索与TYPE相匹配的文件。可以提供多种类型的标志。

-T/ --type-not TYPE不要搜索与TYPE相匹配的文件。

使用该--type-list标志列出所有可用的类型。

以下是一些简单的示例:

rg -Tjs "OK"                              # Excludes *.js, *.jsx, *.vue files.
rg -tpy "OK"                              # Includes Python files.
rg --type-add 'map:*.map' -tmap PATTERN   # Excludes *.map files.
rg -g '!*.js' -g '*.debug.js' PATTERN     # Excludes *.js apart of *.debug.js.

下面是完整的解决方案来排除*.~*.map*.js,但不是*.debug.js

rg -g '*.*' -g '!*.~' -g '!*.map' -g '!*.js' -g '*.debug.js' "OK"

测试:

$ touch file.~ file.map file.js file.debug.js file.txt file.md
$ rg --files
file.debug.js
file.js
file.map
file.md
file.txt
$ rg -g '*.*' -g '!*.~' -g '!*.map' -g '!*.js' -g '*.debug.js' --files
file.debug.js
file.md
file.txt
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.