在大多数shell nullglob中不是默认值。这意味着,例如,如果您运行此命令
ls *
在一个空目录中,它将把*glob 扩展为一个literal *,而不是一个空的参数列表。有多种方法可以更改该行为,以便*在一个空目录中返回一个空参数列表,这似乎更直观。
那么,是否有nullglob默认原因默认禁用的原因?如果是这样,那是什么原因?
*是一个问题,并会扩展到所有现有文件。在空目录glob被“扩展”为文字的情况下,有什么特殊的情况如何“直观” *?
在大多数shell nullglob中不是默认值。这意味着,例如,如果您运行此命令
ls *
在一个空目录中,它将把*glob 扩展为一个literal *,而不是一个空的参数列表。有多种方法可以更改该行为,以便*在一个空目录中返回一个空参数列表,这似乎更直观。
那么,是否有nullglob默认原因默认禁用的原因?如果是这样,那是什么原因?
*是一个问题,并会扩展到所有现有文件。在空目录glob被“扩展”为文字的情况下,有什么特殊的情况如何“直观” *?
Answers:
在很多情况下,该nullglob选项(BTW是一项zsh发明,仅在bash(2.0)之后增加了几年)并不理想。这ls是一个很好的例子:
ls *.txt
或更正确的等价形式:
ls -- *.txt
随着nullglob上可以运行ls不带参数,它是为处理ls -- .(列出当前目录),如果没有文件匹配,这可能比打电话更差ls与文字*.txt作为参数。
大多数文本实用程序都存在类似的问题:
grep foo *.txt
foo如果没有txt文件,将在stdin上查找。
更明智的默认设置是csh,tcsh,zsh或fish 2.3+(以及早期Unix shell)之一,如果glob不匹配,则完全取消该命令。
bash(自版本3起)有一个failglob选项(此讨论很有趣,因为与ashAT&T ksh或相反zsh,bash它不支持选项的本地范围(尽管将在4.4中进行更改),该选项在全局启用后确实会破坏一些功能例如bash补全功能)。
需要注意的是CSH和tcsh从略有不同zsh,fish或bash -O failglob在类似的情况:
ls -- *.txt *.html
您需要所有glob都不匹配的地方才能取消命令。例如,如果只有一个txt文件而没有html文件,则该文件将变为:
ls -- file.txt
你可以得到与行为zsh具有setopt cshnullglob虽然是更明智的方式做到这一点的zsh是使用一个像水珠:
ls -- *.(txt|html)
在zsh和中ksh93,您还可以基于每个glob 来应用nullglob,这比修改全局设置要聪明得多:
files=(*.txt(N)) # zsh
files=(~(N)*.txt) # ksh93
如果没有txt文件,则会创建一个空数组,而不是使命令失败并返回错误(或使其成为具有一个*.txt带有其他Shell的文字参数的数组)。
fish2.3之前的版本可以像这样工作,bash -O nullglob但在全局不匹配时进行交互时会发出警告。从2.3开始,它的工作方式与,或中zsh使用的glob相同。forsetcount
现在,根据历史记录,该行为实际上被 Bourne外壳破坏了。在Unix的早期版本中,通配符是通过/etc/glob辅助程序完成的,并且该辅助程序的行为类似于csh:如果所有通配符都不匹配任何文件,则该命令将失败,否则将不匹配的通配符删除。
因此,我们今天的情况是由于Bourne Shell中的错误决定所致。
请注意,Bourne shell(和C shell)带有Unix的另一个新功能:环境。这意味着变量扩展(它的前身只用了$1,$2...位置参数)。Bourne shell还引入了命令替换。
Bourne shell的另一个糟糕的设计决策是在变量扩展和命令替换时执行globing(和拆分)(可能是为了与Thompson shell向后兼容,如果包含通配符,Thompson shell echo $1仍将调用它(更像是预处理器宏扩展)在那里,因为再次将扩展值解析为shell代码))。/etc/glob$1
不匹配的glob失败意味着例如:
pattern='a.*b'
grep $pattern file
将使命令失败(除非a.whateverb当前目录中有一些文件)。csh(它还会在变量扩展时执行globing)在这种情况下确实会使命令失败(而且我认为它比在其中保留休眠的bug更好,即使它不像in中那样根本不进行globing也是如此zsh)。
nullglob似乎会中断制表符的完成(启用后按Tab键不会执行任何操作)。
files=$(shopt -s nullglob;echo *.txt)
xpg_echo)存储到标量变量中。您需要readarray -td '' files < <(shopt -s nullglob; printf '%s\0' *.txt)使用bash4.4或更高版本或(shopt -s nullglob; printf '%s\0' *.txt) | xargs -r0 cmdGNU之类xargs的东西,才能完全使用任意文件名。或者,仍然使用bash4.4,使用帮助程序功能local -(从25年后的ash中复制)用于选项的本地范围。