僅查找以 .whl 結尾的文件
我正在嘗試擷取所有
.whl
文件,如下所示ls -l /python/*.{whl,} ls: cannot access /python/*.: No such file or directory -rw-r--r-- 1 root root 23000 Jun 14 11:02 /python/argparse-1.4.0-py2.py3-none-any.whl -rw-r--r-- 1 root root 154423 Jun 14 11:02 /python/certifi-2019.9.11-py2.py3-none-any.whl -rw-r--r-- 1 root root 387834 Jun 14 11:02 /python/cffi-1.14.0-cp27-cp27mu-manylinux1_x86_64.whl -rw-r--r-- 1 root root 133356 Jun 14 11:02 /python/chardet-3.0.4-py2.py3-none-any.whl -rw-r--r-- 1 root root 2728298 Jun 14 11:02 /python/cryptography-2.9.2-cp27-cp27mu-manylinux1_x86_64.whl -rw-r--r-- 1 root root 11223 Jun 14 11:02 /python/enum34-1.1.10-py2-none-any.whl -rw-r--r-- 1 root root 58594 Jun 14 11:02 /python/idna-2.8-py2.py3-none-any.whl -rw-r--r-- 1 root root 18159 Jun 14 11:02 /python/ipaddress-1.0.23-py2.py3-none-any.whl -rw-r--r-- 1 root root 125774 Jun 14 11:02 /python/Jinja2-2.11.2-py2.py3-none-any.whl
但正如你所看到的,我們也得到 -
ls: cannot access /python/*.: No such file or directory
如何解決這個問題,以僅查找以 . 結尾的文件的方式。
whl
如果您只對帶有
whl
副檔名的文件感興趣,ls -l /python/*.whl
是你所追求的。
您目前的命令,
ls -l /python/*.{whl,}
相當於
ls -l /python/*.whl /python/*.
(感謝大括號擴展)並失敗,因為後一種模式與
/python
.
正如@StephenKitt 所說,在 中
bash
,大括號擴展是在萬用字元之前完成的(甚至在包括參數擴展在內的所有其他形式的擴展之前,看看bash
唯一的shell如何echo $P{S1,ATH}
輸出兩者的內容$PS1
)$PATH
,所以,ls -l /python/*.{whl,}
是相同的:
ls -l /python/*.whl /python/*.
並且
bash
具有從 Bourne shell 繼承的錯誤功能,不匹配的 glob 按字面意思傳遞給命令,因此如果沒有/python
名稱以 結尾的非隱藏文件.
,則/python/*.
文件名將被傳遞給ls
並ls
抱怨該文件(是的,*.
是 Unix 中完全有效的文件名)不存在。請注意,failglob
andnullglob
選項會改變這種行為。現在,大括號擴展功能來自 70 年代後期的 csh。你會注意到你沒有在
csh
.
csh
沒有 Bourne shell 的那種錯誤特徵,並且表現得像/etc/glob
早期的 Unices(將他們的名字命名為 glob),因為不匹配的 glob 被刪除(而不是按原樣傳遞),如果所有glob 在命令行不匹配,然後命令被取消(明智的做法,因為顯然有問題)。所以在
csh
:ls -l /python/*.{whl,}
首先擴展為
ls -l /python/*.whl /python/*.
像 in
bash
,但由於/python/*.
不匹配任何文件但/python/*.whl
匹配某些文件,/python/*.
因此被刪除並ls
使用文件列表呼叫.whl
。如果也沒有任何
.whl
文件,則cshNo match
會出錯,而不是關於不存在文件的錯誤。ls
zsh
是另一個從 . 複製大括號擴展的 shellcsh
。不匹配的 glob 的行為是不同的。
zsh
也沒有 Bourne shell 的錯誤功能(至少預設情況下沒有),但是只要任何(與 / 中的所有內容相反)glob無法匹配或即使有文件也不會執行,它就會取消命令,因為glob 不匹配。在中,您可以使用或使用 Bourne 行為來獲取行為(不推薦)。在中,您可以獲得類似於with的行為。csh``/etc/glob``ls -l /python/*.{whl,}``ls -l /python/*.whl /python/*.``ls``.whl``/python/*.``zsh``csh``set -o cshnullglob``set +o nomatch``bash``zsh``shopt -s failglob
shell的
fish
行為是不同的。
fish
(一個更新的 shell)的行為就像zsh
失敗的 glob 取消命令。就像 in 一樣zsh
,你會看到ls -l /python/*.whl /python/*.
不執行
ls
並返回:fish: No matches for wildcard “/python/*.”. See `help expand`. ls -l /python/*.whl /python/*. ^
錯誤。但
ls -l /python/*.{whl,}
不返回錯誤,列出文件並且不傳遞參數以在這種情況下表現如.
.whl``/python/*.``ls``csh
但那是因為即使
{x,y}
嚴格來說也不是那裡的萬用字元,它是與萬用字元一起完成的,並且只有在整個大括號上完成的萬用字元與任何文件都不匹配時,才會取消該命令。您會看到,如果既沒有*.whl
也沒有*.
文件,則錯誤變為:fish: No matches for wildcard “/python/*.{whl,}”. See `help expand`. ls -l /python/*.{whl,} ^
即,這裡將整體
/python/*.{whl,}
視為萬用字元,而不是由大括號擴展產生的任何萬用字元。要列出以
.whl
or結尾的文件.
,我會這樣做:ls -ld /python/*(.|.whl) # zsh ls -ld /python/*.(|whl) # zsh ls -ld /python/*@(.|.whl) # ksh / bash -O extglob ls -ld /python/*.?(whl) # ksh / bash -O extglob
也就是說,在一個glob 中使用一個**glob 運算符,該運算符與兩個 glob 匹配,每種情況一個(除非您希望首先列出文件,但在作為命令的情況下,這與對無論如何都要列出)。
.whl``ls``ls
但是請注意,如果由於 Bourne shell 錯誤功能而沒有與該模式匹配的文件,則
ksh
變體,除非您使用failglob
in ,否則bash
最終會列出一個字面呼叫的文件。*.?(whl)
in
zsh
,如果您想列出*.whl
之前的文件*.
而不將其視為錯誤,如果任一列表為空,如 incsh
/fish
,您可以在cshnullglob
本地使用:(){ set -o localoptions -o cshnullglob; ls -ldU /python/*.{whl,}; }
(這裡假設 GNU
ls
並使用它的-U
選項來禁用它的排序)。或者使用
N
glob 限定符(獲取nullglob
行為)並手動進行錯誤處理(對於 glob 都不匹配的情況):() { if (($#)); then ls -ldU -- "$@" else echo>&2 No match return 1 fi } /python/*.{whl,}
類似的事情可以在 bash 中使用子shell(因為
bash
沒有匿名函式)來限制選項和位置參數的範圍:( shopt -s nullglob shopt -u failglob # failglob takes precedence over nullglob when set! set -- /python/*.{whl,} if (($#)); then ls -ldU -- "$@" else echo>&2 No match exit 1 fi )