Project Awesome project awesome

ZSH > zsh-pony

Covers customizing ZSH without a framework.

Package 189 stars GitHub

The Zsh Pony

  • Preface

    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.

  • Grml-zshrc Grab a fully featured Zsh configuration:

#+BEGIN_EXAMPLE % wget -O .zshrc http://git.grml.org/f/grml-etc-core/etc/zsh/zshrc #+END_EXAMPLE

  • Switching directories for lazy people

#+BEGIN_EXAMPLE % setopt autocd && /tmp #+END_EXAMPLE

  • Share history file amongst all Zsh sessions, ignoring dupes

#+BEGIN_EXAMPLE % setopt append_history share_history histignorealldups #+END_EXAMPLE

  • Option Setting in Zsh, AKA setopt*

#+BEGIN_EXAMPLE % setopt $OPTION % man zshoptions #+END_EXAMPLE

  • Replace spaces in filenames with a underline

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

  • Fast Manpage access

#+BEGIN_EXAMPLE % autoload run-help % echo foo | xargs

and then:

% git commit

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

% g co #+END_EXAMPLE

  • Completion System ** Enable completion

#+BEGIN_EXAMPLE % autoload compinit && compinit % kill c % man z % dpkg -L #+END_EXAMPLE ** Menu Selection #+BEGIN_EXAMPLE % zstyle ':completion:*' menu select #+END_EXAMPLE

Layout is :completion:FUNCTION:COMPLETER:COMMAND-OR-MAGIC-CONTEXT:ARGUMENT:TAG

Tip: Get completion help running 'ctrl-x h'. ** Use colors in completion #+BEGIN_EXAMPLE zstyle ':completion:*:default' list-colors ${(s.:.)LS_COLORS} #+END_EXAMPLE ** Pick item but stay in the menu #+BEGIN_EXAMPLE % bindkey -M menuselect "+" accept-and-menu-complete % ls + #+END_EXAMPLE

  • Globbing / Glob Qualifiers Makes find(1) useless for many jobs.

#+BEGIN_EXAMPLE % 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 #+END_EXAMPLE

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

#+BEGIN_EXAMPLE % ls *(e:'file $REPLY | grep -q JPEG':) #+END_EXAMPLE

  • (#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. #+END_EXAMPLE

  • Keybindings ** Run bindkey to get a listing of currently active keybindings Notes:
  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 " to find out which action is bount to a key ** Some interesting keybindings | Keybinding | Meaning | |------------+--------------------------------------------------------------------| | ctrl-d | complete + EOF | | ctrl-l | clear screen | | ctrl-w | delete last word | | ctrl-_ | undo | | tab | complete and take first result | | esc-. | insert last parameter of last typed command (similar to typing !$) | | ctrl-a | begin of line | | ctrl-e | end of line | | alt-' | quote-line ('') | | alt-? | which-command | | ctrl-k | kill line | | ctrl-u | kill while line (kill-ring) | | ctrl-w | copy last word (kill-ring) | | ctrl-y | yank (insert kill-ring) | | esc-q | push line | ** Remove last part from directory name

#+BEGIN_EXAMPLE % 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. #+END_EXAMPLE ** Keybindings {up,down}-line-or-search and history-beginning-search-{backward,forward}-end #+BEGIN_EXAMPLE % echo 123 % echo 234 % ls and then: % echo <cursor-up|down> vs. % echo 2<page-up|down> #+END_EXAMPLE ** Incremental search with history-incremental-pattern-search-backward: #+BEGIN_EXAMPLE % scp*r #+END_EXAMPLE ** 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:

#+BEGIN_EXAMPLE % foobar() { LBUFFER="foobar $LBUFFER"; } # function % zle -N foobar # declare function as bindable widget % bindkey '^x^s' foobar # bind command to a keybinding #+END_EXAMPLE 3) ctrl-x-z provides help_zle_parse_keybindings in grml-zshrc ** Edit command line in editor #+BEGIN_EXAMPLE % autoload edit-command-line && zle -N edit-command-line % bindkey '\ee' edit-command-line % $SOME_COMMAND_LINE #+END_EXAMPLE ** Insert a timestamp on the command line (yyyy-mm-dd) #+BEGIN_EXAMPLE insert-datestamp() { LBUFFER+=${(%):-'%D{%Y-%m-%d}'}; } zle -N insert-datestamp bindkey '^Ed' insert-datestamp #+END_EXAMPLE ** Insert last typed word #+BEGIN_EXAMPLE % insert-last-typed-word() { zle insert-last-word -- 0 -1 }; % zle -N insert-last-typed-word; % bindkey "\em" insert-last-typed-word % mv foobar #+END_EXAMPLE ** Complete word from history with menu #+BEGIN_EXAMPLE % zle -C hist-complete complete-word _generic % zstyle ':completion:hist-complete:*' completer _history % bindkey "^X^X" hist-complete #+END_EXAMPLE

  • Loadable modules ** Play tetris

#+BEGIN_EXAMPLE % autoload -U tetris % tetris #+END_EXAMPLE ** URL quoting #+BEGIN_EXAMPLE % autoload -U url-quote-magic % zle -N self-insert url-quote-magic #+END_EXAMPLE Disclaimer: annoying when using e.g. http://example.org/foo{1,2,3}.tgz

  • Prompt

#+BEGIN_EXAMPLE % autoload -U promptinit % promptinit % prompt fire % prompt #+END_EXAMPLE ** 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) #+BEGIN_EXAMPLE precmd () { RPROMPT="%(?..:()%" } #+END_EXAMPLE

  • Get VCS information into your prompt - vcs_info

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

  • Hashed directories

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

  • On-the-fly editing of variables

#+BEGIN_EXAMPLE % vared PATH #+END_EXAMPLE

  • History Supports csh style bang history expansion.

#+BEGIN_EXAMPLE % 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'. #+END_EXAMPLE

...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

  • 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):

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

  • Text replacing

