我的环境
OSX 10.11.6
zsh 5.0.8 (x86_64-apple-darwin15.0)
GNU bash, version 3.2.57(1)-release (x86_64-apple-darwin15)
Mono C# compiler version 4.0.5.0
test.cs
class Test {
public static void Main() {
System.Console.WriteLine("hello, world");
}
}
test.sh
#! /bin/bash
mcs -recurse:*.cs
我可以用/test.sh编译test.cs
但是如果我把test.sh改为
#! /bin/zsh
mcs -recurse:*.cs
错误显示
./test.sh:3: no matches found: -recurse:*.cs
那么,为什么我不能使用zsh?
zsh
试图将该单词中的*
扩展为文件glob,但失败并引发错误。
bash
也做同样的事情,但默认情况下,它只是忽略globbing失败并保持单词完整(因此mcs
看到了它期望的参数)。
将shopt -s failglob
添加到脚本的顶部(对于bash
),它也将失败。
引用mcs
的参数中的*
可以避免这种情况。
mcs -recurse:'*.cs'
因为字符串-recurse:*.cs
包含一个未加引号的*
,所以大多数shell会尝试将其视为glob模式,并将其扩展为一个或多个匹配的文件名。
zsh
中的默认行为是将没有匹配项的模式视为错误,而不是将该模式视为文字字符串。如果启用failglob
选项,则可以在bash
中看到相同的行为。
$ echo foo*
foo*
$ shopt -s failglob
$ echo foo*
bash: no match: foo*
在zsh
中,引用以下模式:
#! /bin/zsh
mcs -recurse:"*.cs"
关闭NOMATCH
选项,
#! /bin/zsh
setopt NO_NOMATCH
mcs -recurse:*.cs
或者使用zsh命令修饰符:
#! /bin/zsh
noglob mcs -recurse:*.cs
在命令mcs -recurse:*.cs
中,*
旨在作为参数的文字部分传递给mcs
,但它作为路径名扩展的通配符对所有常见Unix外壳(bash
、zsh
、tcsh
和其他)也有意义。因此,如果工作目录中有一个名为-recurse:oops.cs
的文件,您的命令可能会让您大吃一惊。
当没有文件与给定模式匹配时,shell的默认行为会产生差异。默认情况下,bash
会回到猜测*
是字面意思,这实际上就是你的意思。另一方面,zsh
表现出更传统的由于未能匹配模式而失败的行为。通过打开failglob
选项,也可以诱导bash
表现出这种行为。
最好的解决方案是通过引用参数来解决歧义,或者至少转义其中的*
。bash
和zsh
都应该很好地处理这个版本,而不需要任何特殊选项:
mcs -recurse:*.cs