Compatibility between Zsh and Bash

Zsh is mostly compatible with Bash. Mostly.

Loop

If it comes to arrays and the for loop the following script works perfectly in Bash but not in Zsh.


words=("first" "second" "third")
for((i=0; i < ${#words}; i++))
do 
  echo ${words[$i]}
done

The first thing which breaks the compatitibility is the missing whitespace right after the for keyword. After adding it the above script runs in Zsh too but the output is not what you would expect. Arrays in Bash are 0-based and thus starting with the index 0 whereas in Zsh it must start with 1. For Zsh the above script has to be altered as follows.


words=("first" "second" "third")
for ((i=1; i <= ${#words}; i++))
do 
  echo ${words[$i]}
done

Wildcard

Another point where both shells differ in their behavior are wildcards. Where less */textfile works perfectly in both the command locate */vi works in Bash but in Zsh you'll see zsh: no matches found: */vi. The solution here is to use double quotes to let both behave the same.

locate "*/vi"

Short if statement

The short if statement looks as follows.


[ "1" == "1" ] echo "Yes, both are the same.";

In Bash it works like a charm but Zsh claims zsh: = not found. To make it compatible just use one equal sign. This snippet was tested in Bash version 4.2.37 and Zsh version 5.0.0. In the older Bash version 3.2.25 which is still used on certain linux systems nowadays that snippet failed. If you must guarantee your script working with any Bash version use the full if statement instead.

Update (April 19th, 2013)

In one script I used the version with two brackets as suggested by Drew Adams in a comment.

[[ $project_description == "" ]]; echo "You must provide a project description!" && exit;

For some reason the echo statement was always executed no matter the variable was empty or not. I strongly recommend to always use the full if statement.

if [ "$project_description" = "" ];
then
    echo "You must provide a project description!"
    exit
fi

Be sure you quote the variable because if it's empty your shell will substitute the condition to if [ = "" ]; otherwise.

Summary

  1. Keep an eye on missing whitespaces or quotes
  2. Keep in mind the different array indexing
  3. Use one equal sign or simply avoid the short if statement

If you know more incompatibilities, leave me a comment. Also read Iterating over array elements.

5 Comments

  1. Michael Q

    This explanation was extremely helpful! I solved the incompatibility issue with my script. Bash aliases == to = as a service to programmers used to working in languages where == is conventional in conditional logic, so removing second equal signs made the script work in bash and zsh. Makes you wish zsh would also alias == to =. Anyway, big thanks!

  2. In zsh, you can get that last example to work by using: “[[" and "]]” and adding a semicolon after the close brackets.

    My version:

    $ [[ "1" == "1" ]]; print “Yes, both are the same.”; <– run this
    Yes, both are the same. <– get this

    note : i did change echo to print in the example I showed. I did this only because I prefer using print… it will work with echo just as well.

  3. Oh, I should also point out that my example should also work in bash and ksh93 without modification as well.

  4. What is this, some kind of a joke?! Of course the echo statement is always executed, that’s what semicolon does — executes the first command, executes the next, …
    If you wanted to condition the second command on the successful run of the first, you put && in between, which is a logical and.
    Likewise, that’s what’s missing in your ‘Short if statement’ above. Like this, it shouldn’t work in bash either.

  5. slopjong

    kernc, you’re right, the short if statement looks odd, indeed. Maybe I shouldn’t work at night.

Leave a Reply

Your email address will not be published. Required fields are marked *

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>