#+BEGIN_EXAMPLE % mkdir -p /tmp/linux-2.6.3{8,9}/demo % cd /tmp/linux-2.6.38/demo % cd 38

% echo foo % ^foo^bar

% echo foo_bar % echo !$:s/foo/baz/ #+END_EXAMPLE

  • Suffix aliases

#+BEGIN_EXAMPLE % alias -s txt=vim % foobar.txt % alias -s pdf=xpdf % print.pdf #+END_EXAMPLE

  • Grml-zshrc specific stuff ** List changelog of a Debian package

#+BEGIN_EXAMPLE % dchange $DEBIAN_PACKAGE #+END_EXAMPLE ** In-place mkdir to create directory under cursor or the selected area #+BEGIN_EXAMPLE % cp file /tmp/doesnotexist/ #+END_EXAMPLE ** Create a temporary directory and change cwd to it #+BEGIN_EXAMPLE % cdt #+END_EXAMPLE ** Directory specific shell configuration with Zsh See http://michael-prokop.at/blog/2009/05/30/directory-specific-shell-configuration-with-zsh/ Hint: do you remember the fc section? You can combine the directory specific shell configuration with 'fc -p $file'! ** Smart cd #+BEGIN_EXAMPLE % which cd cd () { if [[ -f ${1} ]] then [[ ! -e ${1:h} ]] && return 1 print "Correcting ${1} to ${1:h}" builtin cd ${1:h} else builtin cd ${1} fi } % cd /etc/fstab #+END_EXAMPLE ** grml-zsh-fg #+BEGIN_EXAMPLE % vim # ... % echo foobar % #+END_EXAMPLE ** sudo-command-line #+BEGIN_EXAMPLE % which sudo-command-line sudo-command-line () { [[ -z $BUFFER ]] && zle up-history if [[ $BUFFER != sudo\ * ]] then BUFFER="sudo $BUFFER" CURSOR=$(( CURSOR+5 )) fi } % gparted /dev/sda #+END_EXAMPLE

  • Fast directory switching

#+BEGIN_EXAMPLE % cd - #+END_EXAMPLE ** check out "dirstack handling" in grml-zshrc for persistent directory stack feature

  • Speed up typing | Long version | Short version | |----------------------------------------+---------------------------------------------------------| | for i in $(seq 2 9); do echo $i ; done | for i in {2..9}; echo $i | | ls $(which vim) | ls =vim | | cat bar baz $PIPECHAR sort | sort <b{ar,az} | | ls /usr/share/doc/mutt/examples | ls /u/s/d/m/e | | gzip -cd foo.gz && less foo | less <(gzip -cd foo.gz) | | ls >file1; ls >file2; ls >file3 | ls >file1 >file2 >file3 | | - | less <file1 <file2 | | - | diff <(sort foo) <(sort bar) | | - | xpdf =(zcat ~doc/grml-docs/zsh/grml-zsh-refcard.pdf.gz) |

#+END_EXAMPLE

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

Answer: #+BEGIN_EXAMPLE setopt ksh_option_print && setopt

or:

printf '%s=%s\n' "${(@kv)options}" #+END_EXAMPLE 2) Q: Why do I get "zsh: command not found:" even though I just installed the program?

Answer: execute: #+BEGIN_EXAMPLE % rehash #+END_EXAMPLE or use completion system as provided by grml-zshrc (completion will rehash automatically). 3) Q: What's this strange word splitting thing?

Answer: see http://zsh.sourceforge.net/FAQ/zshfaq03.html #+BEGIN_EXAMPLE % var="foo bar" % args() { echo $#; } % args $var 1 % setopt shwordsplit % args $var 2 #+END_EXAMPLE

  • Important Resources
  1. Zsh Homepage: http://zsh.sourceforge.net/
  2. Zsh Wiki: http://zshwiki.org
  3. Zsh Manpages: man zshall
  4. Zsh Reference Card: http://www.bash2zsh.com/zsh_refcard/refcard.pdf
  5. User's Guide to ZSH: http://zsh.sourceforge.net/Guide/ (old but still interesting)
  6. Zsh Talk by caphuso: http://ft.bewatermyfriend.org/comp/zshtalk.html
  7. English Book: http://www.bash2zsh.com/
  8. German Book: http://zshbuch.org/
  9. Grml's Zsh stuff: http://grml.org/zsh/
  • Credits

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

Back to Terminals Are Sexy