Skip to content


Switch branches/tags

Latest commit


Git stats


Failed to load latest commit information.
Latest commit message
Commit time

The Zsh Pony ============


The Zsh defaults to a minimalistic configuration which doesn’t show the potential behind this powerful and flexible shell. The Zsh pony project provides a list of really hot stuff of what’s possible with Zsh.


Grab a fully featured Zsh configuration:

% wget -O .zshrc

Switching directories for lazy people

% setopt autocd && /tmp

Share history file amongst all Zsh sessions, ignoring dupes

% setopt append_history share_history histignorealldups

Option Setting in Zsh, AKA setopt*

% setopt $OPTION
% man zshoptions

Replace spaces in filenames with a underline

% autoload -U zmv
% touch 1\ 2  3\ 4\ 5
% zmv '* *' '$f:gs/ /_'

Fast Manpage access

% autoload run-help
% echo foo | xargs <esc-h>

and then:

% git commit<esc-h>

or even ('g' being an alias for git and 'co' and git alias for commit):

% g co<esc-h>

Completion System

Enable completion

% autoload compinit && compinit
% kill c<tab>
% man z<tab>
% dpkg -L <tab>

Menu Selection

% zstyle ':completion:*' menu select


Tip: Get completion help running ‘ctrl-x h’.

Use colors in completion

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

Pick item but stay in the menu

% bindkey -M menuselect "+" accept-and-menu-complete
% ls <tab> +

Globbing / Glob Qualifiers

Makes find(1) useless for many jobs.

