Bash

使用生成的文件名列表作為參數列表——帶空格

  • May 22, 2015

我正在嘗試使用由收集的文件名列表呼叫腳本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 拆分的輸入-print0xargs -0這種非標準語法是由 GNU 引入的findxargs但現在也可以在其他一些語法中找到,例如最近的 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

引用自:https://unix.stackexchange.com/questions/110068