mars

zsh

Homepage: zsh.org

Installation

apk add zsh
chsh -s `which zsh`

I needed to logout-login for the switch to take affect.

.profile is not sourced, use .zshrc.

FAQ

The ZSH FAQ is a fun read, here are some bits:

Zsh is a UNIX command interpreter (shell).

…it is not a good idea to put this into .cshrc as that will cause csh scripts (yes, unfortunately some people write these)…

… this makes zsh rather large and feature-ridden so that it seems to appeal mainly to hackers. The only answer, perhaps not entirely satisfactory, is that you have to igore the bits you don’t want.

“Unicode”, or UCS for Universal Character Set, is the modern way of specifying character sets. It replaces a large number of ad hoc ways of supporting character sets beyond ASCII. “UTF-8” is an encoding of Unicode that is particularly natural on Unix-like systems.

if you’d like to run a bash script or plugin under zsh, you must port just like you would when translating a book from American English to British English.

.zshrc

Zsh has a host of ~/.z* startup scripts that it will source on startup. Usually, putting things in ~/.zshrc should do what we want.

In particular though, /etc/profile, ~/.profile and $ENV will not be sourced when zsh is invoked as zsh (they’re only used when zsh is running in sh compatibility mode, that is, when zsh is invoked as sh and like)

Conversely, .zshrc and friends will not be invoked when running in shell compatibility mode. This might or might not be important, but good to lodge that fact in the crevices of my brain.

Sayeth zsh(1):

whilst reasonable efforts are taken to address incompatibilities when they arise, zsh does no guarantee complete emulation of other shells, nor POSIX compliance.

export

If you want programs run from zsh to see them, export the corresponding variables in .zshrc.

Introduction

Zsh has an comprehensive online documentation and man pages. Comprehensive to the point of intimidating.

The 1995 introduction is a great starting point.

Zsh is a shell designed for interactive use, although it is also a powerful scripting language. Many of the useful features of bash, ksh, and tcsh were incorporated into zsh; many original features were added.

The examples used in the intro show the historical context in which zsh originated; where you could finger your friends, and watch for them to login to the same computer you were working on. The roots of IRC, and the wisps of what might’ve been, and what could yet be.

Priors

man pages

There are many man pages (apropos zsh), or a single man page (man zshall) split into multiple.

Autoloading

autoloading is where a function’s definition is loaded on first use. The function is expected to be a shell script (so that it can be used both with the autoloading mechanism and otherwise) present in fpath.

From zshall(1):

The fpath parameter will be searched to find the function definition when the function is first referenced.

echo $fpath
/usr/local/share/zsh/site-functions /usr/share/zsh/site-functions ...

From the intro:

Instead of defining a lot of functions in your .zshrc, all of which you may not use, it is often better to use the autoload builtin. The idea is, you create a directory where function definitions are stored, declare the names in your .zshrc, and tell the shell where to look for them. Whenever you reference the funtion, the shell will automatically load it into memory.

The -U prevents alias expansion, something recommended in zshall(1):

The usual alias expansion during reading will be supressed if the autoload builtin or its equivalent is given the option -U. This is recommended for the use of functions supplied with the zsh distribution.

The -z flag turns off ksh compatibility autoloading (z for “zsh”).

Built in functions are thus often declared as autoload -Uz.

Customization

History

From Why is my history not being savedFAQ:

In zsh, you need to set three variables to make sure your history is written out when the shell exits.

HISTSIZE=200
HISTFILE=~/.zsh_history
SAVEHIST=200

$HISTSIZE tells the shells how many lines to keep internally, $HISTFILE tells it where to write the history, and $SAVEHIST, the easiest one to forget, tells it how many to write out.

Completion

From the mysteries of completionFAQ:

“Completion” is when you hit a particular command key (TAB by default) and the shell tries to guess the word you are typing and finish it for you.

There is a related process, “expansion”, where the shell sees you have typed something which would be turned by the shell into something els, such as a variable turning into a value ($PWD becomes /home/m) or a history reference (!! becomes everything on the last command line). In zsh, when you hit TAB it will look to see if tehre is an expansion to be done; if there is, it does that, otherwise it tries to perform completion (You can see if the word would be expanded – not completed – by TAB by typing C-x g, which lists expansions).

An elegant completion system comes with the shell, based on functions called automatically for completion in particular contexts (e.g. there is a function called _cd to handle completion for the cd command); all we need to do is to arrage for it to be loaded by putting autoload -U compinit; compinit

zsh does some completion even if we don’t do autoload -U compinit; compinit, but that is (I presume) using the older deprecated completion system, not the newer “elegant” (new) completion system (called compsys).

We can see the difference in trying to complete substrings. ls /e/passTAB does nothing by default, but will complete to ls /etc/passwd after compiniting.

zcompdump

By default, zsh will put the file where it caches completions into ~/.zcompdump. To prevent it from littering, we can tell it where to store these dumps when initializing it.

mkdir ~/.cache/zsh
compinit -d ~/.cache/zsh/zcompdump

Prompts

See Prompting in the intro, and PROMPT in zshall(1).

PROMPT='%~ $ '; RPROMPT='%(?..[%?]) %(1j.%j.)'

Related is wanting to display the current directory in the tab bar. The FAQ mentions:

You should use the special function chpwd, which is called by the shell when the directory changes. The following checks that standard output is a terminal, then puts the directory in the title bar if the terminal is an xterm etc.

```sh chpwd () { [[ -t 1 ]] || return case $TERM in xterm) print -Pn “\e]2;%~\a” ;; esac }

The -P option tells print to treat its arguments like a prompt string.

Note that when xterm starts up you will probably want to call chpwd directly.

The -n option supresses the terminating newline, as with echo. The “\e]2;” starts the escape sequence to communicate with the terminal emulator, the “\a” ends it.

Something like this suffices for me:

chpwd () {
  test -t 1 && case $TERM in; *xterm*) print -Pn "\e]2;%~\a";; esac
}

Feature tour

A stroll through the intro.

Globbing

Otherwise known as globbing, filename generation is quite extensive in zsh.

<x-y> matches a range of integers, both ar optional.

ls /dev/tty<->
/dev/tty0   /dev/tty19	/dev/tty29  /dev/tty39	/dev/tty49  /dev/tty59
/dev/tty1   /dev/tty2	/dev/tty3   /dev/tty4	...

**/* does a recursive search.

$RANDOM

echo $RANDOM $[$RANDOM%100]
699 8

Directory stacks

pushd, popd, and dirs to list.

pushd by itself swaps the top two.

Command substitution

alias

alias

History

ZLE

zsh’s command line editor, ZLE. emulates emacs.

bindkey lists default bindings.

Bindings

These editor commands are functions bound by default to certain keys.

expand-or-complete	 TAB
push-line		 M-q
run-help		 M-h
accept-and-hold		 M-a
quote-line		 M-'

Usage

fc

Fix command. invokes $EDITOR on last command.