如何在find命令的exec参数中使用管道符?

82

我正在尝试构建一个find命令,以使用两个不同的可执行文件处理目录中的一堆文件。不幸的是,在find上使用-exec不能使用pipe或者\|,因为shell首先解释该字符。

以下是我正在尝试但无法实现的具体操作(由于管道终止了find命令):

find /path/to/jpgs -type f -exec jhead -v {} | grep 123 \; -print
6个回答

90

试试这个

find /path/to/jpgs -type f -exec sh -c 'jhead -v {} | grep 123' \; -print

或者您可以尝试将执行语句嵌入sh脚本中,然后执行:

sh script.sh

find -exec some_script {} \;

15

稍微不同的方法是使用xargs:

find /path/to/jpgs -type f -print0 | xargs -0 jhead -v | grep 123

我发现使用-print0和-0参数可以应对包含空格的文件名,这使得我更容易理解和适应。

这种方法(未经测试)可能比使用-exec更有效,因为它将文件列表传输到xargs并确保jhead命令行不会太长。


4
在这里使用xargs的问题在于我需要匹配的文件名。该命令确实可以找到匹配项,但我不知道是哪个文件匹配的。 - hoyhoy

4

使用 -exec 只能运行一个带有一些参数的可执行文件,而不能运行任意 shell 命令。为了规避这个问题,您可以使用 sh -c '<shell command>'

请注意,使用 -exec 是相当低效的。对于找到的每个文件,都必须再次执行命令。如果您可以避免这种情况,将会更加高效。(例如,通过将 grep 移到 -exec 之外或将 find 的结果传递给 xargs,如 Palmin 所建议的那样。)


1
避免一般情况下的多进程低效的另一种方法是使用xargs。如果您需要单独的进程,可以使用-i选项。我发现xargs更符合Unix模型。 - Jon Ericson
1
AOL关于xargs的使用。mweerden,也许你应该考虑到xargs的存在来修改你的最后一段话。还要注意findxargs中都存在的-0标志。 - tzot

3

对于这种任务,使用find命令可能不是最佳选择。我经常使用以下命令来查找包含所需信息的文件:

for i in dist/*.jar; do echo ">> $i"; jar -tf "$i" | grep BeanException; done

1

由于这个输出是一个列表,你不会:

find /path/to/jpgs -type f -exec jhead -v {} \; | grep 123

或者

find /path/to/jpgs -type f -print -exec jhead -v {} \; | grep 123

将你的grep放在find -exec的结果上。

那样不行,因为我需要-print工作。如果grep返回成功,则find打印文件名,否则不会。 - hoyhoy

0

还有一种方法可以实现,但也相当“ghetto”。

使用shell选项extquote,您可以执行类似于这样的操作,以便使find exec stuff然后将其管道传输到sh。

root@ifrit findtest # find -type f -exec echo ls $"|" cat \;|sh
filename


root@ifrit findtest # find -type f -exec echo ls $"|" cat $"|" xargs cat\;|sh
h

我只是想添加这个,因为至少在我设想中,它更接近于原帖中有关在exec内部使用管道的问题。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接