假设我想对包含单词 的cmd
所有*.cpp
和文件执行。*.hpp
FOO
就找到这些文件而言,我知道我能做到,
find /path/to/dir -name '*.[hc]pp' -exec grep -l 'FOO' {} +
但是扩展处理以便我可以执行(例如cmd
对每个文件)执行的正确方法是什么?
我知道我可以在 中-exec bash -c '...'
编写“如果文件内容包含,则在文件上FOO
运行cmd
”逻辑...
,但这感觉就像是用大炮射苍蝇。
假设我想对包含单词 的cmd
所有*.cpp
和文件执行。*.hpp
FOO
就找到这些文件而言,我知道我能做到,
find /path/to/dir -name '*.[hc]pp' -exec grep -l 'FOO' {} +
但是扩展处理以便我可以执行(例如cmd
对每个文件)执行的正确方法是什么?
我知道我可以在 中-exec bash -c '...'
编写“如果文件内容包含,则在文件上FOO
运行cmd
”逻辑...
,但这感觉就像是用大炮射苍蝇。
-exec … \;
也是一个测试,只要里面的命令返回退出状态 0,它就成功。-exec … +
可以用一个命令处理许多路径名,并且它总是成功,所以这不是一个有用的测试。grep -q
配合得很好,-exec … \;
因为当存在匹配时(即使检测到错误)它返回退出状态 0,否则返回 1。将您的文件逐个测试,以便您可以添加另一个
-exec grep … +
文件来有条件地运行您所需的命令:-exec grep -q … \;
-exec
一般来说,事实
-exec … \;
是测试允许您构建自定义测试,您可以在其中测试几乎任何内容;特别是因为您可以运行sh -c
并因此使用管道、可以操作的变量、shell 条件等来实现测试(但请注意:可以find -exec sh -c
安全使用吗?)。使用这些实用程序的 GNU 实现(以及支持 ksh 样式的进程替换的 shell),您可以执行以下操作:
上面, with
-r
(又名--recursive
)grep
执行了find
的工作(请注意,在当前版本中grep
,它的行为就像-type f
传递给等效find
命令一样),并将l
NUL 分隔的文件路径列表 (-Z
)xargs
通过管道传递给,管道的路径传递给-a
(又名--arg-file
)。如果您仍然想使用
find
(例如应用比文件名后缀更复杂的文件条件),您可以这样做:(这里
--
不是必需的,因为文件路径将以 开头./
,所以不是-
nor+
)。执行
find ... -exec grep -q FOO {} \; -exec cmd {} +
有效,但意味着分叉一个进程,执行grep
,这涉及到为每个文件加载和链接共享库,这比这里需要做的要昂贵几个数量级grep
(读取几 KiB 的文本并FOO
在其中查找),所以如果性能或资源使用是一个问题,最好尽可能避免。如果您不在 GNU 系统上,但您
find
支持-print0
并xargs
支持下一版本-r
的-0
POSIX 标准,您可以使用以下命令报告文件路径perl
:尽管这假设
cmd
不从其 stdin 读取(此处,根据实现,xargs
将在 /dev/null 上打开或管道的读取端正perl
在写入,继承自xargs
)。1 包括除基于 pdksh 和 zsh 和 bash 之外的 ksh 实现;在类似 rc 的 shell 中将更改为
<(...)
,并在<{...}
(...|psub)
fish