我不明白为什么 * 在没有匹配项时会返回自身。这回答指出情况确实如此,但我不明白这种行为的基本原理。为什么 * 或任何通用模式在不匹配的情况下不返回空字符串?
$ls # Look, no files
$touch a # Add a file
$echo * # Works as expected
a
$rm a # Remove the file
$echo * # Will output a '*'. Why not ''?
*
$* # Ok, * will fail, but how come the previous output?
-bash: *: command not found
$
答案1
与任何文件都不匹配的模式被视为错误。您可以在 UNIX 的第一个版本中看到这一点。
全局会打印一个错误,并且它传递的命令永远不会运行。
错误消息是“不匹配”。
在你的现代外壳中源自Bourne(Unix 版本 7),ls -l *.c
会生成错误“*.c:没有这样的文件或目录”。我想说这个消息更容易理解;它还指示失败的模式。
请注意,如果*.c
扩展为空,ls -l *.c
则会显示目录中的所有文件,并且不会打印错误。
bash 有一个failglob
更接近原始行为的选项。
答案2
* 实际上是由 bash (无论你的 shell 是什么)扩展的,然后它被传递到回声。这回声命令不执行任何操作,只是将其打印到标准输出。阅读本文档 -文件名扩展。它说-
Bash 扫描每个单词中的字符“*”、“?”和“[”。如果出现这些字符之一,则该单词被视为模式,并替换为与该模式匹配的按字母顺序排序的文件名列表。如果没有找到匹配的文件名,并且 shell 选项 nullglob 被禁用,则该单词将保持不变。如果设置了 nullglob 选项,并且未找到匹配项,则该单词将被删除。
所以实际上,当 bash 找不到任何匹配时,它会保留 '*' 不变,并 echo 打印出来。
原因
bash 默认情况下不返回空语句的原因是,在某些情况下,用户不想使用“*”作为通配符,因此他不需要“*”的扩展。因此在这种情况下将“*”扩展为空字符串将是错误的。但是,可以通过选项覆盖此默认行为nullglob
。