@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
、$0
is x
、$1
is a
、$2
is b
..."$@"
這 3 個參數的列表也是如此:a、b 和 c。所以在:
find ... -exec sh -c 'cmd "$@" other arg' find-sh {} +
為了內嵌腳本,$0
(例如在顯示錯誤訊息時使用)設為 ,find-sh
並且"$@"
是檔案清單(find
擴展{}
為的內容)。
透過使用exec
shell 的特殊內建函數:
find ... -exec sh -c 'exec cmd "$@" other arg' find-sh {} +
我們告訴 shell 不要 fork 一個額外的進程來運行cmd
,而是在同一個進程中運行它(用該命令替換正在運行的 shell 進程)。一些 shellzsh
和 的一些實作ksh
會隱式地對內聯腳本中的最後一個命令執行此操作(bash
當內聯腳本中只有一個命令時也是如此)。