如何將 find 找到的文件作為參數傳遞?
首先要切斷瑣碎但不適用的答案:我既不能使用
find
+xargs
技巧也不能使用它的變體(如find
with-exec
),因為每次呼叫我都需要使用很少的這樣的表達式。我會在最後回到這個。現在舉一個更好的例子,讓我們考慮:
$ find -L some/dir -name \*.abc | sort some/dir/1.abc some/dir/2.abc some/dir/a space.abc
我如何將這些作為參數傳遞給
program
?只是這樣做並不能解決問題
$ ./program $(find -L some/dir -name \*.abc | sort)
program
由於獲得以下參數而失敗:[0]: ./program [1]: some/dir/1.abc [2]: some/dir/2.abc [3]: some/dir/a [4]: space.abc
可以看出,帶有空格的路徑被分割並
program
認為它是兩個不同的參數。報價直到它有效
似乎像我這樣的新手使用者,在遇到此類問題時,往往會隨機添加引號,直到它最終起作用 - 只是在這裡它似乎沒有幫助……
"$(…)"
$ ./program "$(find -L some/dir -name \*.abc | sort)" [0]: ./program [1]: some/dir/1.abc some/dir/2.abc some/dir/a space.abc
因為引號防止分詞,所以所有文件都作為單個參數傳遞。
引用單個路徑
一個有前途的方法:
$ ./program $(find -L some/dir -name \*.abc -printf '"%p"\n' | sort) [1]: "some/dir/1.abc" [2]: "some/dir/2.abc" [3]: "some/dir/a [4]: space.abc"
引號在那裡,當然。但它們不再被解釋。它們只是字元串的一部分。所以他們不僅沒有阻止分詞,而且還陷入了爭論!
更改 IFS
然後我試著玩弄
IFS
. 無論如何,我更喜歡find
with-print0
和sort
with-z
- 這樣他們自己就不會在“有線路徑”上遇到問題。那麼為什麼不對null
角色強制分詞並擁有一切呢?$ ./program $(IFS=$'\0' find -L some/dir -name \*.abc -print0 | sort -z) [0]: ./program [1]: some/dir/1.abcsome/dir/2.abcsome/dir/a [2]: space.abc
所以它仍然在空間上分裂,而不是在
null
.我嘗試將
IFS
作業放置在$(…)
(如上所示)和之前./program
。我還嘗試了其他語法,例如\0
,\x0
,\x00
都引用了'
and"
以及有和沒有$
. 這些似乎都沒有任何區別……在這裡我沒有想法。我嘗試了更多的東西,但似乎都遇到了與列出的相同的問題。
我還能做什麼?它完全可行嗎?
當然,我可以
program
接受這些模式並自己進行搜尋。但是,在將其固定為特定語法時,需要做很多雙重工作。(grep
例如,提供文件怎麼樣?)。我也可以
program
接受一個帶有路徑列表的文件。然後我可以輕鬆地將表達式轉儲find
到某個臨時文件並僅提供該文件的路徑。這可以支持直接路徑,因此如果使用者只有一個簡單的路徑,則可以在沒有中間文件的情況下提供它。但這似乎不太好 - 需要創建額外的文件並處理它們,更不用說需要額外的實現了。(不過,從好的方面來說,它可以作為參數的文件數量開始導致命令行長度問題的情況下的救援……)最後,讓我再次提醒您,
find
+xargs
(和類似的)技巧在我的情況下不起作用。為了描述簡單,我只展示一個論點。但我的真實情況看起來更像這樣:$ ABC_FILES=$(find -L some/dir -name \*.abc | sort) $ XYZ_FILES=$(find -L other/dir -name \*.xyz | sort) $ ./program --abc-files $ABC_FILES --xyz-files $XYZ_FILES
因此,
xargs
從一個搜尋中進行搜尋仍然讓我知道如何處理另一個搜尋……
使用數組。
如果您不需要處理文件名中換行符的可能性,那麼您可以逃脫
mapfile -t ABC_FILES < <(find -L some/dir -name \*.abc | sort) mapfile -t XYZ_FILES < <(find -L other/dir -name \*.xyz | sort)
然後
./program --abc-files "${ABC_FILES[@]}" --xyz-files "${XYZ_FILES[@]}"
如果您確實需要處理文件名中的換行符,並且 bash >= 4.4,則可以在數組構造期間使用
-print0
and-d ''
以空值終止名稱:mapfile -td '' ABC_FILES < <(find -L some/dir -name \*.abc -print0 | sort -z)
(同樣適用於
XYZ_FILES
)。如果您沒有較新的 bash,那麼您可以使用以 null 結尾的讀取循環將文件名附加到數組中,例如ABC_FILES=() while IFS= read -rd '' f; do ABC_FILES+=( "$f" ); done < <(find -L some/dir -name \*.abc -print0 | sort -z)