在大多数 shellnullglob中不是默认的。这意味着,例如,如果您运行此命令
ls *
Run Code Online (Sandbox Code Playgroud)
在一个空目录中,它会将*glob扩展为一个 literal *,而不是一个空的参数列表。有一些方法可以改变这种行为,这样*在一个空目录中将返回一个空的参数列表,这看起来更直观。
那么,是否有理由nullglob默认禁用?如果是,那是什么原因?
Sté*_*las 93
该nullglob选项(顺便说一句zsh,这是一项发明,仅在几年后才添加到bash( 2.0) 中)在许多情况下并不理想。这ls是一个很好的例子:
ls *.txt
Run Code Online (Sandbox Code Playgroud)
或者更正确的等价物:
ls -- *.txt
Run Code Online (Sandbox Code Playgroud)
(列出名称以 结尾的非隐藏目录的内容.txt,或具有相同名称模式的非目录文件)
随着nullglob上可以运行ls不带参数,它被视为ls -- .(列表中的当前目录),如果没有文件匹配,这可能比打电话更差ls与文字*.txt为argument¹。
大多数文本实用程序都会遇到类似的问题:
grep foo *.txt
Run Code Online (Sandbox Code Playgroud)
foo如果没有txt文件,将在 stdin 上查找。
一个更明智的默认设置,csh、tcsh、zsh 或fish 2.3+(以及早期的 Unix shell)之一是在 glob 不匹配时完全取消命令。
bash(从版本 3 开始)有一个failglob选项(这个讨论很有趣,因为与ash、AT&T ksh或相反zsh,bash不支持选项² 的本地范围,该选项在全局启用时确实会破坏一些东西,例如 bash 完成功能)。
请注意, csh 和 tcsh 与 略有不同zsh,fish或者bash -O failglob在以下情况下:
ls -- *.txt *.html
Run Code Online (Sandbox Code Playgroud)
您需要所有 glob 不匹配才能取消命令。例如,如果有一个 txt 文件而没有 html 文件,则变为:
ls -- file.txt
Run Code Online (Sandbox Code Playgroud)
您可以zsh使用以下setopt cshnullglob方法来实现该行为,但更明智的方法zsh是使用如下 glob:
ls -- *.(txt|html)
Run Code Online (Sandbox Code Playgroud)
在zshand 中ksh93,您还可以在每个 glob 的基础上应用nullglob,这比修改全局设置要明智得多:
files=(*.txt(N)) # zsh
files=(~(N)*.txt) # ksh93
Run Code Online (Sandbox Code Playgroud)
如果没有txt文件,则将创建一个空数组,而不是使命令失败并出现错误(或使其成为一个*.txt带有其他 shell 的一个文字参数的数组)。
fish2.3 之前的版本会工作,bash -O nullglob但在 glob 没有匹配时交互时会发出警告。从 2.3 开始,它的工作原理类似于,或 中zsh使用的globs 。forsetcount
现在,在历史记录上,该行为实际上被Bourne shell破坏了。在先前版本的 Unix 中,globbing 是通过/etc/globhelper完成的,该 helper 的行为类似于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
Run Code Online (Sandbox Code Playgroud)
将使命令失败(除非a.whateverb当前目录中有一些文件)。csh(它也在变量扩展时执行 globbing)在这种情况下确实使命令失败(我认为这比在那里留下一个休眠的错误要好,即使它不如在rc/ zsh/ fish... )。
¹ 对于它ls可能会报告*.txt文件不存在的错误,除非它已在间隔中创建,或者当前目录恰好可搜索但不可读并且该文件或目录存在。尝试后mkdir -p '*.txt/wtf'; chmod a=,u=wx .例如
² 4.4 版在这方面看到了一些改进,因为set -o可以local -在 Almquist shell中将选项设置为本地函数,但这不适用于bash的第二组选项,设置为shopt
| 归档时间: |
|
| 查看次数: |
19578 次 |
| 最近记录: |