man zsh-lovers (Commandes) - tips, tricks and examples for the Z shell
NAME
zsh-lovers - tips, tricks and examples for the Z shell
OVERVIEW
Whenever we look at the zsh manual we wonder why there are no examples for those simply things in (shell) life. The zsh contains many features, but there was no manpage with some examples (like procmailex(5)). That's why we wrote this manpage.
Most of the tricks and oneliner come from the mailinglists zsh-users, zsh-workers, google, newsgroups and from ourself. See section LINKS for details.
Note: This manpage (zsh-lovers(1)) is not an offical part of the Z shell! It's just a just for fun - manpage ;) For comments, bugreports and feedback take a quick look at the section BUGS.
EXAMPLES
REDIRECTION
See also man 1 zshmisc.
null command shorthands:
"< file" is like "$READNULLCMD <file" "> file" is like "cat >file" ">> file" is like "cat >>file"
Append `exit 1' at the end of all *.sh - files:
$ echo "exit 1" >> *.sh
Append /etc/services at the end of file `foo' and `bar':
$ cat /etc/services >> foo >> bar
Pipe STDERR:
$ echo An error >&2 2>&1 | sed -e 's/A/I/'
MULTIPLE I/O REDIRECTION
Requires setopt multios! Some examples:
Print output of 'ls' into files 'foo' and 'bar':
$ ls >foo >bar
Send standard output of one process to standard input of several processes in the pipeline:
$ process1 > >(process1) > >(process2)
Redirection to file as well as send on to pipe:
$ make install > /tmp/logfile | grep -i error
Redirect stderr to a command like xless without redirecting stdout as well:
$ foo 2>>(xless) ... but this executes the command asynchronously. To do it synchronously:$ { { foo 1>&3 } 2>&1 | xless } 3>&1
Redirect stderr two times:
$ setopt multios ; program 2> file2 > file1 2>&1
More fun with stderr:
$ ./my-script.sh 2> >(grep -v geek >error.log) | process-output > output.log echo "Thats STDOUT" >>(sed 's/stdout/another example/' > foobar)
MODIFIERS USAGE
Modifiers are a powerful mechanism that lets you modify the results returned by parameter, filename and history expansion. See zshexpn(1) for details. Remove a trailing pathname component, leaving the head. This works like `dirname':
$ echo =ls(:h) /binRemove all leading pathname components, leaving the tail. This works like `basename'.
$ echo =ls(:t) lsRemove a filename extension of the form `.xxx', leaving the root name.
$ echo $PWD /usr/src/linux $ echo $PWD:t linuxRemove all but the extension.
$ foo=23.42 $ echo $foo 23.42 $ echo $foo:e 42Print the new command but do not execute it. Only works with history expansion.
$ echo =ls(:h) /bin $ !echo:p $ echo =ls(:h)Quote the substituted words, escaping further substitutions.
$ bar="23'42" $ echo $bar 23'42 $ echo $bar:q 23'42Convert the words to all lowercase.
$ bar=FOOBAR $ echo $bar FOOBAR $ echo $bar:l foobarConvert the words to all uppercase.
$ bar=foobar $ echo $bar foobar $ echo $bar:u FOOBARVariables can be modified by modifiers, too. That makes modification of variables possible without using any external program.
sentence="beginning and some words of a sentence with end."Now lets split this sentence-var by using the (s| |) modifier which modifies words by splitting at " ":
words=${(s| |)sentence} print $words[1] -> "beginning" print $words[-1] ->"end."Now if one wants to have the beginning of a sentence with a Capital, it's as easy as doing:
print "${(C)words[1]} $words[2,-1]"which capitalizes the first word of the list words and then adds with " " second to last word of words. It's possible to join these words as a colon separated scalar.
colonlist=${(j|,|)words} # (j|,|) joins with ",".You can see that it's a scalar by testing with (t):
print ${(t)colonlist} prints "scalar". print ${(t)words} prints "array".It's possible to sort arrays with o and O:
print ${(o)words} # lists the words-array sorted (forwards) print ${(O)words} # lists the words-array sorted (backwards)
COMPLETITION
See also man 1 zshcompctl zshcompsys zshcompwid. zshcompctl is the old style of zsh programmable completion, zshcompsys is the new completion system, zshcompwid are the zsh completion widgets. Some functions, like _apt and _dpkg, are very slow. You can use a cache in order to proxy the list of results (like the list of available debian packages) Use a cache:
zstyle ':completion:*' use-cache on zstyle ':completion:*' cache-path ~/.zsh/cachePrevent CVS files/directories from being completed :
zstyle ':completion:*:(all-|)files' ignored-patterns '(|*/)CVS' zstyle ':completion:*:cd:*' ignored-patterns '(*/)#CVS'
Fuzzy matching of completions for when you mistype them:
zstyle ':completion:*' completer _complete _match _approximate zstyle ':completion:*:match:*' original only zstyle ':completion:*:approximate:*' max-errors 1 numeric
And if you want the number of errors allowed by _approximate to increase with the length of what you have typed so far:
zstyle -e ':completion:*:approximate:*' max-errors 'reply=( $(( ($#PREFIX+$#SUFFIX)/3 )) numeric )'
Ignore completion functions for commands you don't have:
zstyle ':completion:*:functions' ignored-patterns '_*'
With helper functions like:
xdvi() { command xdvi ${*:-*.dvi(om[1])} }you can avoid having to complete at all in many cases, but if you do, you might want to fall into menu selection immediately and to have the words sorted by time:
zstyle ':completion:*:*:xdvi:*' menu yes select zstyle ':completion:*:*:xdvi:*' file-sort time
Completing process IDs with menu selection:
zstyle ':completion:*:*:kill:*' menu yes select zstyle ':completion:*:kill:*' force-list always
If you end up using a directory as argument, this will remove the trailing slash (usefull in ln)
zstyle ':completion:*' squeeze-slashes true
cd will never select the parent directory (e.g.: cd ../<TAB>):
zstyle ':completion:*:cd:*' ignore-parents parent pwd
ADVANCED GLOBBING
See man zshexpn | less -p 'Glob Qualifiers'
List file 'foobar' via recursiv search in directories:
$ ls **/foobar
List files file20, file30, file100, etc:
$ ls file<20->
List files with suffix c and pro (e.g. foo.c, bar.pro):
$ ls *.(c|pro)
List files which are word-readable:
$ ls *(R)
List all .c-files except 'lex.c':
$ ls *.c~lex.c
List all `README' - files case-insensitive with max. one typo (e.g. RADME, REEME, RAEDME):
$ ls (#a1)README
List files named README but accept one spelling error including case-insensitive (e.g. RADME, REEME, RAEDME):
$ ls (#ia1)README
List executable files, directories and symlinks:
$ ls *(*@)
List dangling symlinks:
$ ls **/*(-@)
List all zero-length-files which are not group- or world-writable:
$ ls *(L0f.go-w.)
List all .c-files for which there doesn't exist a .o file:
$ c=(*.c) o=(*.o(N)) eval 'ls ${${c:#(${~${(j:|:)${o:r}}}).c}:?done}'
Find (and print) all symbolic links without a target within the current dirtree:
$ file **/*(D@) | fgrep broken $ for i in **/*(D@); [[ -f $i || -d $i ]] || echo $i $ echo **/*(@-^./=%p) $ print -l **/*(-@)
Rename all MP3-files from name with spaces.mp3 to Name With Spaces.mp3:
$ for i in *.mp3; do mv $i ${${(C)i}:s/Mp3/mp3/} done
Rename all PDF-files from name.mp3 to Name.mp3 (lowercase to uppercase of first letter) without touching the rest of the filename:
$ zmv '([a-z])(*).pdf' '${(C)1}$2.pdf'
Substitutions in strings can be done by string-indexes:
$ a="doh.";a[1]='d';a[-1]='. (Bart Simpson)' $ echo $a doh. (Bart Simpson)
Associative arrays:
$ typeset -A ass_array; ass_array=(one 1 two 2 three 3 four 4) $ print ${(k)ass_array} # prints keys one four two three $ print ${(v)ass_array} # prints values 1 4 2 3 $ print $ass_array[one] 1
Extract parts of a string. Print first word of output of 'date':
$ print ${$( date )[1]}
Extract parts of a string. Print ip-address of loopback device:
$ print ${${$( LC_ALL=C /sbin/ifconfig lo )[6]}#addr:}
Print specific line of a file. E.g. print line 5 of file:
$ print -l ${"$( < file )"[(f)5]}
Print line containing string 'root' of file /etc/passwd:
$ print ${"$( < /etc/passwd )"[(fr)*root*]}
Print words two to four of output of 'date':
$ print ${$( date )[2,4]}
Use of two-dimensional indizes. Print time via date but without seconds:
$ print ${$(date)[4][1,5]}
Calculate floating point numbers:
$ printf "%.0fn" $[ 2.8*15 ]
Convert images from foo.gif to foo.png:
$ for i in **/*.gif; convert $i $i:r.png
Download files created with LaTeX2HTML (e.g. the ZSH-Guide):
$ for f in http://zsh.sunsite.dk/Guide/zshguide{,{01..08}}.html; do lynx -source $f >${f:t} done
Make with dpkg a master-list of everyfile that it has installed:
$ diff <(find / | sort) <(cat /var/lib/dpkg/info/*.list | sort)
Replace this color escape-sequences:
$ autoload colors ; colors $ print "$bg[cyan]$fg[blue]Welcome to man zsh-lovers" >> $TTY
Get ASCII value of a character:
$ char=N ; print $((#char))
Filename suffix. Note: (N) activates setopt nullglob only for this loop.
$ for i in *.o(N); do
rm $i
done
Rename files: 'FOO' to 'foo':
$ for i in *(.); mv $i ${i:l}
Rename files: 'bar' to 'BAR':
$ for i in *(.); mv $i ${i:u}
Show all suid-files in $PATH:
$ ls -latg ${(s.:.)PATH} | grep '^...s'
ZMV - multiple move with zsh
Requires 'autoload zmv'. Some examples:
Move serially all files (foo.foo > 1.foo, fnord.foo > 2.foo, ..).
$ ls * 1.c asd.foo bla.foo fnord.foo foo.fnord foo.foo $ c=1 zmv '*.foo' '$((c++)).foo' $ ls * 1.c 1.foo 2.foo 3.foo 4.foo foo.fnord
See above, but now only files with a filename >= 30 chars.
$ c=1 zmv "${(l:30-4::?:)}*.foo" '$((c++)).foo'
Replace spaces in filenames with a underline.
$ zmv '* *' '$f:gs/ /_'
Change the suffix from *.sh to *.pl.
$ zmv -W '*.sh' '*.pl'
Lowercase/uppercase all files and directories.
$ zmv '(*)' '${(L)1}' for lowercase $ zmv '(*)' '${(U)1}' for uppercase
Remove the suffix *.c from all c-files.
$ zmv '(*).c' '$1'
Uppercase only the first letter of all *.mp3 - files.
$ zmv '([a-z])(*).mp3' '${(C)1}$2.mp3'
Copy the target `README' in same directory as each `Makefile'.
$ zmv -C '(**/)Makefile' '${1}README'
Rename pic1.jpg, pic2.jpg,.. to pic0001.jpg, pic0002.jpg,...
$ zmv 'pic(*).jpg' 'pic${(l:4::0:)1}.jpg' $ zmv '(**/)pic(*).jpg' '$1/pic${(l:4::0:)2}.jpg' # recursive
MODULES
See also man zshmodules. Don't forget to run zmodload -i MODULENAME before using a module. Example: zmodload -i zsh/datetime.
- zsh/cap
- Builtins for manipulating POSIX.1e (POSIX.6) capability (privilege) sets.
- zsh/clone
- A builtin that can clone a running shell onto another terminal.
Creates a forked instance of the current shell ($! is set to zero) and
execute ``command'' on /dev/tty8 (for this example):
$ zmodload zsh/clone $ clone /dev/tty8 && (($! == 0)) && exec command
- zsh/compctl
- The compctl builtin for controlling completion.
- zsh/complete
- The basic completion code.
- zsh/complist
- Completion listing extensions.
- zsh/computil
- A module with utility builtins needed for the shell function based completion system.
- zsh/datetime
- Some date/time commands and parameters.
Do not have GNU date? Let's replace it:
$ alias datereplacement='strftime "%Y-%m-%d" $EPOCHSECONDS' $ export DATE=`datereplacement` $ echo $DATE
- zsh/deltochar
- A ZLE function duplicating EMACS' zap-to-char.
- zsh/example
- An example of how to write a module.
- zsh/files
- Some basic file manipulation commands as builtins.
# search a directory for files containing a certain string then copy those files to another directory. $ IFS=$'0' $ cp $(grep -lZr foobar .) otherdirectory
- zsh/mapfile
- Access to external files via a special associative array.
# grepping for two patterns $ pattern1="foo" $ pattern2="bar foo" $ print -l ./**/*(DN.e{'z=$mapfile[$REPLY] && [[ $z = *$pattern1* && $z = *$pattern2* ]]'}) # or a solution in combination with zsh/pcre $ zmodload -i zsh/mapfile zsh/pcre $ pattern1="foo" $ pattern2="bar foo" $ pcre_compile "(?s)(?=.*?$pattern1).*?$pattern2" $ pcre_study $ print -l ./**/*(DN.e{'pcre_match $mapfile[$REPLY]'})
# equivalent for ``less /etc/passwd | grep -v root'' $ IFS=$'nn' $ print -rl -- ${${=mapfile[/etc/passwd]}:#*root*} # or - for case insensitive $ setopt extendedglob $ print -rl -- ${${=mapfile[/etc/passwd]}:#*(#i)root*}
# If a XML-file contains stuff like ``<TAGA/>'' and ``<TAGB/>'', number this empty tags # (ones ending in '/>') so if encountered in the same order, the preceeding tags would become # ``<TAGA/>1</TAGA>'' and ``<TAGB/>2</TAGB>'' $ cnt=0 $ apfile[data.xml.new]=${(S)mapfile[data.xml]// > (#im)<TAGA>*</TAGA>/<TAGA>$((++cnt))</TAGA>}
# removing all files in users Maildir/new that contain ``filename="gone.src'' $ zmodload zsh/{files,mapfile} $ rm -f /u1/??/*/Maildir/new/100*(.e{'[[ $mapfile[$REPLY] == *filename=
# Grep out the Title from a postscript file and append that value to the end of # the filename $ autoload -U zmv $ zmv '(*).ps' '$1-${${${mapfile[$f]##*%%Title: }%% *}//[^a-zA-Z0-9_]/}.ps'
- zsh/mathfunc
- Standard scientific functions for use in mathematical evaluations.
$ echo $(( sin(1/4.0)**2 + cos(1/4.0)**2 - 1 )) -1.1102230246251565e-16 $ echo $(( pi = 4.0 * atan(1.0) )) 3.1415926535897931 $ echo $(( f = sin(0.3) )) 0.29552020666133955 $ print $(( rand48(seed) )) 0.01043488334700271
- zsh/parameter
- Access to internal hash tables via special associative arrays.
- zsh/pcre
- Interface to the PCRE library.
Important: requires zsh compiled with pcre-support. Check
whether your version supports pcre via `ldd =zsh | grep
pcre`.
PCRE provides support for Perl's regular expressions (regex). You
have to compile a regex and can match it afterwards using
error codes:
$ zmodload zsh/pcre $ pcre_compile '\s\d.\d{3}.\d{3} Euro' &&\ pcre_match ' 1.000.000 Euro' &&\ echo "matches" || echo "does not match"
Note: if you are using complex regular expressions you can improve speed via pcre_study. - zsh/sched
- A builtin that provides a timed execution facility within the shell.
- zsh/net/socket
- Manipulation of Unix domain sockets
$ zmodload zsh/net/socket
$ zsocket -l -d 3
# ``-l'': open a socket listening on filename
# ``-d'': argument will be taken as the target file descriptor for the
# connection
# ``3'' : file descriptor. See ``A User's Guide to the Z-Shell''
# (3.7.2: File descriptors)
$ zsocket -a -d 4 3
# ``-a'': accept an incoming connection to the socket
$ zsocket -a -d 5 3 # accept a connection
$ echo foobar >&4
$ echo barfoo >&5
$ 4>&- 5>&- 3>&-
In one shell:
$ zmodload zsh/net/socket $ zsocket -l -d 3 /tmp/mysocket # open listening socket $ zsocket -a -d 4 3 # accept a connection $ zsocket -a -d 5 3 # accept a connection $ echo Hi there >&4 $ echo Hi there also >&5 $ exec 4>&- 5>&- 3>&-
In another shell:$ zmodload zsh/net/socket $ zsocket -d 3 /tmp/mysocket # connect to /tmp/socket $ zsocket -d 4 /tmp/mysocket # connect to /tmp/socket $ read msg <&3; echo got: "$msg on fd 3" $ read msg <&4; echo got: "$msg on fd 4" $ exec 3>&- 4>&-
- zsh/stat
- A builtin command interface to the stat system call.
Get size of a file in bytes:
$ zmodload -i zsh/stat $ stat -L +size file
Equal to GNU's:$ stat -c %s file
Comparing file dates:$ file1=foo $ file2=bar $ touch bar & sleep 5 & touch foo $ echo $file1 is $(( $(stat +mtime $file2) - $(stat +mtime $file1) )) seconds older than $file2. bar is 5 seconds older than foo
List the files of a disk smaller than some other file:$ stat -A max +size some-other-file $ print -rl ./**/*(D.L-$max)
List the top 100 biggest files in a disk:$ ls -fld ./**/*(d`stat +device .`OL[1,100])
Get only the user name and the file names from (like ls -l * | awk '{print $3" " $8}'):$ for file; do > stat -sA user +uid -- "$file" && > print -r -- "$user" "$file" > done
Get the difference between actual bytes of file and allocated bytes of file:$ print $(($(stat +block -- file) * 512 - $(stat +size -- file)))
Find largest file:$ stat +size ./*(DOL[1]) # ``D'' : to include dot files (d lowercase is for device) # ``O'' : reverse Ordered (o lowercase for non-reverse order) # ``L'' : by file Length (l is for number of links) # ``[1]'': return only first one
Delete files in a directory that hasn't been accessed in the last ten days and send ONE mail to the owner of the files informing him/her of the files' deletion:$ zmodload zsh/stat zsh/files $ typeset -A f; f=() $ rm -f /path/**/*(.a+10e{'stat -sA u +uidr $REPLY; f[$u]="$f[$u]$REPLY"'}) $ for user (${(k)f}) {print -rn $f[$user]|mailx -s "..." $user}
Get a "ls -l" on all the files in the tree that are younger than a specified age:$ for d (. ./**/*(N/m-2)) > print -r -- $'n'$d: && cd $d && { > for f (*(Nm-2om)) > stat -F '%b %d %H:%M' -LsAs -- $f && > print -r -- $s[3] ${(l:4:)s[4]} ${(l:8:)s[5]} \ > ${(l:8:)s[6]} ${(l:8:)s[8]} $s[10] $f ${s[14]:+-> $s[14]} > cd ~- > }
Get file creation date:$ stat -F '%d %m %Y' +mtime ~/.zshrc 30 06 2004 $ stat -F '%D' +mtime ~/.zshrc 06/30/04
- zsh/system
- A builtin interface to various low-level system features.
- zsh/net/tcp
- Manipulation of TCP sockets
- zsh/termcap
- Interface to the termcap database.
$ zmodload -ab zsh/termcap echotc $ GREEN=`echotc AF 2` $ YELLOW=`echotc AF 3` $ RED=`echotc AF 1` $ BRIGHTRED=`echotc md ; echotc AF 1` $ print -l ${GREEN}green ${YELLOW}yellow ${RED}red ${BRIGHTRED}brightred
- zsh/terminfo
- Interface to the terminfo database.
- zsh/zftp
- A builtin FTP client.
Write ftp scripts as though shell:
$ init $ autoload -U zfinit && zfinit $ zfparams www.example.invalid myuserid mypassword $ zfopen $ zfcd tips $ zfls -l zsh-lovers.html $ zfput zsh-lovers.html $ zfls -l zsh-lovers.html
Automatically transfer files using FTP with error checking:$ zftp open host.name.invalid user passwd || exit $ zftp get /remote/file > /local/file; r=$? $ zftp close && exit r
Compress and ftp on the fly:$ zftp open host.name.invalid user password $ zftp get $file | bzip2 > ${file}.bz2 $ zftp close
Long list of files on a ftp:$ autoload -U zfinit $ zfinit $ zfopen some-host $ zfcd /some/remote/Dir $ cd /some/local/Dir
If the list.txt is located on the remote host, change to $ zfget ${(f)"$(zftp get /path/to/remote/list.txt)"} $ zfget ${(f)"$(cat list.txt)"} $ zfclose - zsh/zle
- The Zsh Line Editor, including the bindkey and vared builtins.
- zsh/zleparameter
- Access to internals of the Zsh Line Editor via parameters.
- zsh/zprof
- A module allowing profiling for shell functions.
- zsh/zpty
- A builtin for starting a command in a pseudo-terminal.
$ zmodload -i zsh/zpty $ zpty PW passwd $1 # ``-r'': read the output of the command name. # ``z'' : Parameter $ zpty -r PW z '*password:' # send the to command name the given strings as input $ zpty -w PW $2 $ zpty -r PW z '*password:' $ zpty -w PW $2 # | The second form, with the -d option, is used to delete commands # | previously started, by supplying a list of their names. If no names # | are given, all commands are deleted. Deleting a command causes the HUP # | signal to be sent to the corresponding process. $ zpty -d PW
- zsh/zselect
- Block and return when file descriptors are ready.
# It's simular to ,---- | $ sg=$(stty -g) | $ stty -icanon min 0 time 50 | $ read yesno | $ stty "$sg" | $ case "$yesno" in | > yes) command1;; | > *) command2;; | > esac `---- $ if zselect -t 500 -r 0 && read yesno && [ yes = "$yesno" ]; then > command1 > else > command1 > fi
- zsh/zutil
- Some utility builtins, e.g. the one for supporting configuration via styles.
SUBSTITUTION
Path substitution:
$ ls -l =zsh # is like: 'ls -l /path/to/zsh' or 'ls -l `which zsh`'
Process substitution:
$ (vi =(cmd)) # edit output of 'cmd' (called process substitution).
Substitution of variables:
$ var1=42 $ tmp=var1 $ echo $((tmp)) 42 $
$ var=foo $ tmp=var $ echo ${(P)tmp} foo
ALIASES
Suffix aliases are supported in zsh since version 4.2.0. Some examples:
alias -s tex=vim alias -s html=w3m alias -s org=w3m
Now pressing return-key after entering 'foobar.vim' starts vim with foobar.vim. Calling a html-file runs browser w3m. 'www.zsh.org' and pressing enter starts w3m with argument www.zsh.org.
Global aliases can be used anywhere in the command line. Example:
$ alias -g C='| wc -l' $ grep alias ~/.zsh/* C 443
Some more or less useful global aliases (choose whether they are useful or not for you on your own):
alias -g ...='../..' alias -g ....='../../..' alias -g .....='../../../..' alias -g CA="2>&1 | cat -A" alias -g C='| wc -l' alias -g D="DISPLAY=:0.0" alias -g DN=/dev/null alias -g ED="export DISPLAY=:0.0" alias -g EG='|& egrep' alias -g EH='|& head' alias -g EL='|& less' alias -g ELS='|& less -S' alias -g ETL='|& tail -20' alias -g ET='|& tail' alias -g F=' | fmt -' alias -g G='| egrep' alias -g H='| head' alias -g HL='|& head -20' alias -g §k="*~(*.bz2|*.gz|*.tgz|*.zip|*.z)" alias -g LL="2>&1 | less" alias -g L="| less" alias -g LS='| less -S' alias -g MM='| most' alias -g M='| more' alias -g NE="2> /dev/null" alias -g NS='| sort -n' alias -g NUL="> /dev/null 2>&1" alias -g PIPE='|' alias -g R=' > /c/aaa/tee.txt ' alias -g RNS='| sort -nr' alias -g S='| sort' alias -g TL='| tail -20' alias -g T='| tail' alias -g US='| sort -u' alias -g VM=/var/log/messages alias -g X0G='| xargs -0 egrep' alias -g X0='| xargs -0' alias -g XG='| xargs egrep' alias -g X='| xargs'
Array parameters [array_name=(value1 value2 ... valueN)].
$ stupid=emacs $ echo $stupid[3] a $
SHELL-SCRIPTING
This section provides some examples for often needed shellscript-stuff. Notice that you should not use otherwise most examples won't work. Parse options in shellscripts. Example taken from ZWS by Adam Chodorowski (http://www.chodorowski.com/projects/zws/):
parse_options() { o_port=(-p 9999) o_root=(-r WWW) o_log=(-d ZWS.log)
zparseopts -K -- p:=o_port r:=o_root h=o_help if [[ $? != 0 || "$o_help" != "" ]]; then echo Usage: $(basename "$0") "[-p PORT] [-r DIRECTORY]" exit 1 fi
port=$o_port[2] root=$o_root[2] log=$o_log[2]
if [[ $root[1] != '/' ]]; then root="$PWD/$root"; fi } # now use the function: parse_options $*
MISC-EXAMPLES
Hint: A list of valid glob Qualifiers can be found in zshexpn(1). See ``man 1 zshexpn | less -p'' Qualifiers for details. Load all available modules at startup
$ typeset -U m $ m=() $ for md ($module_path) m=($m $md/**/*(*e:'REPLY=${REPLY#$md/}'::r)) $ zmodload -i $mRename all MP3-Files from ``name with spaces.mp3'' to ``Name With Spaces.mp3'':
$ for i in *.mp3; do > mv $i ${${(C)i}:s/Mp3/mp3/} > doneDownload with LaTeX2HTML created Files (for example the ZSH-Guide):
$ for f in http://zsh.sunsite.dk/Guide/zshguide{,{01..08}}.html; do > lynx -source $f >${f:t} > doneReplace the unreadable Escape-Sequences:
$ autoload colors ; colors $ print "$bg[cyan]$fg[blue]You are an zsh user" >> /dev/pts/3Filename-Expansion. Note: (N) activates setopt nullglob only for this loop.
$ for i in *.o(N); do
> rm $i
> done
Re-linking broken links:
$ for f in ./**/*(-@); do > stat +link -A l $f > (cd $f:h & [[ -e $l.gz ]]) & ln -sf $l.gz $f > doneShow me all the .c files for which there doesn't exist a .o file:
$ c=(*.c) o=(*.o(N)) eval 'ls ${${c:#(${~${(j:|:)${o:r}}}).c}:?done}'
Load all available modules at startup:
$ typeset -U m $ m=() $ for md ($module_path) m=($m $md/**/*(*e:'REPLY=${REPLY#$md/}'::r)) $ zmodload -i $mRename all files within a directory such that their names get a numeral prefix in the default sort order:
$ i=1; for j in *; do mv $j $i.$j; ((i++)); done $ i=1; for f in *; do mv $f $(echo $i| awk '{ printf("%03d", $0)}').$f; ((i++)); done $ integer i=0; for f in *; do mv $f $[i+=1].$f; doneFind (and print) all symbolic links without a target within the current dirtree:
$ $ file **/*(D@) | fgrep broken $ for i in **/*(D@); [[ -f $i || -d $i ]] || echo $i $ echo **/*(@-^./=%p) $ print -l **/*(-@)List all plain files that do not have extensions listed in `fignore':
$ ls **/*~*(${~${(j/|/)fignore}})(.) # see above, but now omit executables $ ls **/*~*(${~${(j/|/)fignore}})(.^*)Print out files that dont have extensions (require setopt extendedglob dotglob):
$ printf '%sn' ^?*.*List files in reverse order sorted by name:
$ print -rl -- *(On) or $ print -rl -- *(^on)Synonymic to ``ps ax | awk '{print $1}''':
$ print -l /proc/*/cwd(:h:t:s/self//)Get the PID of a process (without ``ps'', ``sed'', ``pgrep'', .. (under Linux):
$ pid2 () { > local i > for i in /proc/<->/stat > do > [[ "$(< $i)" = *\((${(j:|:)~@})\)* ]] && echo $i:h:t > done > }for X in 'n' 'o' 'p' 'q' 'r' 's' 't' 'u' 'v' 'w' 'x' 'y'; do ...:
$ for (( i = 36#n; i <= 36#y; i++ )); do > print ${$(([##36]i)):l} > done # or in combination with ``dc'' $ print {$((##n))..$((##y))}P 10P | dc # or with ``eval'' $ eval print '${$(([##36]'{$((36#n))..$((36#y))}')):l}'Foreach in one line of shell:
$ for f (*) print -r -- $fCopy a directory recursively without data/files:
$ dirs=(**/*(/)) $ cd -- $dest_root $ mkdir -p -- $dirs # or without zsh $ find . -type d -exec env d="$dest_root" sh -c ' exec mkdir -p -- "$d/$1"' '{}' '{}' ;If `foo=23'', then print with 10 digit with leading '0':
$ foo=23 $ print ${(r:10::0:)foo}Find the name of all the files in their home directory that have more than 20 characters in their file names:
print -rl $HOME/${(l:20::?:)~:-}*Save arrays:
$ print -r -- ${(qq)m} > $nameoffile # save it $ eval "m=($(cat -- $nameoffile)" # or use $ m=("${(@Q)${(z)"$(cat -- $nameoffile)"}}") # to restore itGet a "ls -l" on all the files in the tree that are younger than a specified age (e.g "ls -l" all the files in the tree that where modified in the last 2 days):
$ ls -tld **/*(m-2)This will give you a listing 1 file perl line (not à la ls -R). Think of an easy way to have a "ls -R" style output with only files newer than 2 day old.
$ for d (. ./**/*(/)) { > print -r -- $'n'${d}: > cd $d && { > l=(*(Nm-2)) > (($#l)) && ls -ltd -- $l > cd ~- > } > }If you also want directories to be included even if their mtime is more than 2 days old:
$ for d (. ./**/*(/)) { > print -r -- $'n'${d}: > cd $d && { > l=(*(N/,m-2)) > (($#l)) && ls -ltd -- $l > cd ~- > } > }And if you want only the directories with mtime < 2 days to be listed:
$ for d (. ./**/*(N/m-2)) { > print -r -- $'n'${d}: > cd $d && { > l=(*(Nm-2)) > (($#l)) && ls -ltd -- $l > cd ~- > } > }Print 42 ``-'':
$ echo ${(l:42::-:)} # or use ``$COLUMS'' $ echo ${(l:$COLUMNS::-:)} # and now with colors (require autoload colors ;colors) $ echo "$bg[red]$fg[black]${(l:42::-:)}"Redirect STDERR to a command like xless without redirecting STDOUT as well:
$ foo 2>>(xless) # but this executes the command asynchronously. To do it synchronously: $ { { foo 1>&3 } 2>&1 | xless } 3>&1Rename all MP3-Files from name with spaces.mp3 to Name With Spaces.mp3:
$ for i in *.mp3; do > mv $i ${${(C)i}:s/Mp3/mp3/} > doneMatch file names containing only digits and ending with .xml (requiresetopt kshglob):
$ ls -l [0-9]##.xml $ ls -l <0->.xmlRemove all "non txt" files:
$ rm ./^*.txtMove 200 files from a directory into another:
$ mv -- *([1,200]) /another/DirConvert images (foo.gif => foo.png):
$ for i in **/*.gif; convert $i $i:r.pngConvert a collection of mp3 files to wave or cdr (e.g. file.wav -> file.mp3):
$ for i (./*.mp3){mpg321 --w - $i > ${i:r}.wav}Download with LaTeX2HTML created Files (for example the ZSH-Guide):
$ for f in http://zsh.sunsite.dk/Guide/zshguide{,{01..08}}.html; do > lynx -source $f >${f:t} > doneMove all files in dir1 and dir2 that have line counts greater than 10 to another directory say "/more10":
$ mv dir[12]/**/*.cr(-.e{'((`wc -l < $REPLY` > 10))'}) /more10Make with dpkg a master-list of everyfile that it has installed:
$ diff <(find / | sort) <(cat /var/lib/dpkg/info/*.list | sort)Replace the unreadable Escape-Sequences:
$ autoload colors ; colors $ print "$bg[cyan]$fg[blue]You are an zsh user" >> /dev/pts/3Get ASCII value of a character:
$ char=N ; print $((#char))Filename suffix: Note: The (N) says to use the nullglob option for this particular glob pattern.
$ for i in *.o(N); do
> rm $i
> done
Rename files; i. e. FOO to foo and bar to BAR:
$ for i in *(.); mv $i ${i:l} # `FOO' to `foo' $ for i in *(.); mv $i ${i:u} # `bar to `BAR'Show all suid-files in $PATH:
$ ls -latg ${(s.:.)PATH} | grep '^...s' # or more complex ;) $ print -l ${^path}/*(Ns,S) # or show only executables with a user given pattern $ print -l ${^path}/*vim*(*N)gzip files when containing a certain string:
$ gzip ${(ps:0:)"$(grep -lZ foobar ./*.txt(.))"}A small one-liner, that reads from stdin and prints to stdout the first unique line i. e. does not print lines that have been printed before (this is similar to the unique command, but unique can only handle adjacent lines):
$ IFS=$'nn'; print -rl -- ${(Oau)${(Oa)$(cat file;echo .)[1,-2]}}Lists every executable in PATH:
$ print -l ${^path}/*(-*N)Match all .c files in all subdirectories, _except_ any SCCS subdirectories?
$ ls **/*.c~(*/)#SCCS/*List all `README' - files case-insensitive with max. one typo:
$ ls **/*(#ia2)readmePrint version information of zsh:
$ print $ZSH_VERSION
Get hostspecific information:
$ echo $MACHTYPE $VENDOR $OSTYPE
Fast change of directories:
alias ...='cd ../..' alias ....='cd ../../..' alias .....='cd ../../../..' alias ......='cd ../../../../..' alias .......='cd ../../../../../..'
Mailpath: simple multiple mailpath:
mailpath=($HOME/Mail/mbox'?new mail in mbox' $HOME/Mail/tux.u-strasbg'?new mail in tux' $HOME/Mail/lilo'?new mail in lilo' $HOME/Mail/ldap-fr'?new mail in ldap-fr')
Mailpath: dynamic mailpath:
typeset -a mailpath for i in ~/Mail/Lists/*(.); do mailpath[$#mailpath+1]="${i}?You have new mail in ${i:t}." done
Avoid globbing on special commands:
for com in alias expr find mattrib mcopy mdir mdel which; alias $com="noglob $com"
For migrating your bashprompt to zsh use the script bash2zshprompt located in the zsh source distribution under 'Misc'.
For migration from (t)csh to zsh use the c2z tool that converts csh aliases and environment and shell variables to zsh. It does this by running csh, and having csh report on aliases and variables. The script then converts these to zsh startup files. It has some issues and usage information that are documented at the top of this script.
Here are functions to set the title and hardstatus of an XTerm or of GNU Screen to 'zsh' and the current directory, respectively, when the prompt is displayed, and to the command name and rest of the command line, respectively, when a command is executed:
function title { if [[ $TERM == "screen" ]]; then # Use these two for GNU Screen: print -nR $'033k'$1$'033'\ print -nR $'033]0;'$2$'a' elif [[ $TERM == "xterm" || $TERM == "rxvt" ]]; then # Use this one instead for XTerms: print -nR $'033]0;'$*$'a' fi }
function precmd { title zsh "$PWD" }
function preexec { emulate -L zsh local -a cmd; cmd=(${(z)1}) title $cmd[1]:t "$cmd[2,-1]" } Put the following line into your ~/.screenrc to see this fancy hardstatus:
caption always "%3n %t%? (%u)%?%?: %h%?"
Special variables which are assigned or you can assign:
$ echo $LINENO $RANDOM $SECONDS $COLUMNS $HISTCHARS $ echo $UID $EUID $GID $EGID $USERNAME $ echo $fignore $mailpath $cdpath
Show me all the .c files for which there doesn't exist a .o file:
$ c=(*.c) o=(*.o(N)) eval 'ls ${${c:#(${~${(j:|:)${o:r}}}).c}:?done}'
Find (and print) all symbolic links without a target within the current dirtree:
$ file **/*(D@) | fgrep broken $ for i in **/*(D@); [[ -f $i || -d $i ]] || echo $i $ echo **/*(@-^./=%p) $ print -l **/*(-@)
Rename files; i. e. FOO to foo and bar to BAR:
$ for i in *(.); mv $i ${i:l} # `FOO' to `foo' $ for i in *(.); mv $i ${i:u} # `bar to `BAR'Show all suid-files in $PATH:
$ ls -latg ${(s.:.)PATH} | grep '^...s'List all `README' - files case-insensitive with max. one typo:
$ ls **/*(#ia2)readme
(RECURSIVE) GLOBBING-EXAMPLES
Search for `README' in all Subdirectories
$ print -l **/READMERecursive ``chmod''
$ chmod 700 **/(.) # Only files $ chmod 700 **/(/) # Only directoriesList files beginning at `foo23' upwards (foo23, foo24, foo25, ..)
$ ls -l foo<23->Remove spaces from filenames
$ for a in ./**/*\ *(Dod); do mv $a ${a:h}/${a:t:gs/ /_}; doneShow only all *.c and *.h - Files
$ ls -l *.(c|h)Show only all *.c - files and ignore `foo.c'
$ ls *.c~foo.cShow only world-readable files
$ ls -l *(R)find and delete the files which are older than a given parameter (seconds/minutes/hours)
# deletes all regular file in /Dir that are older than 3 hours $ rm -f /Dir/**/*(.mh+3) # # deletes all symlinks in /Dir that are older than 3 minutes $ rm -f /Dir/**/*(@mm+3) # deletes all non dirs in /Dir that are older than 30 seconds $ rm -f /Dir/**/*(ms+30^/) # deletes all files more than 6 hours old $ rm -f **/*(mh+6) # deletes all folders, sub-folders and files older than one hour $ rm ./**/*(.Dmh+1,.DL0) # removes all files but the ten newer ones (delete all but last 10 files in a directory) $ rm ./*(Om[1,-11])
Note: If you get a arg list too long, you use the builtin rm. For example: $ zmodload zsh/files ; rm -f **/*(mh+6) or use the zargs function: $ autoload zargs ; zargs **/*(mh+6) -- rm -f Explanation:
./: to avoid problem with files starting with "-" **/: recursively descend *.: any file (...): qualifiers: (<a>,<b>): files of <a> type or <b> type <a>: .: regular files D: including dot files mh+1: whose [m]odification time, is more (+) than [1] [h]our in the past. <b>: .: regular files D: including dot files L0: of 0 [L]ength.If you want to remove empty directories afterwards:
# ``/'' matches only directories and ``od'' sorted in depth order (so # that dir/subdir is removed before directory). $ rmdir ./**/*(/od) 2> /dev/nullNote: If you get a arg list too long, you use the builtin rm. For example:
$ zmodload zsh/files ; rm -f **/*(mh+6)or use the zargs function:
$ autoload zargs ; zargs **/*(mh+6) -- rm -fDelete only the oldest file in a directory:
$ rm ./*filename*(Om[1])Sort the output from `ls -l' by file size:
$ ls -fld *(OL)Find most recent file in a directory:
$ setopt dotglob ; print directory/**/*(om[1])List the top 100 biggest files in a disk
$ zmodload -i zsh/stat ; ls -fld ./**/*(d`stat +device .`OL[1,100])
$ ls *(L0f.go-w.)Find all files without a valid owner:
$ chmod someuser /**/*(D^u:${(j.:u:.)${(f)"$(</etc/passwd)"}%%:*}:)Show only files are owned from group `users':
$ ls -l *(G[users])
ZMV-EXAMPLES
Note: ``autoload zmv'' needed! See ``man zshcontrib | less -p zmv'' for more details. Serially all files (foo.foo > 1.foo, fnord.foo > 2.foo, ..):
$ ls * 1.c asd.foo bla.foo fnord.foo foo.fnord foo.foo $ c=1 zmv '*.foo' '$((c++)).foo' $ ls * 1.c 1.foo 2.foo 3.foo 4.foo foo.fnordSee above, but now only files with a filename >= 30 chars:
$ c=1 zmv "${(l:30-4::?:)}*.foo" '$((c++)).foo'Replace spaces in filenames with a underline:
$ zmv '* *' '$f:gs/ /_'Change the suffix from *.sh to *.pl:
$ zmv -W '*.sh' '*.pl'lowercase/uppercase all files/directories:
# lowercase $ zmv '(*)' '${(L)1}' # uppercase zmv '(*)' '${(U)1}'Remove the suffix *.c from all C-Files:
$ zmv '(*).c' '$1'Uppercase only the first letter of all *.mp3 - files:
$ zmv '([a-z])(*).mp3' '${(C)1}$2.mp3'Copy the target `README' in same directory as each `Makefile':
$ zmv -C '(**/)Makefile' '${1}README'Removing single quote from filenames (recursive):
$ zmv -Q "(**/)(*'*)(D)" "\$1\${2//'/}"Replace spaces with underscores in filenames (recursive):
$ zmv -Q "(**/)(* *)(D)" "\$1\${2// /_}"Rename pic1.jpg, pic2.jpg, .. to pic0001.jpg, pic0002.jpg, ..:
# Not recursively $ zmv 'pic(*).jpg' 'pic${(l:4::0:)1}.jpg' # Recursively $ zmv '(**/)pic(*).jpg' '$1/pic${(l:4::0:)2}.jpg'
TIPS BY ZZAPPER (http://www.rayninfo.co.uk/tips/zshtips.html)
!! # last command !$ # last argument !$:h (last argument, strip one level) !?echo vi !* (all parameters) vi !$ (last parameters) !42 history ^fred^joe # edit previous command replace fred by joe !42:p also use control-R
cmdy !?cmd1?:*<TAB> #get parameters of a previous command
!:0 is the previous command name !^, !:2, !:3, ?, !$ are the arguments !* is all the arguments !-2, !-3, ? are earlier commands !-2^, !-2:2, !-2$, !-2*
cd !$:h (remove file name) cat !!:t (only file name) print ${param:&} (last substitute)
# globbing modifiers # :r removes the suffix from the result, # :t takes away the directory part # . means must be regular files not directories etc # *(om[1]) picks most recently modified file # (.N) no warning message if any file absent print *(om[1]) # print the most recent file print *(.om[1]) # print the most recent file (not directory) ls -l *(Om[1]) # oldest file print *(om[1,5]) # print the 5 most recent files vi *(.om[1]^D) # vi newest file ^D means switch off GLOB_DOTS ls -l *(m4) # list files modified exactly 4 days ago ls -ltd *(mw3) # list files 3 weeks old echo *(m-1) # files modified today echo *(m0) # files modified today rm *.{aux,dvi,log,toc}(.N) # rm latex temp files N means no error msg is any file absent
print *(n:t) # order by name strip directory print **/*(On:t) # recursive reverse order by name, strip directory print *.c(:r) # strip suffix ls **/*(.) # only files no directories -ld *(/) # list only directories FOO = (#i)foo ]] # case insensitive matching #oddities fred=$((6**2 + 6)) # can do maths print ${#path} # length of "path" array print ${#path[1]} # length of first element in path array ls fred{joe,sid}.pl ls fred{09..13}.pl
# arrays array=(~/.zshenv ~/.zshrc ~/.zlogout) % print ${array:t} .zshenv .zshrc .zlogout
x="bu&^*ck" # variable with mucky characters print ${x//[^[:alnum:]]/_} # replace all non-alphanumerics with _
cp file ~1 # where 1 is first entry in pushd stack #zsh completion startfilename<tab> # will complete matching files anywhere in $PATH startfilename<C-D> # will list matching files anywhere in $PATH #directory sizes du -sk *(/)
ls * | grep foo | less #to ls * G foo L #
#magic equals vim =some_file # edits file anywhere in $PATH ls =some_file # lists file anywhere in $PATH #magic ** (recursion) vim **/some_file # edits file under under current dir # modifying more than one file (multios) # writes ls results to file1 & file2 appends to filec ls > file1 > file2 >> file3 | wc
Find file containing string 'printf' in /usr/include.
$ zargs /usr/include/**/*.h -- grep printf /dev/null
A solution without zsh could look like:
$ find /usr/include -name \*.h -exec grep printf /dev/null {} ;
Create a directory structure based on an existing one.
$ dirs=(**/*(/)) $ cd -- $dest_root $ mkdir -p -- $dirs
A solution without zsh could look like:
$ src=/usr/local $ dst=/opt $ cd "$src" $ find . -type d | cpio -pdmv "$dst"
Uncompress file and read it
less <(gzip -cd foo.gz)
A solution without zsh could look like:
$ gzip -cd foo.gz && less foo
Print two files and sort them
$ sort <f{oo,ubar}
A solution without zsh could look like:
$ cat foo fubar | sort
Find files up from current directory and change permissions to '700'.
$ chmod 700 **/*(.)
A solution without zsh could look like:
$ find . -type f -exec chmod 700 {} \;
List details of the executable 'foobar'.
$ ls -l =foobar
A solution without zsh could look like:
$ ls -l `which foobar`
Small examples
'cd old new' replaces 'old' with 'new' in directory-names. 'which -a cmd' lists all occurences of 'cmd' in $PATH.
OPTIONS
- Navigation options
- auto_cd (allow one to change to a directory by entering it as a command). auto_pushd (automatically append dirs to the push/pop list) pushd_ignore_dups (and don't duplicate them)
- Misc
- no_hup (don't send HUP signal to background jobs when exiting ZSH) print_exit_value (show a message with the exit code when a command returns with a non-zero exit code)
- History options
- hist_verify (let the user edit the command line after history expansion (e.g. !ls) instead of immediately running it)
Use the same history file for all sessions :
setopt SHARE_HISTORY
- Privacy / Security
- no_clobber (or set -C; prevent '>' redirection from truncating the given file if it already exists)
- Spelling correction
- correct (automatically correct the spelling of commands) correct_all (automatically correct the spelling of each word on the command line) dvorak (dvorak layout)
LINKS
- The Z shell Homepage
- http://www.zsh.org/
- The Z shell FAQ
- http://zsh.sunsite.dk/FAQ/
- The Z shell wiki
- http://www.zshwiki.org/
- Mailinglistarchive
- http://www.zsh.org/mla/
- The Z shell reference-card (included in the zsh-lovers
- debian-package) http://zsh.sunsite.dk/Refcard/refcard.ps.gz
- Adam Spier's UNIX shells page
- http://adamspiers.org/computing/shells/
- The Single UNIX (R) Specification, Version 2 - Shell Command Language Index
- http://www.opengroup.org/onlinepubs/007908799/xcu/shellix.html
- Zzappers Best of ZSH Tips
- http://www.rayninfo.co.uk/tips/zshtips.html
- The ZSH area on dotfiles.com
- http://www.dotfiles.com/index.php3?app_id=4
- Zsh Webpage by Christian Schneider
- http://strcat.neessen.net/zsh/
- The zsh-lovers webpage
- http://grml.org/zsh/
- IRC channel
- #zsh at irc.freenode.org
AUTHORS
This manpage was written by Michael Prokop, Christian 'strcat' Schneider and Matthias Kopfermann. But many ideas have been taken from zsh-geeks e.g. from the zsh-mailinglists (zsh-users and zsh-workers), google, newsgroups and the zsh-Wiki. Thanks for your cool and incredible tips. We learned much from you! In alphabetic order:
Andrew 'zefram' Main - http://www.fysh.org/~zefram/ Barton E. Schaefer - http://www.well.com/user/barts/ Matthias Kopfermann - http://www.infodrom.north.de/~matthi/ Oliver Kiddle - http://people.freenet.de/opk/ Paul Falstad - http://www.falstad.com/ Peter Stephenson - http://python.swan.ac.uk/~pypeters/ Richard Coleman Stéphane Chazelas - http://stephane.chazelas.free.fr/ Sven Guckes - http://www.guckes.net/ Sven Wischnowsky - http://w9y.de/zsh/zshrc
SEE ALSO
Manpages of zsh:
zsh Zsh overview (this section) zshmisc Anything not fitting into the other sections zshexpn Zsh command and parameter expansion zshparam Zsh parameters zshoptions Zsh options zshbuiltins Zsh built-in functions zshzle Zsh command line editing zshcompwid Zsh completion widgets zshcompsys Zsh completion system zshcompctl Zsh completion control zshmodules Zsh loadable modules zshzftpsys Zsh built-in FTP client zshall Meta-man page containing all of the above
Note: especially 'man zshcontrib' covers very useful topics!
Book:
From Bash to Z Shell by Oliver Kiddle, Jerry Peck and Peter Stephenson ISBN: 1590593766
Also take a look at the section LINKS in this manpage.
BUGS
Probably. This manpage might be never complete. So please report bugs, feedback and suggestions to <zsh-lovers@michael-prokop.at>. Thank you!
COPYRIGHT
Copyright © 2005 Michael Prokop, Christian Schneider and Matthias Kopfermann.