Bash – Why does arithmetic expansion work in Bash but not in Zsh

arithmeticbashshell-scriptzsh

I was demonstrating a piece of funny code (or so I think) to my students in class, and to my surprise, it did not work in zsh. I then switched to bash and it worked as expected.

The code is the following:

[ $(( $RANDOM % 6 )) == 0 ] && echo "Boom" || echo "Click"

In bash it prints Boom or Click randomly, as expected. But in zsh I get the error message below:

zsh: = not found

Can anyone explain what is the difference? To my understanding, both shells should interpret scripts in an equivalent manner.

Thanks.

Best Answer

Try doing unsetopt equals and try again. Or put quotes on the first equals character.

If you use [ for conditions, all arguments are evaluated normally and = at the start of a word is a useful zsh shorthand to get the location of a command. e.g. =ls expands to /bin/ls. Given == zsh looks for an = command and doesn't find one.

Zsh in posix mode (sh emulation) will be a lot more compatible with bash. Many things are compatible and most learnt knowledge of bash is still useful but there are certain things to be aware of if you want to write portable scripts.

Unlike [ which is a builtin, [[ is a reserved word understood by the parser and will give you fewer issues. However in this case you're using arithmetic mode so you simplify it:

    (( RANDOM % 6 == 0 )) && echo "Boom" || echo "Click"

In fact the comparison to zero is even superfluous because, the default return status reflects whether the value is zero, though the sense is reversed:

    (( RANDOM % 6 )) && echo "Click" || echo "Boom"
Related Question