-1

我的环境

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

测试.cs

class Test {
        public static void Main() {
                System.Console.WriteLine("hello, world");
        }
}

测试.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?

4

3 回答 3

2

zsh正在尝试*将该单词中的 扩展为文件 glob,失败并引发错误。

bash做同样的事情,但默认情况下,它只是忽略 globbing 失败并保持单词完整(所以mcs看到它期望的参数)。

添加shopt -s failglob到脚本的顶部(for bash),它也会失败。

*在参数中引用mcs以避免这种情况。

mcs -recurse:'*.cs'
于 2016-08-02T17:41:18.990 回答
2

因为字符串-recurse:*.cs包含一个不带引号的*,所以大多数 shell 会尝试将其视为 glob 模式并将其扩展为一个或多个匹配的文件名。

的默认行为zsh是将没有匹配的模式视为错误,而不是将模式视为文字字符串。bash如果启用该failglob选项,则可以看到相同的行为。

$ 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
于 2016-08-02T17:43:13.653 回答
1

在您的 commandmcs -recurse:*.cs中,*旨在mcs作为参数的文字部分传递给,但对于所有常见的 Unix shell(bashzshtcsh和其他)作为路径名扩展的通配符也是有意义的。-recurse:oops.cs因此,如果工作目录中有一个名为的文件,您的命令可能会让您感到惊讶。

当没有文件与给定模式匹配时,shell 的默认行为会有所不同。默认情况下,bash回退到猜测您的意思*是文字,这实际上就是您的意思。 zsh另一方面,由于无法匹配模式而表现出更传统的失败行为。 bash通过打开它的failglob选项,也可以诱导它表现出这种行为。

最好的解决方案是通过引用参数来解决歧义,或者至少*在其中转义。两者都bash应该zsh在没有任何特殊选项的情况下很好地处理这个版本:

mcs -recurse:\*.cs
于 2016-08-02T17:45:42.457 回答