## A.8. zsh

zsh is a powerful interactive shell and scripting language with many features found in ksh, bash, and tcsh, as well as several unique features. zsh has most of the features of ksh88 but few of ksh93. It is freely available and should compile and run on just about any modern version of Unix. Ports for other operating systems are also available. The zsh home page is http://www.zsh.org. The current version is 4.0.2.

In this section we cover:

- Extended globbing

- Completion

- Command-line editing

- Prompts and prompt themes

- Differences between zsh and ksh

### A.8.1. Extended Globbing

A very useful feature is the recursive glob[152] operator, `**`. For example, a recursive grep is simple to construct:

> [152] Globbing is technical slang for wildcard expansion.

>     grep foo **/*.c

Or to recursively find all files or directories named core, try:

>     print **/core

Another useful feature is glob qualifiers. There are many of these, for example, to print out only regular files in the current directory:

>     print *(.)

or just the directories:

>     print *(/)

Combining these with the recursive glob operator can be handy. We can improve the above example of finding core files by limiting the search to regular files only:

>     print **/core(.)

Another qualifier is `U` for file system objects you own. The following prints all files you own in /tmp and below:

>     print /tmp/**/*(U)

The glob qualifiers can also be combined. For example, using the socket file keyword `=` in combination with `U`, it's easy to find socket files in /tmp and below that you own:

>     print /tmp/**/*(U=)

File size qualifiers are also available. For example, to find all files in your home directory that are greater than 10 megabytes in size:

>     print ~/**/*(Lm+10)

And file permission qualifiers are also available. For example, the `W` qualifier selects world-writable file system objects. You can use it to find all directories in your home directory and below that are owned by you and that are world-writeable:

>     print ~/**/*(UW/)

See zshexpn(1) for more information.

### A.8.2. Completion

The zsh completion system is extremely sophisticated. The main idea is that any time you are about to type something on the command line, if you hit TAB, zsh will try to complete it. zsh comes with many defaults for completion and is also fully customizable.

To get a full set of default completion features, run the following commands (normally in your ~/.zshrc startup file):

>     autoload -U compinit
>     compinit

Now let's look at some examples. We represent the TAB key in examples as `[TAB]`.

First, zsh is smart about doing completions. For example, `cd[TAB]` only expands directories, thus eliminating completion noise.

Have you ever been frustrated because you can't think of exactly the name of the command you want to find more information on, and man -k[153] hasn't been configured on your system? Well, zsh will complete available man pages for you:

> [153] This does a keyword search of an online database extracted from the man pages.

>     g@sifl:pts/7% man zsh[TAB]
>     zsh           zshcompctl    zshcontrib    zshmodules    zshzftpsys
>     zshall        zshcompsys    zshexpn       zshoptions    zshzle
>     zshbuiltins   zshcompwid    zshmisc       zshparam

Or maybe you want to find out a process name or PID you want to kill:

>     g@sifl:pts/2% kill [TAB]
>      9652 pts/2    00:00:00 zsh
>      9653 pts/2    00:00:00 ps

For finger, it expands users:

>     g@sifl:pts/7% finger o[TAB]
>     odin	omg	oof        operator	orb

and hosts:

>     g@sifl:pts/7% finger oof@[TAB]
>     brak	localhost 	sifl 	zorak

Using the distributed compdef function, you can define your own completions, using either your own custom functions or the completion functions that come with zsh. For example, the distribution defines the kill command to use the _pids distribution function to provide process identifiers. You can also use it to define completion for other commands, such as the Solaris pstack command:

>     compdef _pids pstack

Once this is done, you can apply completion to the pstack command like so:

>     g@sifl:pts/7% pstack [TAB]
>     13606 pts/7    00:00:00 zsh
>     13607 pts/7    00:00:00 ps

Another very useful distribution completion function is _gnu_generic. This can be applied to any command that uses the GNU `--long-option` command-line option conventions. The zsh distribution specifies many GNU commands to complete with this function (such as tar):

>     g@sifl:pts/7% tar --v[TAB]
>     --verbose      --verify       --version      --volno-file

And this is just the tip of the proverbial iceberg. There is much more to the zsh completion system; see zshcompsys(1) for the (gory) details.

### A.8.3. Command-Line Editor

The zsh command-line editor is extremely powerful. It has several unique features, including multiline editing and an input buffer stack. The multiline command editor makes composing small scripts on the command line much easier then just having one line to edit with.

