使用“find ... -exec sh -c '...' sh {} +”的 find 命令如何工作?

使用“find ... -exec sh -c '...' sh {} +”的 find 命令如何工作?

@StephaneChazelas 对此问答发布了以下解决方案:使用“find -exec {} +”时遇到一些问题

$ find . -iname "*.extension" -exec sh -c '
  exec <command> "$@" <additional parameters>' sh {} +

这里究竟发生了什么?最后一个具体是sh {}做什么的呢?看起来它只是为了安抚 find 的-exec命令,以便它有事情可做,一个 NOOP。

我可以很容易地放在echo {}那里,它看起来工作得很好。

答案1

语法是:

find ... -exec cmd {} +

find将根据中的条件找到许多文件,...cmd使用该文件路径列表作为参数运行,尽可能多,而不超过命令参数大小的限制。

如果需要,它可能会拆分文件列表并调用cmd多次。例如,它最终可能会调用:

cmd ./file1 ./file2 ... ./file3000
cmd ./file3001 ./file3002 ... ./file4321

这样做的一个限制是它{}必须是最后一个。例如,你不能写:

find ... -exec cmd {} other args +

就像你可以用';'代替'+'.

你可以写:

find ... -exec echo foo {} +

但不是:

find ... -exec echo {} foo +

因此,如果您确实需要在文件列表后面添加一些额外的参数cmd,则必须求助于调用 shell。 (您需要调用 shell 的其他原因是任何时候您需要使用 shell 功能,如重定向、管道、一些字符串扩展......)

在 中sh -c 'inline-script' x a b c,对于inline-script$0is x$1is a$2is b..."$@"这 3 个参数的列表也是如此:a、b 和 c。所以在:

find ... -exec sh -c 'cmd "$@" other arg' find-sh {} +

为了内联脚本$0(例如在显示错误消息时使用)设置为 ,find-sh并且"$@"是文件列表(find扩展{}为的内容)。

通过使用execshell 的特殊内置函数:

find ... -exec sh -c 'exec cmd "$@" other arg' find-sh {} +

我们告诉 shell 不要 fork 一个额外的进程来运行cmd,而是在同一个进程中运行它(用该命令替换正在运行的 shell 进程)。一些 shellzsh和 的一些实现ksh会隐式地对内联脚本中的最后一个命令执行此操作(bash当内联脚本中只有一个命令时也是如此)。

相关内容