我有一个名为的程序foo
,我想对通过 find 找到的每个结果执行该程序。所以像这样:
find . -name '*.o' -type f -exec foo {} \;
foo
我想 grep某个字符串 bar的所有这些调用的输出。所以我添加这个:
find . -name '*.o' -type f -exec foo {} \; | grep bar
但我丢失了有关匹配项来自哪些文件的原始信息。我尝试添加-fprintf /dev/stderr '%p\n'
到find
命令中,但现在看起来标准输出消失了,因为没有打印 grep 结果。
如何将每个文件名打印到输出,然后打印与该文件相对应的 grep 结果?
或者,如果有某种方法可以使工作-H
论证grep
也很好,但正如所写的那样,它不起作用,因为我只是从标准输入传递文本,并且grep
不知道文件名。我尝试了各种咒语xargs
,但也没有任何效果。
答案1
要将每个文件名打印到输出,然后打印与该文件相对应的 grep 结果,您可以将-exec foo {} | grep
管道包装在 shell 中:
find . -name '*.o' -type f -print -exec sh -c 'foo "$1" | grep "bar"' sh {} \;
要使-H
grep 的参数与标准输入一起工作,如果您的版本grep
支持--label=
您可以执行的选项
find . -name '*.o' -type f -exec sh -c '
foo "$1" | grep -H --label="$1" "bar"
' sh {} \;
或者(如果您的发现支持+
多参数替代\;
):
find . -name '*.o' -type f -exec sh -c '
for f; do foo "$f" | grep -H --label="$f" "bar"; done
' sh {} +
答案2
如何将每个文件名打印到输出,然后打印与该文件相对应的 grep 结果?
1.)使用两个 grep 实例,一个用于打印文件名,另一个用于打印匹配项:
find . -name '*.o' -type f -exec grep -l bar {} \; -exec grep bar {} \;
2.)使 grep 的行为就像是多个文件一样:
find . -name '*.o' -type f -exec grep bar {} /dev/null \;
这并不能解决[..]-exec foo {} \;[...]
在管道内运行 grep 的问题,如您的示例所示。
答案3
这很丑陋,但它会对你有用:
find . -name '*.o' -type f -exec sh -c 'foo "$1" | sed "s@^@$1\t@"' _ {} \;
这会将文件名和制表符放在每行的开头。裸下划线是一个填充$0
在生成的 shell 中的字符串,文件名保留为$1
.现在您可以 grep find 的输出,文件名将出现在输出中。
对于任何包含该字符的文件名,这都会中断@
。如果这是一个问题,我们可以增强 shell 脚本:
find . -name '*.o' -type f -exec sh -c '
r=$(echo "$1" | sed "s/@/\\\\\\\\@/g")
foo "$1" | sed "s@^@$r\t@"
' _ {} \;
8个反斜杠是通过反复试验确定的......
或者使用 bash(或 ksh),它具有方便的“搜索和替换”参数替换
find . -name '*.o' -type f -exec ksh -c 'foo "$1" | sed "s@^@${1//@/\\\\@}\t@"' _ {} \;