Bash

如何雙引號文件的萬用字元模式?

  • August 27, 2020

我已經看到了一堆與此類似的問題,但沒有一個完全相同。

我有一個文件目錄,我想使用萬用字元擴展將其作為單個雙引號參數傳遞給命令。

文件

a.ext
b.ext
c.ext

預期用途

command --flag "a.ext b.ext c.ext"

目前,我正在使用command --flag $(echo \"$(echo ./*.ext)\"),但這不起作用,而且看起來也不必要地複雜。有沒有一種簡單的方法可以做到這一點?

如果您想使用 SPC 字元連接 glob 擴展產生的文件名,您可以將它們儲存在位置參數中並用於"$*"執行連接:

set -- ./*.ext
IFS=' ' # SPC is the first character of $IFS by default, we're setting it
       # here in case that code is called in a context where it has been
       # modified before.
files_joined_with_SPC="$*"
cmd --flag "$files_joined_with_SPC"

或者:

cmd --flag "$*"

當然直接(儘管它更容易忘記它取決於 的目前值這一事實$IFS)。

以上是標準的 POSIXsh語法。在zsh/ ksh93/ bash/ mksh/yash中,您還可以使用數組代替位置參數:

files=(./*.ext)
IFS=' '; files_joined_with_SPC="${files[*]}"

使用zsh,您還可以使用:

files=(./*.ext)
cmd --flag "${(j[ ])files}"

或使用匿名函式:

(){ cmd --flag "${(j[ ])argv}"; } ./*.ext

我們明確地請求j使用 SPC 進行操作,而不必依賴像$IFS.

現在,請注意 SPC 與文件路徑中的任何字元一樣有效。除了 NUL 之外的任何字元在文件路徑中都是有效的(實際上在大多數係統上除了 0 之外的任何字節值,這些字節甚至不必形成有效字元),但是 NUL 不能作為參數傳遞給執行的命令

你沒有說那*command*是什麼(順便說一下是command標準 shell 內置命令的名稱,我更喜歡使用cmd佔位符),但如果那cmd --flag list是為了接受任何文件名列表,SPC 分隔,它們必須有一種讓使用者SPC在文件名中指定 a 的方法。

那可能是cmd --flag 'with\ space.ext other.ext'or cmd --flag 'with%20space.ext other.ext, cmd --flag 'with\040space.ext other.ext', 等等。

在這種情況下,在為 建構該參數時cmd --flag,您可能必須先轉義文件名中的該 SPC(可能還有\字元%),然後再將它們與 SPC 連接。

ksh93// zsh/bashyash,可以這樣做:

escaped_files=("${files[@]//\\/\\\\}") # \ escaped as \\
escaped_files=("{files[@]// /\\ }")    # SPC escaped as \SPC
# more characters may need to be escaped such as other whitespace
# or quoting characters, depending on the exact syntax expected by
# cmd for the --flag option.

IFS=' '; escaped_files_joined_with_SPC="$*"
cmd -- flag "$escaped_files_joined_with_SPC"

(儘管要注意使用字元編碼的語言環境,例如 GB18030、BIG5 ……其中某些字元包含反斜杠的編碼(字節 0x5c)。您的外殼可能不會轉義那些 0x5c 字節,但cmd --flag如果不解碼,仍可能將它們視為反斜杠根據語言環境的字元集的參數)。

命令獲取文件名列表的更可靠/方便的方法是將它們作為單獨的參數(而不是作為選項的參數),或者作為cmd --flag 'file 1.ext' --flag 'file 2.ext'....

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