% setopt extendedglob
% rm ../debianpackage(.)   # remove files only
% ls -d *(/)               # list directories only
% ls /etc/*(@)             # list symlinks only
% ls -l *.(png|jpg|gif)    # list pictures only
% ls *(*)                  # list executables only
% ls /etc/**/zsh           # which directories contain 'zsh'?
% ls **/*(-@)              # list dangling symlinks ('**' recurses down directory trees)
% ls foo*~*bar*            # match everything that starts with foo but doesn't contain bar

The e glob qualifier - e.g. to match all files of which file says that they are JPEGs:

% ls *(e:'file $REPLY | grep -q JPEG':)
  • (#s) or (#e) for what ^ and $ are in regexps (beginning of line/end of line)
  • (#b) or (#m) to enable backreferences
  • (#i) to match case insensitive
  • (#a) to match approximately (certain errors are ignored, e.g. “(#a1)foo*” matches the string “ofobar”)

Tip: run e.g. `ls *(<tab>` to get help regarding globbing.


Run `bindkey` to get a listing of currently active keybindings


  1. \^ := ctrl
  2. \^[ := esc

Get emacs-like keybindings

Zsh defaults to vi keybindings (‘bindkey -v’) if $VISUAL or $EDITOR contain string ‘vi’. Run ‘bindkey -e’ to get emacs-like keybindings then.

Tip: run “bindkey ctrl-v <keys>” to find out which action is bount to a key

Some interesting keybindings

ctrl-dcomplete + EOF
ctrl-lclear screen
ctrl-wdelete last word
tabcomplete and take first result
esc-.insert last parameter of last typed command (similar to typing !$)
ctrl-abegin of line
ctrl-eend of line
alt-’quote-line (”)
ctrl-kkill line
ctrl-ukill while line (kill-ring)
ctrl-wcopy last word (kill-ring)
ctrl-yyank (insert kill-ring)
esc-qpush line

Remove last part from directory name

% slash-backward-kill-word() {
    local WORDCHARS="${WORDCHARS:s@/@}"
    zle backward-kill-word
% zle -N slash-backward-kill-word
% bindkey '\e^?' slash-backward-kill-word
% cd /usr/share/doc/mutt/examples/<alt+backspace>

Note: configured by default in grml-zshrc, so ready for usage out-of-the-box.

Keybindings {up,down}-line-or-search and history-beginning-search-{backward,forward}-end

% echo 123
% echo 234
% ls
and then:
% echo <cursor-up|down>
% echo 2<page-up|down>

Incremental search with history-incremental-pattern-search-backward:

% <ctrl-r>scp*r

Zsh Line Editor (AKA zle)

  1. It’s what readline is for bash (move, delete, copy words/lines/…)
  2. Basic layout of custom widgets, used like functions:
% foobar() { LBUFFER="foobar $LBUFFER"; } # function
% zle -N foobar         # declare function as bindable widget
% bindkey '^x^s' foobar # bind command to a keybinding
  1. ctrl-x-z provides help_zle_parse_keybindings in grml-zshrc

Edit command line in editor

% autoload edit-command-line && zle -N edit-command-line
% bindkey '\ee' edit-command-line

Insert a timestamp on the command line (yyyy-mm-dd)

insert-datestamp() { LBUFFER+=${(%):-'%D{%Y-%m-%d}'}; }
zle -N insert-datestamp
bindkey '^Ed' insert-datestamp

Insert last typed word

% insert-last-typed-word() { zle insert-last-word -- 0 -1 };
% zle -N insert-last-typed-word;
% bindkey "\em" insert-last-typed-word
% mv foobar <esc-m>

Complete word from history with menu

% zle -C hist-complete complete-word _generic
% zstyle ':completion:hist-complete:*' completer _history
% bindkey "^X^X" hist-complete

Loadable modules

Play tetris

% autoload -U tetris
% tetris

URL quoting

% autoload -U url-quote-magic
% zle -N self-insert url-quote-magic

Disclaimer: annoying when using e.g.{1,2,3}.tgz


% autoload -U promptinit
% promptinit
% prompt fire
% prompt <tab>

Exit code in prompt, if it’s not exit code 0

Special functions

precmd(): executed before each prompt - e.g. for setting prompt information

preexec(): running before every command - e.g. for setting GNU screen title

RPOMPT with a smiley (note: the version in grml-zshrc is more sophisticated -> moving smiley)

precmd () { RPROMPT="%(?..:()%" }

Get VCS information into your prompt - vcs\_info

autoload -Uz vcs_info
precmd() {
  [[ -n $vcs_info_msg_0_ ]] && psvar[1]="$vcs_info_msg_0_"
PS1="%m%(1v.%F{green}%1v%f.)%# "

Hashed directories

% hash -d doc=/usr/share/doc
% cd ~doc
% hash -d deb=/var/cache/apt/archives
% sudo dpkg -i ~deb/foobar*deb

On-the-fly editing of variables

% vared PATH


Supports csh style bang history expansion.

% history  # last 16 events
% history -E 0  # all history events including date/time information
% !23      # Re-execute history command 23
% !!       # The last command.
% !$       # Last word of the last command.
% !-2      # The last but one command.
% !-2$     # The last word of the command before the last command.
% !#$      # The last word of the current command line.
% !#0      # The first word of the current command line.
% !?foo    # The last command that matches the pattern `foo'.
% !?foo?1  # The second word of the last command line that matches `foo'.

…and that’s really just the start. History expansion is extremely versatile and powerful - but also a bit cryptic for the untrained eye. Practice, young padawan, makes perfect. .o( man zshexpn | less -p ‘\^HISTO.*ANSION$’ )


  • fc -p/fc -a/fc -P deals with the “history stack”
  • “fc -p” clears out the current history and starts with a new one, until you run fc -P, which will restore the old history again
  • You can use that to “bind” certain histories to specific directories.

Top 10 commands

Check your history for most frequently used commands and create aliases/functions for them (AKA top10):

% print -l -- ${(o)history%% *} | uniq -c | sort -nr | head -n 10

Text replacing

% mkdir -p /tmp/linux-2.6.3{8,9}/demo
% cd /tmp/linux-2.6.38/demo
% cd 38 <tab>

% echo foo
% ^foo^bar

% echo foo_bar
% echo !$:s/foo/baz/

Suffix aliases

% alias -s txt=vim
% foobar.txt
% alias -s pdf=xpdf
% print.pdf

Grml-zshrc specific stuff

List changelog of a Debian package


In-place mkdir to create directory under cursor or the selected area

% cp file /tmp/doesnotexist/<ctrl-xM>

Create a temporary directory and change cwd to it

% cdt

Directory specific shell configuration with Zsh

See Hint: do you remember the fc section? You can combine the directory specific shell configuration with ‘fc -p $file’!

Smart cd

% which cd
cd () {
        if [[ -f ${1} ]]
                [[ ! -e ${1:h} ]] && return 1
                print "Correcting ${1} to ${1:h}"
                builtin cd ${1:h}
                builtin cd ${1}
% cd /etc/fstab


% vim # ... <ctrl-z>
% echo foobar
% <ctrl-z>


% which sudo-command-line
sudo-command-line () {
        [[ -z $BUFFER ]] && zle up-history
        if [[ $BUFFER != sudo\ * ]]
                BUFFER="sudo $BUFFER"
                CURSOR=$(( CURSOR+5 ))
% gparted /dev/sda <ctrl-o s>

Fast directory switching

% cd -<tab>

check out “dirstack handling” in grml-zshrc for persistent directory stack feature

Speed up typing

Long versionShort version
for i in $(seq 2 9); do echo $i ; donefor i in {2..9}; echo $i
ls $(which vim)ls =vim
cat bar baz $PIPECHAR sortsort <b{ar,az}
ls /usr/share/doc/mutt/examplesls /u/s/d/m/e<tab>
gzip -cd foo.gz && less fooless <(gzip -cd foo.gz)
ls >file1; ls >file2; ls >file3ls >file1 >file2 >file3
-less <file1 <file2
-diff <(sort foo) <(sort bar)
-xpdf =(zcat ~doc/grml-docs/zsh/grml-zsh-refcard.pdf.gz)


  1. Q: How to I get a listing of all my currently in use options?


      setopt ksh_option_print && setopt
      printf '%s=%s\n' "${(@kv)options}"
  2. Q: Why do I get “zsh: command not found:” even though I just installed the program?

    Answer: execute:

    % rehash

    or use completion system as provided by grml-zshrc (completion will rehash automatically).

  3. Q: What’s this strange word splitting thing?

    Answer: see

    % var="foo bar"
    % args() { echo $#; }
    % args $var
    % setopt shwordsplit
    % args $var

Important Resources

  1. Zsh Homepage:
  2. Zsh Wiki:
  3. Zsh Manpages: man zshall
  4. Zsh Reference Card:
  5. User’s Guide to ZSH: (old but still interesting)
  6. Zsh Talk by caphuso:
  7. English Book:
  8. German Book:
  9. Grml’s Zsh stuff:


Thanks to Frank Terbeck for reviewing and his valuable feedback (which isn’t limited to this document :)).


(c) 2011 by Michael Prokop <>


Demo of hot stuff in the Zsh






No releases published


No packages published