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


8

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

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

这到底是怎么回事?具体来说,最后sh {}做什么?似乎只是为了平息find的-exec命令而已,以便它可以做一些事情,即NOOP。

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

Answers:


9

语法为:

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...,所以"$@"这三个参数的列表也是如此: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 {} +

我们告诉外壳程序不要派生额外的进程来运行cmd,而要在同一进程中运行(用该命令替换正在运行的外壳程序进程)。某些外壳程序(如bashzsh和的某些实现对ksh脚本中的最后一条命令隐式执行。


您可以在其中使用subshel​​l而不是exec吗?-exec sh -c '(cmd1; cmd2;)' find-sh {} +
slm

因此,如果我对您的理解正确,那么find-sh {}sh -c'...'命令的参数是对吗?
slm

@slm find将以... $ 0` /bin/sh作为参数,而位置参数(,...您可以说是内联脚本的参数)作为,作为参数调用。("sh", "-c", "...", "find-sh", "./file1", "./file2"...). And inside , that maps (the shells maps that) to "find-sh"$1$2./file1./file2
斯特凡Chazelas
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.