命令`grep -Ilri foo 。 | xargs grep -i bar` 仅当生成的路径没有空格时才有效

命令`grep -Ilri foo 。 | xargs grep -i bar` 仅当生成的路径没有空格时才有效

要查找所有包含该单词的文件foo以及其中包含该单词的文件bar,我们可以使用

grep -Ilri foo . | xargs grep -i bar

(不区分大小写并排除二进制文件)...但是,如果文件路径类似于

/Users/myusername/Text Files

那么它就不起作用了,因为现在该xargs部分变成了

grep -i bar /Users/myusername/Text Files

但实际上它需要是

grep -i bar "/Users/myusername/Text Files"

或者

grep -i bar /Users/myusername/Text\ Files

如何让它发挥作用? (在 macOS Monterey 上)。

答案1

如果您grep支持 GNU 的-Z/--null选项以空字节分隔文件名(FreeBSD 仅支持长--null变体),并且您xargs支持使用空字节作为输入项分隔符的-0选项(也有一些),您可以使用它们来处理文件名--null安全地:

grep -Ilri --null foo . | xargs -0 grep -i bar

如果您的grepxargs不支持这些非标准选项(但话又说回来,两者都不-r-I标准的),您可以使用find

find . -type f -exec grep -Iiq foo {} \; -exec grep -iq bar {} \; -print

它查找从当前目录开始的文件,对于它找到的每个文件,运行grep以确定它是否包含“foo”,如果包含,则grep再次运行以确定它是否包含“bar”,如果包含,则打印其姓名。

这效率不高,但可以安全地工作。

答案2

要在任何 Unix 机器上使用强制 POSIX 工具“查找其中包含该单词的所有文件foo以及其中的单词”(未经测试):bar

find . -type f -exec \
    awk '
        FNR==1 { x=y=0 }
        { $0 = tolower($0) }
        /foo/ { x=1 }
        /bar/ { y=1 }
        x && y { hits[FILENAME]; nextfile }
        END { for (fname in hits) print fname }
    ' {} +

或者如果您愿意:

find . -type f -exec \
    awk '
        FNR==1 { x=y=0 }
        { $0 = tolower($0) }
        /foo/ { x=1 }
        /bar/ { y=1 }
        x && y && !seen[FILENAME]++ { print FILENAME; nextfile }
    ' {} +

在上面的两种情况下,我们使用nextfile支持它的 awks 来提高效率,但也编写代码以确保即使在不支持它的 awks 中,我们也不会多次打印相同的文件名。

上面假设您不关心子字符串或正则表达式与字符串匹配的匹配。

相关内容