Can not use /bin/zsh to compile a csharp program, but /bin/bash can

197 Views Asked by At

My env

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

I can use ./test.sh to compile test.cs

but if I change test.sh to

#! /bin/zsh

mcs -recurse:*.cs

error shows

./test.sh:3: no matches found: -recurse:*.cs

So, Why I can not use zsh?

3

There are 3 best solutions below

0
Etan Reisner On

zsh is attempting to expand the * in that word as a file glob, failing, and throwing an error.

bash does the same thing but, by default, it just ignores the globbing failure and keeps the word intact (so mcs sees the argument it expects).

Add shopt -s failglob to the top of the script (for bash) and it will fail also.

Quote the * in the argument to mcs to avoid this.

mcs -recurse:'*.cs'
0
chepner On

Because the string -recurse:*.cs contains an unquoted *, most shells will attempt to treat it as a glob pattern and expand it to one or more matching file names.

The default behavior in zsh is to treat a pattern that has no matches as an error, rather than treating the pattern as a literal string. The same behavior can be seen in bash if you enable the failglob option.

$ echo foo*
foo*
$ shopt -s failglob
$ echo foo*
bash: no match: foo*

In zsh, either quote the pattern:

#! /bin/zsh

mcs -recurse:"*.cs"

turn off the NOMATCH option,

#! /bin/zsh

setopt NO_NOMATCH
mcs -recurse:*.cs

or use the zsh command modifier:

#! /bin/zsh

noglob mcs -recurse:*.cs
0
John Bollinger On

In your command mcs -recurse:*.cs, the * is intended to be passed to mcs as a literal part of the argument, but it is also meaningful to all common Unix shells (bash, zsh, tcsh, and others) as a wildcard for pathname expansion. As such, your command would probably surprise you if there were a file named -recurse:oops.cs in the working directory.

The difference arises in the shells' default behavior when no file matches the given pattern. By default, bash falls back to guessing that you meant the * to be a literal, which is in fact what you meant. zsh, on the other hand, exhibits the more traditional behavior of failing on account of the failure to match the pattern. bash can be induced to exhibit that behavior, too, by turning on its failglob option.

The best solution is to resolve the ambiguity by quoting the argument, or at least escaping the * in it. Both bash and zsh should handle this version fine without any special options:

mcs -recurse:\*.cs