Why zsh Should Be the Default Shell on OS X
From OS X Scientific Computing
| Return to ZSH on OS X. |
I used to think people who argued about the merits of different unix shells were, well, blessed with a lot of spare time. However, I was finally convinced by Gary Kerbaugh, an immensely knowledgable and helpful person, to give zsh a try. I decided to do so for a weekend, and found I was unable to go back. Under OS X v. 10.2.x, tcsh is the default shell. The other shells that come with OS X by default include bash (the "Bourne Again" and more user-friendly version of the Bourne shell, sh) and zsh. zsh is probably most like ksh in its syntax, but is actually more user-friendly than is tcsh.
If you are comfortable with tcsh, you will likely find zsh at least as user-friendly. If you like any of the sh-type shells, you will find that zsh incorporates all of the programmability of the sh-type shells but has some very nice additional features.
The zsh site does an excellent job of explaining and advocating for the Z-shell. Be sure to obtain a copy of the very nice pdf. You should download and read it. I printed it out and had it bound at a photocopy store. It is one of the best-written computer books I have ever read. In addition, you can now purchase a book entitled From Bash to Z Shell. (Oliver Kiddle, Jerry Peek and Peter Stephenson, From Bash to Z Shell: Conquering the Command Line, Apress (2005).)
Here are some of the things that zsh offers you that tcsh (and maybe other options) do not:
Contents |
Really nice programmable command-line completions, including remote filename completions:
For example, let's say I have nine png files in a directory that start with the prefix aqua. If I type open aqua and then hit the tab key without hitting the space bar, I will see the following output from the shell:
zsh-% open aqua<tab> ---- file aqua_autoinstall_osx.png aqua_devtools_osx.png aqua_mosflm_osx.png aqua_title_crystal_o.png aqua_backups_osx.png aqua_eden_osx.png aqua_nmr_osx.png aqua_title_crystal_osx.png aqua_ccp4_osx.png |
But it gets even better. If I hit the tab key again and again (six times total) it cylces through the various options in the order listed, giving me the sixth file:
open aqua <tab><tab><tab><tab><tab><tab> open aqua_eden_osx.png
Also, the shell is smart enough to use only sensible options, thanks to the programmability of the command line completion functions. Nonsensical completions are usually filtered out.
You aren't limited to filenames. Zsh can complete just about anything, including user and domain names:
zsh-% ssh wgs<tab>
gives me
zsh-% ssh wgscott@
and
zsh-% ssh wgscott@x<tab>
gives me
ssh wgscott@xaxaxa.foobar.org
Again, it can cycle through all the options. It even does remote file completion with scp, (but you have to have passwordless ssh set up first for it to work efficiently).
You can define useful functions in addition to aliases:
The various sh-shells, unlike csh and tcsh, allow you to define functions. A function is essentially like an alias to a zsh shell script that you can call by name, except that it is read into memory when the shell is started. It is much more versatile than a simple alias as well. Here is a somewhat trivial example (that probably could be an alias in tcsh):
function joinpdf {
gs -q -dNOPAUSE -dBATCH -sDEVICE=pdfwrite -sOutputFile=merged.pdf "$@"
}
This function, called joinpdf, takes one or any number of pdf files and joins them into one catenated pdf called merged.pdf.
Here is another example, a function that invokes vi as a normal user unless one or more files is owned by root, in which case it invokes sudo vi. I wrote this (with a lot of help from Gary Kerbaugh) because I got really tired of opening a root owned file with vi, making a bunch of changes, and then finding I couldn't save the changes. This would be too complex for a simple alias, and being a function rather than a shell-script, it is invoked a bit more quickly.
function vi {
LIMIT=$#
for ((i = 1; i <= $LIMIT; i++ )) do
eval file="\$$i"
if [[ -e $file && ! -O $file ]]
then
otherfile=1
else
fi
done
if [[ $otherfile = 1 ]]
then
sudo vi "$@"
else
command vi "$@"
fi
}
Recursive globbing is implemented in zsh:
eg:
ls **/*whatever.c
finds your forwhatever.c file anywhere in the directory tree.
Glob qualifiers are also available in zsh:
ls *(/)
prints directories and their contents
print *(/)
prints the directory names
ls *(.)
lists just files.
Admitedly, you can do stuff in tcsh like
alias dls "\ls -F | grep /"
but this is way more cool and flexible.
| Return to ZSH on OS X. |

