使用生成的文件名列表作為參數列表——帶空格
我正在嘗試使用由收集的文件名列表呼叫腳本
find
。沒什麼特別的,就是這樣:$ myscript `find . -name something.txt`
問題是某些路徑名包含空格,因此它們在參數擴展時被分解為兩個無效名稱。通常我會用引號將名稱括起來,但在這裡它們是通過反引號擴展插入的。我已經嘗試過濾
find
每個文件名的輸出並用引號括起來,但是當 bash 看到它們時,剝離它們為時已晚,它們被視為文件名的一部分:$ myscript `find . -name something.txt | sed 's/.*/"&"/'` No such file or directory: '"./somedir/something.txt"'
是的,這就是如何處理命令行的規則,但我該如何解決呢?
這很尷尬,但我沒有想出正確的方法。我終於想出瞭如何使用
xargs -0 -n 10000
…但是它是如此醜陋的hack,我仍然想問:我如何引用反引號擴展的結果,或者以另一種方式達到相同的效果?編輯:我對將所有參數收集到單個參數列表
xargs
中的事實感到困惑,除非另有說明或可能超出系統限制。感謝大家讓我直截了當!其他人,在閱讀接受的答案時請記住這一點,因為它沒有被直接指出。我已經接受了答案,但我的問題仍然存在:是否有某種方法可以保護反引號(或
$(...)
)擴展中的空間?(請注意,接受的解決方案是非 bash 答案)。
您可以使用一些類似的實現來執行以下
find
操作xargs
。$ find . -type f -print0 | xargs -r0 ./myscript
或者,標準地,只是
find
:$ find . -type f -exec ./myscript {} +
例子
假設我有以下範例目錄。
$ tree . |-- dir1 | `-- a\ file1.txt |-- dir2 | `-- a\ file2.txt |-- dir3 | `-- a\ file3.txt `-- myscript 3 directories, 4 files
現在假設我有這個
./myscript
。#!/bin/bash for i in "$@"; do echo "file: $i" done
現在當我執行以下命令時。
$ find . -type f -print0 | xargs -r0 ./myscript file: ./dir2/a file2.txt file: ./dir3/a file3.txt file: ./dir1/a file1.txt file: ./myscript
或者當我像這樣使用第二種形式時:
$ find . -type f -exec ./myscript {} + file: ./dir2/a file2.txt file: ./dir3/a file3.txt file: ./dir1/a file1.txt file: ./myscript
細節
查找 + xargs
以上兩種方法雖然看起來不同,但本質上是相同的。第一個是從 find 中獲取輸出,通過switch使用 NULL (
\0
)將其拆分為 find。專門設計用於獲取使用 NULL 拆分的輸入-print0
。xargs -0
這種非標準語法是由 GNU 引入的find
,xargs
但現在也可以在其他一些語法中找到,例如最近的 BSD。如果在 GNU 中沒有找到任何東西,但在 BSD中沒有找到,則需要該-r
選項來避免呼叫。myscript``find``find
**注意:**整個方法取決於您永遠不會傳遞過長的字元串這一事實。如果是,則第二次呼叫
./myscript
將與 find 的其餘後續結果一起開始。用 + 查找
這是標準方式(儘管它只是在最近(2005 年)添加到 GNU 實現中
find
)。做我們正在做的事情的能力xargs
實際上是內置於find
. 所以find
將找到一個文件列表,然後將該列表傳遞給後面指定的命令-exec
(注意,在這種情況下{}
只能是最後一個+
),如果需要,多次執行命令。為什麼不引用?
在第一個範例中,我們通過使用 NULL 分隔參數來完全避免引用問題,從而走捷徑。當
xargs
給出這個列表時,它被指示在 NULL 上進行拆分,從而有效地保護我們的單個命令原子。在第二個範例中,我們將結果保存在內部
find
,因此它知道每個文件原子是什麼,並保證適當地處理它們,從而避免引用它們的麻煩事。命令行的最大大小?
這個問題不時出現,因此我將其添加到此答案中,主要是為了將來可以找到它。您可以使用
xargs
以下方式查看環境的限制:$ xargs --show-limits Your environment variables take up 4791 bytes POSIX upper limit on argument length (this system): 2090313 POSIX smallest allowable upper limit on argument length (all systems): 4096 Maximum length of command we could actually use: 2085522 Size of command buffer we are actually using: 131072