user1934428
user1934428

Reputation: 22356

zsh (vs. bash) parameter expansion anomaly

If you execute the script

X=abcd
echo ${1:-$X}
echo ${1?$X}

without passing any parameter, and do it under bash, it outputs

abcd
./mrh.sh: line 3: 1: abcd

If you run it under zsh, it outputs

abcd
mrh.sh:3: 1: -$X

We see that in the case of ${...?...}, the substitution ($X) is expanded under bash, but not under zsh. In the case of ${...:-...}, $X is expanded in both bash and zsh.

I looked up the zsh man page to find an explanation, why no substitution of $X takes place in the second case, but could not find anything. Is it a bug in zsh?

Using zsh 5.0.6

Upvotes: 0

Views: 215

Answers (1)

Adaephon
Adaephon

Reputation: 18429

The explanation actually can be found in the man pages of zsh (zshexpn(1)) and bash (bash(1)).

For both shells substituted text is also subject to parameter expansion:

  • zshexpn(1):

    […] the replacement text of any substitutions, are themselves subject to parameter expansion […]

  • bash(1):

    In each of the cases below, word is subject to tilde expansion, parameter expansion […]

Here are the relevant parts of the substitutions in question (emphases by me):

  1. For ${1:-$X} both shells behave the same:

    • zshexpn(1):

      ${name:-word}

      If name is […] is non-null, then substitute its value; otherwise substitute word.

    • bash(1):

      ${parameter:-word}

      […] If parameter is unset or null, the expansion of word is substituted. Otherwise, the value of parameter is substituted

    While the zsh manpage does not explicitly mention that word is again expanded, this is covered by the above mentioned rule. Leading to abcd being printed in your example.

  2. For ${1:?$X} there is a slight difference in the wording of what zsh does:

    • zshexpn(1):

      ${name:?word}

      [...] if name is both set and non-null, then substitute its value; otherwise, print word and exit from the shell.

    • bash(1):

      ${parameter:?word}

      If parameter is null or unset, the expansion of word [...] is written to the standard error and the shell, if it is not interactive, exits. Otherwise, the value of parameter is substituted.

    For bash it is explicitly stated that word is expanded. But for zsh it states that word is printed and not substituted. That also means that it is not subject to the rule mentioned above.

Upvotes: 2

Related Questions