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

slm*_*slm 8 scripting find shell-script

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

$ find . -iname "*.extension" -exec sh -c '
  exec <command> "$@" <additional parameters>' sh {} +
Run Code Online (Sandbox Code Playgroud)

这里到底发生了什么?具体最后是sh {}做什么的?似乎它只是为了安抚 find 的-exec命令,以便它有事可做,一个 NOOP。

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

Sté*_*las 9

语法是:

find ... -exec cmd {} +
Run Code Online (Sandbox Code Playgroud)

find将根据 in 中的条件查找多个文件,...cmd使用该文件路径列表作为参数运行,在不超过命令参数大小限制的情况下尽可能多地运行。

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

cmd ./file1 ./file2 ... ./file3000
cmd ./file3001 ./file3002 ... ./file4321
Run Code Online (Sandbox Code Playgroud)

一个限制是{}必须是最后。例如你不能写:

find ... -exec cmd {} other args +
Run Code Online (Sandbox Code Playgroud)

就像你可以用';'而不是'+'.

你可以写:

find ... -exec echo foo {} +
Run Code Online (Sandbox Code Playgroud)

但不是:

find ... -exec echo {} foo +
Run Code Online (Sandbox Code Playgroud)

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

In 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 {} +
Run Code Online (Sandbox Code Playgroud)

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

通过使用execshell的特殊内置:

find ... -exec sh -c 'exec cmd "$@" other arg' find-sh {} +
Run Code Online (Sandbox Code Playgroud)

我们告诉 shell 不要派生一个额外的进程来运行cmd,而是在同一个进程中运行它(用该命令替换正在运行的 shell 进程)。一些炮弹一样bashzsh和一些实现ksh做隐含在脚本中的最后一个命令。