(从ask-ubuntu自行迁移,因为它与linux相关,而不是ubuntu,而且我的操作系统不是ubuntu)
我正在尝试制作一个如下所示的 grep:
grep -r 2019 | grep -riv FAILED | grep -rl DSL
我想获取其中-l
包含的文件的文件名 ( ) ,而不是 ( ) 包含AND 包含.2019
-v
FAILED
DSL
这里只执行最后一个grep。我知道这是因为-r
,所以每个 grep 都会对所有文件进行 grep,而不是之前的结果。但我不知道如何让它在没有-r
.
也许还有另一种方法可以在 grep 上使用多个模式,但对于“正”和“负”匹配,我没有找到任何内容。
答案1
grep
管道中的最后一个将从前一个读取grep
(如果它没有使用该-r
选项,请参阅稍后),因此它不知道从什么文件数据来自,这又意味着它无法报告文件的路径名。
相反,请考虑find
像这样使用:
find . -type f \
-exec grep -q 2019 {} \; \
-exec grep -q DSL {} \; \
! -exec grep -qi FAILED {} \; \
-print
这将从当前目录和任何子目录中获取每个常规文件(递归地)并测试它是否包含字符串2019
, DSL
, 和FAILED
(不区分大小写)。它将打印包含前两个字符串但不包含第三个字符串的文件的路径名。
如果文件不包含2019
则不进行另外两个测试,如果不包含DSL
则不进行最后一个测试,依此类推。
请注意,grep -v -qi FAILED
我没有使用 的否定grep -qi FAILED
作为第三个测试。我对文件是否包含不包含的行不感兴趣FAILED
,我感兴趣的是文件是否包含包含 FAILED
,在这种情况下我想跳过这个文件。
有关的:
你的管道问题,
grep -r 2019 | grep -riv FAILED | grep -rl DSL
是最后一个grep
将递归地查找当前目录及以下目录中的所有文件,并将忽略管道前一阶段的输入。两个初始grep
调用可能会产生一些数据,但它们无法通过管道转发这些数据,并且最终会在最后一个调用grep
完成时被杀死。
另外,正如我上面已经指出的,中间grep
不会找到不包含 的文件FAILED
,它会找到包含除FAILED
。顺便说一句,它会还忽略前面的输入grep
。
答案2
与 GNU grep
(-r
已经是 GNU 扩展)和 GNUxargs
或兼容:
grep -rlZ 2019 . |
xargs -r0 grep -LiZ FAILED |
xargs -r0 grep -l DSL
您需要xargs
能够传递文件列表输出由一grep
作为论点到下一个grep
。并且-Z
该文件列表以 NUL 分隔。要报告不包含 FAILED 的文件列表,它-L
(也是 GNU 扩展),而不是-vl
报告包含至少一行不匹配的文件。
这应该将调用次数限制grep
在最低限度,并且对于大量文件,可以同时利用最多三个处理器。