Linux

管道 glob 到 ls

  • February 19, 2022

文件內容filelist

/some/path/*.txt
/other/path/*.dat
/third/path/example.doc

我想列出這些文件,所以我這樣做:

cat filelist | xargs ls

但我沒有擴大這些球體,而是得到:

ls: cannot access '/some/path/*.txt': No such file or directory  
ls: cannot access '/other/path/*.dat': No such file or directory  
/third/path/example.doc

貝殼擴大球體。在這裡,這是非常罕見的情況之一,其中隱式 split+glob 運算符在 zsh 以外的類似 Bourne 的 shell 中不帶引號的命令替換時呼叫可能很有用:

IFS='
' # split on newline only
set +o noglob # make sure globbing is not disabled
ls -ld -- $(cat filelist) # split+glob

zsh中,你會這樣做:

ls -ld -- ${(f)~"$(<filelist)"}

f要在換行符上拆分的參數擴展標誌在哪裡,並~ 請求萬用字元,否則預設情況下不會在參數擴展或命令替換時完成。

請注意,如果匹配文件的列表很大,您可能會遇到Argument list too long錯誤(execve()大多數係統上系統呼叫的限制),xargs否則可以解決此問題。在zsh中,您可以zargs改用:

autoload zargs
zargs --eof= -- ${(f)~"$(<filelist)"} '' ls -ld --

Wherezargs將拆分列表並執行ls多次以避免必要的限制xargs

或者您可以將列表傳遞給內置命令(因此不涉及execve()系統呼叫):

要列印文件列表:

print -rC1 -- ${(f)~"$(<filelist)"}

或者將其提供給xargsNUL 分隔:

print -rNC1 -- ${(f)~"$(<filelist)"} |
 xargs -r0 ls -ld --

請注意,如果任何 glob 無法匹配文件, in zsh,您將收到錯誤消息。如果您希望將這些 glob 擴展為空,您可以將Nglob 限定符添加到 glob(這nullglob在每個 glob 的基礎上啟用):

print -rNC1 -- ${(f)^~"$(<filelist)"}(N) |
 xargs -r0 ls -ld --

添加(N)它還會將所有沒有 glob 運算符的行轉換為 glob,從而允許過濾掉路徑引用且不存在的文件;但是,這意味著您不能在 glob 中使用 glob 限定符,filelist除非您將它們表示為(#q...)並啟用該extendedglob選項。另請注意,由於限定符可以執行任意程式碼,因此filelist文件的內容來自受信任的來源很重要。

在其他類似 Bourne 的 shell 中,包括bash,不匹配的 glob 保持原樣,因此將按字面意思傳遞給ls可能會報告相應文件不存在的錯誤。

bash中,您可以使用該nullglob選項(它從 zsh 複製)並處理沒有任何 glob 特別匹配的情況:

shopt -s nullglob
IFS=$'\n'
set +o noglob
set -- $(<filelist)
(( $# == 0 )) || printf '%s\0' "$@" | xargs -r0 ls -ld --

bash, 沒有任何等價於zsh’ 的 glob 限定符。為了確保沒有 glob 運算符的行(例如 your /third/path/example.doc)被視為 glob 並在它們不對應於實際文件時將其刪除,您可以添加@()到行中(requires extglob)。/但是,這對於以字元結尾的行不起作用。但是,您可以添加@()到最後一個非字元並依賴於始終存在/的事實/

shopt -s nullglob extglob
IFS=$'\n'
set +o noglob
set -- $(LC_ALL=C sed 's|.*[^/]|&@()|' filelist)
(( $# == 0 )) || printf '%s\0' "$@" | xargs -r0 ls -ld --

在任何情況下,請注意支持的 glob 運算符列表隨 shell 變化很大。不過,您在範例中使用的唯一一個 ( *) 應該得到所有人的支持。

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