Shell

為什麼 nullglob 不是預設值?

  • April 8, 2022

在大多數 shellnullglob中不是預設設置。這意味著,例如,如果您執行此命令

ls *

在一個空目錄中,它會將*glob 擴展為一個文字*,而不是一個空的參數列表。有一些方法可以改變這種行為,這樣*在一個空目錄中將返回一個空的參數列表,這看起來更直覺。

nullglob那麼,預設情況下禁用是否有原因?如果是這樣,那是什麼原因?

nullglob選項(順便說一句,這是一項zsh發明,幾年後才添加到bash2.0)中)在許多情況下並不理想。並且ls是一個很好的例子:

ls *.txt

或更正確的等價物:

ls -- *.txt

(列出名稱以 結尾的非隱藏目錄的內容.txt,或具有相同名稱模式的非目錄文件)

nullglob如果沒有文件匹配, on 將不帶任何參數執行,如果沒有文件匹配,則將ls其視為ls -- .(列出目前目錄),這可能比ls使用文字*.txt作為參數呼叫更糟糕¹。

大多數文本實用程序都會遇到類似的問題:

grep foo *.txt

foo如果沒有txt文件,將在標準輸入上查找。

如果 glob 不匹配,一個更明智的預設設置,以及 csh、tcsh、zsh 或 fish 2.3+(以及早期的 Unix shell)之一是完全取消命令。

bash(從版本 3 開始)有一個failglob選項(這個討論很有趣,因為與AT ash&T ksh或不支持 options² 的本地範圍相反,該選項在全域啟用時會破壞一些事情,比如 bash 完成功能)。zsh``bash

請注意, csh 和 tcsh 與 略有不同zshfish或者bash -O failglob在以下情況下:

ls -- *.txt *.html

您需要所有 glob 不匹配才能取消命令。例如,如果有一個 txt 文件而沒有 html 文件,則變為:

ls -- file.txt

您可以通過以下方式獲得該行為,zsh儘管set -o cshnullglob更明智的方法zsh是使用如下的 glob:

ls -- *.(txt|html)

zshandksh93中,您還可以在每個 glob 的基礎上應用nullglob,這比修改全域設置要明智得多:

files=(*.txt(N))  # zsh
files=(~(N)*.txt) # ksh93

如果沒有txt文件,則將創建一個空數組,而不是使命令失敗並出現錯誤(或使其成為*.txt具有其他 shell 的一個文字參數的數組)。

fish2.3 之前的版本可以正常工作,bash -O nullglob但是當 glob 不匹配時互動時會發出警告。從 2.3 開始,它zsh的工作方式與for,setcount.

現在,在歷史記錄中,行為實際上被 Bourne shell*破壞了。*在早期版本的 Unix 中,萬用字元是通過/etc/glob幫助程序完成的,該幫助程序的行為類似於csh:如果沒有任何 glob 匹配任何文件,它將使命令失敗,否則將刪除不匹配的 glob。

所以我們今天的情況是由於在 Bourne shell 中做出了一個錯誤的決定。

請注意,Bourne shell(和 C shell)帶有另一個新的 Unix 特性:環境。這意味著變數擴展(它的前身只有$1, $2… 位置參數)。Bourne shell 還引入了命令替換。

Bourne shell 的另一個糟糕的設計決策是在變數擴展和命令替換時執行通配(和拆分)(可能是為了與 Thompson shell 向後兼容,如果包含萬用字元echo $1仍會呼叫它(它更像是預處理器宏擴展)在那裡,就像在擴展的值被再次解析為 shell 程式碼一樣))。/etc/glob``$1

不匹配的失敗 glob 意味著例如:

pattern='a.*b'
grep $pattern file

將使命令失敗(除非目前目錄中有一些a.whateverb文件)。csh(它也會在變數擴展時執行 globbing)在這種情況下確實會使命令失敗(我認為這比在那裡留下一個休眠的 bug 更好,即使它不像 in rc/ zsh/ fish… )。


¹ls可能會報告*.txt文件不存在的錯誤,除非它是在間隔中創建的,或者目前目錄恰好可搜尋但不可讀並且該文件或目錄存在。mkdir -p '*.txt/wtf'; chmod a=,u=wx .例如嘗試之後

² 4.4 版在這方面進行了一些改進,因為set -o可以將設置的選項設置為在 Almquist shell 中類似的函式的本地local -,但這不適用於bash設置的第二組選項shopt

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