The input buffer stack comes in very handy. While you are typing a command, you can type ESC q, and the current line is pushed onto the buffer stack. The input line is then cleared, and you can type another command. When that has been executed, the previous line is popped off the stack and you can continue with that command. See zshzle(1) for more details.

### A.8.4. Prompts and Prompt Themes

While most modern shells have customizable prompts, zsh raises it to an art form. One of the unique features is a right side prompt, `RPROMPT`, which is very useful for holding the current directory. This in turn removes clutter from the left hand prompt:

>     g@sifl:pts/2% RPROMPT='%~'
>     g@sifl:pts/2%                                    ~/src/xemacs-21.1.14

Also, you can define colors and bold fonts, and the prompt can be more than one line.

And as the notion of themes[154] has become popular in GUIs such as GNOME, zsh prompt themes can be defined; the distribution ships with several to choose from. To enable prompt themes, add these lines to your ~/.zshrc:

> [154] Some popular GUIs, such as GNOME, support themes. Rather than having one immutable look and feel, they can be changed to different styles, or themes. The distributions of these GUIs often contain several to choose from. Some of these tend to emulate other GUI's, while others are new and are mostly fun window dressing.

>     autoload -U promptinit
>     promptinit

To see what themes are available, run:

>     g@sifl:pts/2% prompt -l                                             ~
>     Currently available prompt themes:
>     adam1 adam2 bart bigfade clint elite2 elite fade fire off oliver
>     redhat suse zefram

To enable a theme, use the -s option. For example:

>     g@sifl:pts/7% prompt -s bart                                        ~
>     sifl [prompt -s bart] ~                              01-10-04 11:58PM
>     g@sifl:pts/7%                                                       ~

You can see that bart is a two-line prompt with several components such as the host name, the previous command, the current directory, and the date and time. See zshcontrib(1) for more details on prompt themes.

### A.8.5. Differences Between zsh and ksh

This section is derived from information in the zsh FAQ.

Most features of ksh88 (and hence also of the Bourne shell, sh) are implemented in zsh; problems can arise because the implementation is slightly different. Note also that not all ksh's are the same either. This is based on the 11/16/88f version of ksh; differences from ksh93 are more substantial.

As a summary of the status:

1. Because of all the options, it is not safe to assume a general zsh run by a user will behave as if sh or ksh compatible.

2. Invoking zsh as sh or ksh (or if either is a symbolic link to zsh) sets appropriate options and improves compatibility (from within zsh itself, calling `ARGV0=sh zsh` will also work).

3. From Version 3.0 onward, the degree of compatibility with sh under these circumstances is very high: zsh can now be used with GNU configure or perl's Configure, for example.

4. The degree of compatibility with ksh is also high, but a few things are missing: for example, the more sophisticated pattern-matching expressions are different for versions before 3.1.3 -- see the detailed list below.

5. Also from 3.0, the command emulate is available: `emulate ksh` and `emulate sh` set various options as well as changing the effect of single-letter option flags, as if the shell had been invoked with the appropriate name. Including the command `emulate sh; setopt localoptions` in a shell function turns on sh emulation for that function only. In 4.0 (and in 3.0.6 through 8), this can be abbreviated as `emulate -L sh`.

The classic difference is word splitting: zsh keeps the result of plain `$variable` as one word, even if the variable contains white space. This trips up many beginning zsh users. The answer is to set `SH_WORD_SPLIT` for backward compatibility. The next most classic difference is that unmatched glob patterns cause the command to abort; set `NO_NOMATCH` for those.

zsh has a large set of options which increase ksh compatibility, though maybe decreasing zsh's abilities: see the manual entries for the details. If invoked as ksh, the shell sets suitable options.

Here are some differences from ksh which might prove significant for ksh programmers, some of which may be interpreted as bugs. Note that this list is deliberately rather full and that most of the items are fairly minor. Those marked with perform in a ksh-like manner if the shell is invoked with the name ksh or if `emulate ksh` is in effect. Capitalized words with underscores in their names refer to shell options.

Syntax

  - Shell word splitting: see above.

  - Arrays are (by default) more csh-like than ksh-like: subscripts start at 1, not 0; `array[0]` refers to `array[1]`; `$array` refers to the whole array, not `$array[0]`; braces are unnecessary: `$a[1]` is the same as `${a[1]}`, etc. Set the `KSH_ARRAYS` option for compatibility.

  - Coprocesses are established by coproc; `|&` behaves like csh.[155] Handling of coprocess file descriptors is also different.

    > [155] In csh, `|&` sends both standard output and standard error down the same pipeline; it is equivalent to ... `2>&1 |` ....

  - For ``cmd1`` `&&` ``cmd2`` `&`, only cmd2, instead of the whole expression, is run in the background in zsh. The manual implies that this is a bug. Use `{` ``cmd1`` `&&` ``cmd2`` `} &` as a workaround.

