chris blogs

March 2007

25mar2007 · Switching to zsh

With the help of the nice folks in #ruby-de, I finally switched to the Z shell after using GNU Bash for over seven years (with a rather short tcsh intermezzo, admittedly).

I’ve wanted to do the switch for some time, but I never managed to make it familiar enough for daily use (the default setup is unusable). Well, I now got a reasonable .zshrc together, and want like to share some parts of it.

Completion is the most awesome feature of zsh, although the recent Bash versions are steadily coming closer. Let’s enable the completion:

zmodload zsh/complist
autoload compinit && compinit

I don’t want it to think // means anything special, though:

zstyle ':completion:*' squeeze-slashes true

Add colors like in ls(1) for the file name completion:

eval `gdircolors`
zstyle ':completion:*' list-colors ''
zstyle ':completion:*:default' list-colors ${(s.:.)LS_COLORS}

And then, make the completion feel as Bash-like as possible (show all completions after two TABS, don’t cycle, put the prompt always below the completions):

setopt BASH_AUTO_LIST
setopt NO_AUTO_MENU
setopt NO_ALWAYS_LAST_PROMPT

History management, this is essentially how I configured it for Bash too:

setopt HIST_IGNORE_DUPS
setopt HIST_IGNORE_SPACE
setopt APPEND_HISTORY
setopt EXTENDED_HISTORY
HISTFILE=~/.zsh_history
SAVEHIST=1000
HISTSIZE=1000

The prompt, I used a rather bloated prompt with Bash; this is a stripped-down version with everything removed I don’t need. (And the monochrome version.)

PROMPT="%(?..[%?] )%(1L.%L.)#%h<%l>%m:%(4~,.../,)%3~%(!.#.$) "

How it looks, for example:

[1] 2#276<p5>lilith:.../rack/lib/rack$

This means, the last command exited with status 1, it is a second-level subshell, line 276 of history (for !), running on ttyp5 on my trusty iBook lilith, and I’m a normal user ($) in the rack/lib/rack directory on my disk (I know where that is).

I don’t use a right-hand-side prompt at the moment because I think it’s confusing, especially if your terminal isn’t very wide.

Terminal title, using a precmd. Host and path are enough for my purposes.

precmd () {print -Pn "\e]0;%n@%m: %d\a"}

Z line editor, zsh’s version of readline has a very good Emacs keybinding support which we’ll enable and configure it to regard / as a word seperator too (highly useful for editing paths):

WORDCHARS=${WORDCHARS//[&=\/;!#%{]}
bindkey -e

Mess, finally, mess dir support for zsh:

function mess {
  DIR=`~/bin/mess.rb "$@"`
  [[ $? -eq 0 ]] && cd "$DIR"
}

That’s essentially it; as you see, nothing really special but it’s a non-trivial configuration I’m very comfortable with so far.

Now, what benefits does zsh give me?

  • Mighty globs (** alone is worth the switch).
  • A good multiline editor.
  • Ready-made completion of just about everything.
  • Better redirection (shortcuts like |& for 2>&1, which I always get wrong).
  • Control structures I can remember (for x (1 2 3); echo $).
  • Better scripting (I don’t really do shell scripts anymore, tough).
  • Tetris. Ehem.

The only thing so far I couldn’t find out was how to disable file name escaping in the completion list, but that’s a minor aesthetic feature. Feel free to tell me if you know how that can be fixed.

Addition from January 19, 2007: zsh supports UTF8 line editing if the locale is right. For English messages, therefore set LANG=en_US.utf8 as LANG=C will not work.

NP: Guns N’ Roses—There Was A Time

Copyright © 2004–2016