The Zsh Pony
July 29, 2011 · View on GitHub
-
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
- 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
- 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
bindkeyto get a listing of currently active keybindings Notes:
- ^ := ctrl
- ^[ := esc
** Get emacs-like keybindings
Zsh defaults to vi keybindings ('bindkey -v') if 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
%
- It's what readline is for bash (move, delete, copy words/lines/...)
- 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
- 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 <esc-e>
#+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 matchesfoo'. #+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/<ctrl-xM>
#+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:h} ]] && return 1
print "Correcting {1:h}"
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 (( 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 i ; done | for i in {2..9}; echo (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
- 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
- Zsh Homepage: http://zsh.sourceforge.net/
- Zsh Wiki: http://zshwiki.org
- Zsh Manpages: man zshall
- Zsh Reference Card: http://www.bash2zsh.com/zsh_refcard/refcard.pdf
- User's Guide to ZSH: http://zsh.sourceforge.net/Guide/ (old but still interesting)
- Zsh Talk by caphuso: http://ft.bewatermyfriend.org/comp/zshtalk.html
- English Book: http://www.bash2zsh.com/
- German Book: http://zshbuch.org/
- 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 :)).
- Copyright (c) 2011 by Michael Prokop mika@grml.org