Command-line substitutions, globbing, etc.

  - Failure to match a globbing pattern causes an error (use `NO_NOMATCH`).

  - The results of parameter substitutions are treated as plain text: `foo="*"; print $foo` prints all files in ksh but prints `*` in zsh (use `GLOB_SUBST`).

  - The prompt variables (e.g., `PS1`) do not undergo parameter substitution by default (use `PROMPT_SUBST`).

  - Standard globbing does not allow ksh-style pattern-lists. Table A-1 shows equivalent patterns.

    The `^`, `~` and `#` (but not `|`) forms require setting `EXTENDED_GLOB`. From version 3.1.3, the ksh forms are fully supported when the option `KSH_GLOB` is in effect; for previous versions you must use the equivalents given in Table A-1.

  - Unquoted assignments do file expansion after colons (intended for `PATH`-style variables).

  - integer does not allow -i.

  - typeset and integer have special behavior for assignments in ksh, but not in zsh. For example, this doesn't work in zsh:

    >     integer k=$(wc -l ~/.zshrc)

    because the return value from wc includes leading whitespace, which causes wordsplitting. ksh handles the assignment specially, as a single word.

#### Table A-1. ksh/zsh pattern equivalents

ksh | zsh | Meaning
--- | --- | ---
`!(foo)` | `^foo` | Anything but `foo.`
| `foo1~foo2` | Anything matching `foo1` but not `foo2`.[156]
`@(foo1|foo2|...)` | `(foo1|foo2|...)` | One of `foo1` or `foo2` or ...
`?(foo)` | `(foo|)` | Zero or one occurrences of `foo`.
`*(foo)` | `(foo)#` | Zero or more occurrences of `foo`.
`+(foo)` | `(foo)##` | One or more occurrences of `foo`.

[156] Note that `~` is the only globbing operator to have a lower precedence than `/`. For example, `**/foo~*bar*` matches any file in a subdirectory called foo, except where bar occurred somewhere in the path (e.g. users/barstaff/foo will be excluded by the `~` operator). As the `**` operator cannot be grouped (inside parentheses it is treated as `*`), this is the way to exclude some subdirectories from matching a `**`.

Command execution

  - There is no `ENV` variable (use /etc/zshrc, ~/.zshrc; note also `$ZDOTDIR`).

  - `$PATH` is not searched for commands specified at invocation without -c.

Aliases and functions

  - The order in which aliases and functions are defined is significant: function definitions with `()` expand aliases.

  - Aliases and functions cannot be exported.

  - There are no tracked aliases: command hashing replaces these.

  - The use of aliases for key bindings is replaced by bindkey.

  - Options are not local to functions (use `LOCAL_OPTIONS`; note this may always be unset locally to propagate options settings from a function to the calling level).

  - Functions defined with `function` `funcname` `{` `body` `;}` behave the same way as those defined with `funcname` `() {` `body` `;}`. In ksh93, only the former behave as true functions, and the latter behave as if the body were read from a file with the dot command.

Traps and signals

  - Traps are not local to functions. The option `LOCAL_TRAPS` is available from 3.1.6.

  - TRAPERR has become TRAPZERR (this was forced by UNICOS which has SIGERR).

Editing

  - The options emacs, gmacs, and viraw are not supported. Use bindkey to change the editing behavior: `set -o emacs` becomes `bindkey -e` and `set -o vi` becomes `bindkey -v`; for gmacs, go to emacs-mode and use `bindkey \^t gosmacs-transpose-characters.`

  - The keyword option does not exist and set -k is instead interactivecomments.

  - Management of histories in multiple shells is different: the history list is not saved and restored after each command. The option `SHARE_HISTORY` appeared in 3.1.6 and is set in ksh compatibility mode to remedy this.

  - `\` does not escape editing chars (use CTRL-V).

  - Not all ksh bindings are set (e.g. ESC #; try ESC q).

  - `#` in an interactive shell is not treated as a comment by default.

Built-in commands

  - Some built-ins (r, autoload, history, integer, ...) are aliases in ksh.

  - There is no built-in command newgrp: use `alias newgrp="exec newgrp"`.

  - jobs has no -n flag.

  - read has no -s flag.

Other idiosyncrasies

  - `select` always redisplays the list of selections on each loop.

Copyright © 2003 O'Reilly & Associates. All rights reserved.