Bash

僅查找以 .whl 結尾的文件

  • June 24, 2020

我正在嘗試擷取所有.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/*.文件名將被傳遞給lsls抱怨該文件(是的,*.是 Unix 中完全有效的文件名)不存在。請注意,failglobandnullglob選項會改變這種行為。

現在,大括號擴展功能來自 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是另一個從 . 複製大括號擴展的 shell csh。不匹配的 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,}視為萬用字元,而不是由大括號擴展產生的任何萬用字元。

要列出以.whlor結尾的文件.,我會這樣做:

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變體,除非您使用failglobin ,否則bash最終會列出一個字面呼叫的文件。*.?(whl)

in zsh,如果您想列出*.whl之前的文件*.而不將其視為錯誤,如果任一列表為空,如 in csh/ fish,您可以在cshnullglob本地使用:

(){ set -o localoptions -o cshnullglob; ls -ldU /python/*.{whl,}; }

(這裡假設 GNUls並使用它的-U選項來禁用它的排序)。

或者使用Nglob 限定符(獲取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
)

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