Answers:
grep -l string2 `grep -l string1 /path/*`
这与
grep -l string2 $(grep -l string1 /path/*)
编辑:这就是为什么grep string1 /path/* | grep string2不做我认为alwbtc想要的事情。
$ cd /tmp
$ cat a
apples
oranges
bananas
$ cat b
apples
mangoes
lemons
$ cat c
mangoes
limes
pears
$ cd ~
$ grep apples /tmp/* | grep mangoes
$
找不到任何内容,但文件b包含两个字符串。
这就是我认为alwbtc想要的
$ grep -l apples $(grep -l mangoes /tmp/*)
/tmp/b
-l将两个命令视为相等的选项。
用管道grep输送到另一个管道:
grep "string1" /path/to/files/* | grep "string2"
这是等效的 确认命令RedGrittyBrick的答案:
ack string2 $(ack string1 -l)
以相同的方式工作(ack默认情况下,递归搜索当前目录除外)。$()搜索中的内容仅搜索找到该字符串的文件名,string1但-l仅输出。然后将它们作为参数传递给外部命令,这意味着string2仅在这些文件列表中搜索。
comm -12 <(grep --fixed-strings --files-with-matches "STRING1" /path/to/files/* 2>/dev/null | sort) <(grep --fixed-strings --files-with-matches "STRING1" /path/to/files/* 2>/dev/null | sort)
或更少的冗余:
search_files () { str="$1"; shift; grep -Fl "$str" "$@" 2>/dev/null | sort; }
comm -12 <(search_files "STRING1" /path/to/files/*) <(sf "STRING2" /path/to/files/*)
如果字符串在同一文件的不同行上,则将起作用;如果文件名包含字符串之一,则也将避免误报。
要详细说明@RedGrittyBrick的解决方案,该解决方案在运行无人值守命令时存在一个缺点,并且可以按预期抑制错误输出并以递归方式查找文件
grep -l 'STRING1' $(! grep -lrs 'STRING2' /absolute/path/to/search/dir && echo /dev/null)
-s选项将禁止显示错误消息
-r选项允许在任意嵌套的目录中搜索字符串,
!并&& echo /dev/null保证命令不会挂断。否则,如果inner grep找不到任何文件,它将不会输出任何内容,因此outer grep将会无限期等待搜索输入。/dev/null在这种情况下,此解决方案将输出,因此outer grep将STRING1在/dev/null应该找不到任何内容的位置进行搜索。
我一直在寻找一种可扩展的方式来处理2个或更多字符串,并提出了以下建议:
grep -rl string1 path-to-files | xargs grep -l string2 | xargs grep -l string3
第一个grep递归地查找包含string1在中的文件的名称path-to-files。
结果通过管道传输到xargs,以便在的那些文件上运行一个或多个grep命令string2。
然后将结果通过管道传递到另一个xargs命令中string3-与第一个xargs调用相同,只是在寻找不同的字符串。
使用xargs将会避免出现太多结果的问题,以至于使用反引号引起的命令行太长。
为了避免警告,我们可以重定向stderr到/dev/null:
grep -rl string1 path-to-files 2>/dev/null | xargs grep -l string2
后续的grep调用不需要它,因为string1已经在文件中找到了,因此已知权限是好的。
-l选项来返回文件名而不是行。然后,他使用美元符号或反引号将该列表作为FILE参数传递给第二个grep。这使第二个grep可以搜索找到的每个文件的整体,而不是像我的解决方案那样搜索单独的行。