.\" Title: zsh-lovers, 1 .\" Author: Michael Prokop / www.michael-prokop.at / www.grml.org .\" Latest change: Son Jun 19 12:13:40 CEST 2005 [mika] .\"############################################################### .\"############################################################### .TH zsh\-lovers 1 "2005-06-19" "zsh 4\&.2\&.5" .SH "NAME" zsh\-lovers \- tips, tricks and examples for the Z shell .SH "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. .P Most of the tricks and oneliner come from the mailinglists zsh\-users, zsh\-workers, google, newsgroups and from ourself. See section .B LINKS for details. .P .B Note: This manpage (zsh-lovers(1)) is .B 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 .B BUGS. .\"####################################################### .\"####################################################### .SH "EXAMPLES" .SS "REDIRECTION" See also \fIman 1 zshmisc\fP\&. null command shorthands: .nf "< file" is like "$READNULLCMD file" is like "cat >file" ">> file" is like "cat >>file" .fi .sp Append `exit 1' at the end of all *.sh \- files: .nf $ echo "exit 1" >> *.sh .fi .sp Append /etc/services at the end of file `foo' and `bar': .nf $ cat /etc/services >> foo >> bar .fi .sp Pipe STDERR: .nf $ echo An error >&2 2>&1 | sed -e 's/A/I/' .fi .\"####################################################### .\"####################################################### .SS MULTIPLE I/O REDIRECTION Requires \fIsetopt multios\fP! Some examples: .sp Print output of 'ls' into files 'foo' and 'bar': .nf $ ls >foo >bar .fi .sp Send standard output of one process to standard input of several processes in the pipeline: .nf $ process1 > >(process1) > >(process2) .fi .sp Redirection to file as well as send on to pipe: .nf $ make install > /tmp/logfile | grep -i error .fi .sp Redirect stderr to a command like xless without redirecting stdout as well: .nf $ foo 2>>(xless) \&.\&.\&. but this executes the command asynchronously. To do it synchronously: .nf $ { { foo 1>&3 } 2>&1 | xless } 3>&1 .fi .sp Redirect stderr two times: .nf $ setopt multios ; program 2> file2 > file1 2>&1 .fi .sp More fun with stderr: .nf $ ./my-script.sh 2> >(grep -v geek >error.log) | process-output > output.log echo "Thats STDOUT" >>(sed 's/stdout/another example/' > foobar) .fi .\"####################################################### .\"####################################################### .SS 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. .sp Remove a trailing pathname component, leaving the head. This works like `dirname': .nf $ echo =ls(:h) /bin .fi .sp Remove all leading pathname components, leaving the tail. This works like `basename'. .nf $ echo =ls(:t) ls .fi .sp Remove a filename extension of the form `.xxx', leaving the root name. .nf $ echo $PWD /usr/src/linux $ echo $PWD:t linux .fi .sp Remove all but the extension. .nf $ foo=23.42 $ echo $foo 23.42 $ echo $foo:e 42 .fi .sp Print the new command but do not execute it. Only works with history expansion. .nf $ echo =ls(:h) /bin $ !echo:p $ echo =ls(:h) .fi .sp Quote the substituted words, escaping further substitutions. .nf $ bar="23'42" $ echo $bar 23'42 $ echo $bar:q 23\'42 .fi .sp Convert the words to all lowercase. .nf $ bar=FOOBAR $ echo $bar FOOBAR $ echo $bar:l foobar .fi .sp Convert the words to all uppercase. .nf $ bar=foobar $ echo $bar foobar $ echo $bar:u FOOBAR .fi .sp Variables can be modified by modifiers, too. That makes modification of variables possible without using any external program. .nf sentence="beginning and some words of a sentence with end." .fi .sp Now lets split this sentence-var by using the (s| |) modifier which modifies words by splitting at " ": .nf words=${(s| |)sentence} print $words[1] -> "beginning" print $words[-1] ->"end." .fi .sp Now if one wants to have the beginning of a sentence with a Capital, it's as easy as doing: .nf print "${(C)words[1]} $words[2,-1]" .fi .sp 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. .nf colonlist=${(j|,|)words} # (j|,|) joins with ",". .fi .sp You can see that it's a scalar by testing with (t): .nf print ${(t)colonlist} prints "scalar". print ${(t)words} prints "array". .fi .sp It's possible to sort arrays with o and O: .nf print ${(o)words} # lists the words-array sorted (forwards) print ${(O)words} # lists the words-array sorted (backwards) .fi .\"####################################################### .\"####################################################### .SS "COMPLETITION" See also \fIman 1 zshcompctl zshcompsys zshcompwid\fP\&. zshcompctl is the old style of zsh programmable completion, zshcompsys is the new completion system, zshcompwid are the zsh completion widgets. .sp 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: .nf zstyle ':completion:*' use-cache on zstyle ':completion:*' cache-path ~/.zsh/cache .fi .sp Prevent CVS files/directories from being completed : .nf zstyle ':completion:*:(all-|)files' ignored-patterns '(|*/)CVS' zstyle ':completion:*:cd:*' ignored-patterns '(*/)#CVS' .fi .sp Fuzzy matching of completions for when you mistype them: .nf zstyle ':completion:*' completer _complete _match _approximate zstyle ':completion:*:match:*' original only zstyle ':completion:*:approximate:*' max-errors 1 numeric .fi .sp And if you want the number of errors allowed by _approximate to increase with the length of what you have typed so far: .nf zstyle -e ':completion:*:approximate:*' max-errors 'reply=( $(( ($#PREFIX+$#SUFFIX)/3 )) numeric )' .fi .sp Ignore completion functions for commands you don't have: .nf zstyle ':completion:*:functions' ignored-patterns '_*' .fi .sp With helper functions like: .nf xdvi() { command xdvi ${*:-*.dvi(om[1])} } .fi .sp 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: .nf zstyle ':completion:*:*:xdvi:*' menu yes select zstyle ':completion:*:*:xdvi:*' file-sort time .fi .sp Completing process IDs with menu selection: .nf zstyle ':completion:*:*:kill:*' menu yes select zstyle ':completion:*:kill:*' force-list always .fi .sp If you end up using a directory as argument, this will remove the trailing slash (usefull in ln) .nf zstyle ':completion:*' squeeze-slashes true .fi .sp cd will never select the parent directory (e.g.: cd ../): .nf zstyle ':completion:*:cd:*' ignore-parents parent pwd .fi .\"####################################################### .\"####################################################### .SS "ADVANCED GLOBBING" See \fIman zshexpn | less -p 'Glob Qualifiers'\fP .sp List file 'foobar' via recursiv search in directories: .nf $ ls **/foobar .fi .sp List files file20, file30, file100, etc: .nf $ ls file<20-> .fi .sp List files with suffix c and pro (e.g. foo.c, bar.pro): .\" Anmerkung: es gibt da ein noch genaueres Pattern - FIXME .nf $ ls *.(c|pro) .fi .sp List files which are word-readable: .nf $ ls *(R) .fi .sp List all .c-files except 'lex.c': .nf $ ls *.c~lex.c .fi .sp List all `README' - files case-insensitive with max. one typo (e.g. RADME, REEME, RAEDME): .nf $ ls (#a1)README .fi .sp List files named README but accept one spelling error including case-insensitive (e.g. RADME, REEME, RAEDME): .nf $ ls (#ia1)README .fi .sp List executable files, directories and symlinks: .nf $ ls *(*@) .fi .sp List dangling symlinks: .nf $ ls **/*(-@) .fi .sp List all zero-length-files which are not group- or world-writable: .nf $ ls *(L0f.go-w.) .fi .\".sp .\"List the last two modified files/directories: .\" FIXME - stimmt das? .\".nf .\" $ ls *(om[2]) .\".fi .\".sp .\"Edit newest file with vim: .\" FIXME - stimmt das? .\".nf .\" $ vim *(.om[1]^D) .\".fi .sp List all .c-files for which there doesn't exist a .o file: .nf $ c=(*.c) o=(*.o(N)) eval 'ls ${${c:#(${~${(j:|:)${o:r}}}).c}:?done}' .fi .sp Find (and print) all symbolic links without a target within the current dirtree: .nf $ file **/*(D@) | fgrep broken $ for i in **/*(D@); [[ -f $i || -d $i ]] || echo $i $ echo **/*(@-^./=%p) $ print -l **/*(-@) .fi .sp Rename all MP3-files from name with spaces.mp3 to Name With Spaces.mp3: .nf $ for i in *.mp3; do mv $i ${${(C)i}:s/Mp3/mp3/} done .fi .sp Rename all PDF-files from name.mp3 to Name.mp3 (lowercase to uppercase of first letter) without touching the rest of the filename: .nf $ zmv '([a-z])(*).pdf' '${(C)1}$2.pdf' .fi .sp Substitutions in strings can be done by string-indexes: .nf $ a="doh.";a[1]='d';a[-1]='. (Bart Simpson)' $ echo $a doh. (Bart Simpson) .fi .sp Associative arrays: .nf $ 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 .fi .sp Extract parts of a string. Print first word of output of 'date': .nf $ print ${$( date )[1]} .fi .sp Extract parts of a string. Print ip-address of loopback device: .nf $ print ${${$( LC_ALL=C /sbin/ifconfig lo )[6]}#addr:} .fi .sp Print specific line of a file. E.g. print line 5 of file: .nf $ print -l ${"$( < file )"[(f)5]} .fi .sp Print line containing string 'root' of file /etc/passwd: .nf $ print ${"$( < /etc/passwd )"[(fr)*root*]} .fi .\" TODO / FIXME -> .\" print -l ${(M)${(f)"$(< /etc/passwd)"##*$muster*}} (f) .\" liest die in Anführungsstrichen stehende Ausgabe der Datei zeilenweise in eine unbenannte Variable. Wie auch in anderen Shells schneidet ## am Anfang *$muster* ab. .\" Da aber (M) benutzt wird, werden alle Zeilen, bei denen das Muster zutrifft, nicht abgeschnitten, sondern alleine ausgegeben. Das Gegenstück dazu ist (R), was im vorigen Fall dann einem "grep -v" entspricht. .\" Würde man nur ein # angeben, würden die Sterne (Stellvertreter für 0 oder mehr Zeichen) geizig - mit so wenig Zeichen wie möglich - ausgegeben. In diesem Fall würde dann also nur $muster selber ausgeben. .\" Zsh kann wie bekanntere Programmiersprachen (Perl, Python, Ruby z.B) im Index einer Variablen ein "von_feld,bis_feld". .sp Print words two to four of output of 'date': .nf $ print ${$( date )[2,4]} .fi .\".sp .\"FIXME [text] .\".nf .\" $ print ${${:-one two three four five}[2,-2]} .\".fi .\".pp .\"gibt als Ergebnis zwei drei vier aus. (':-' ersetzt den .\"fehlenden Variablennamen hier wie bei der Bash durch seine .\"Werte). .sp Use of two-dimensional indizes. Print time via date but without seconds: .nf $ print ${$(date)[4][1,5]} .fi .\" TODO .\" Mit dem sogenannten Here-String kann man eine Art Here-Document benutzen ohne ein EOT-Signal auf einer Extra-Zeile eingeben zu müssen: .\" .\" for Programm in cat tail head grep ; do >> /tmp/datei \ .\" <<< "Hallo,Welt! Ich habe das Geüfhl, mein \ .\" externes $Programm wird bald nicht mehr so viel benutzt." ; done .\" Man achte auch auf das Auslassen von cat, was bei der zsh nicht mehr nötig ist! .sp Calculate floating point numbers: .nf $ printf "%.0f\n" $[ 2.8*15 ] .fi .\" Ausserdem kann in verschiedenen Zahlensystemen gerechnet werden, in dem in eckigen Klammern [#] geschrieben wird, also: .\" .\" for (( i=1; i<100; i++ )) { print $(( [#10] i)) } .\" entspricht .\" .\" $(( [#16] i )) } .\" Bei zweifacher Angabe von # wird das Zahlensystem nicht ausgegeben. .\" .\" Sogar einen "Taschenrechner" gibt es in der Zsh, der nach autoload zcalc zur Verfügung steht. .\" .\" Beispiele zur Vervollständigung (noch nach dem alten Schema bis 3.1.5): .\" .\" compctl -g '*(/)' cd .\" macht aus einer einfachen Dateiergänzung wie der Ksh eine intelligente Vervollständigung für "cd", die nur noch Verzeichnisnamen aufführt. .\" Vor allem mit compctl -k '(`aktion`)' lassen sich sehr praktische Vervollständigungsmechanismen erstellen. Man kann sich so z.B. ohne Probleme bei Aufruf eines Email-Programmes nur Email-Adressen und mit ftp nur FTP-Adressen vervollständigen lassen. Außerdem kann man bei der Vervollständigung auch Dateienden abschneiden lassen. Das ist z.B. bei Java sehr praktisch. .\" .\" compctl -g '*.class(:r)' java .\" (Mehr Beispiele zur älteren Vervollständigung hier) .\" Mit der Zsh kann man sehr gezielt nach Worten in Dateien suchen: Nach dem Freischalten von Sonderzeichen für die Reichweite eines glob-Befehls mit setopt extended_glob ist folgendes machbar: .\" .\" grep Wort *~(*.gz|*.bz|*.bz2|*.zip|*.Z) .\" sucht 'Wort' nicht mehr in den komprimierten Dateien im Mail-Ordner. .\" ~ bedeutet hier so viel wie "außer". .\" Alle Dateien, die nicht die Endung *.bz2 und auch nicht *.gz enthalten , sucht man mit .\" .\" ls ^(*.bz2|*.gz) .\" Das ^ ist also das "NICHT", das Ausrufezeichen wird von der Zsh für alte Befehle benutzt. .\" An dieser Stelle bietet sich vielleicht ein globales Alias für komprimierte Dateien an (siehe weiter unten). .\" Zusätzlich zu ^ und ~ lassen sich die Ausdrücke # und ##benutzen, um null und mehr bzw. ein und mehr Vorkommen des Zeichens davor zu erhalten, was bei Perls regulären Ausdrücken den Zeichen * bzw. + entspricht. .\" Globale Aliase sind Aliase, die nicht nur am Anfang der Kommandozeile oder nach ; als Aliase wirken können. Sie sollten gut gekennzeichnet werden: .\" .\" alias -g §k="*~(*.bz2|*.gz|*.tgz|*.zip|*.z)" .\" und danach der Befehl .\" .\" ls -d §nk .\" listet alle nicht-komprimierte Dateien auf. .\" Mit unalias '§k' wird man dieses globale Alias wieder los. Wichtig hierbei sind die einfachen Anführungsstriche. Sonst wirkt nämlich §k weiter, was nicht im Sinne des Benutzers wäre. .\" Aliase können seit Version 4.2 auch verwendet werden, um bestimmten Zeichenketten-Endungen (Suffixes) nach einem Punkt automatisch mit dem selben Befehl aufzurufen, was meist für Dateiendungen benutzt wird. Dabei gilt: .\" .\" .\" alias -s NAME=WERT .\" wobei TEXT.NAME dann durch die Zsh zu WERT TEXT.NAME wird. .\" .\" alias -s txt='less -rE' .\" ruft alle ohne Befehl aufgerufenen .txt-Dateien automatisch mit dem Befehl less -rE auf, so dass man jetzt einfach nur den Dateinamen und ein return eingeben muss. Diese Funktionalität ist vergleichbar mit dem Anklicken einer oder mehrerer Dateien mit einem graphischen Dateimanager. Dabei kann man auch globale Zeichen wie * verwenden, also beispielsweise *.txt und ein "enter" eingeben um alle Dateien mit Endung ".txt" mit less zu lesen. .\" Praktischerweise gibt es mit autoload zsh-mime-setup ; zsh-mime-setup die Möglichkeit, anhand der Mime-Definitionen in /etc/ schon bestimmte Datei-Endungen mit bestimmten Programmen zu belegen. .\" .\" .\" alias -s de=w3m .\" alias -s at=w3m .\" ruft alle WWW-Seiten mit .de oder .at direkt mit w3m auf. ('.de' bzw. '.at' in der Eingabe ist in diesem Fall keine Dateiendung!) .\" In der Zsh kann man aus jeder eigenen Funktion eine Datei machen, ohne dass diese Datei ausführbar sein muss. Hierzu setzt man die Variable FPATH bzw fpath (siehe unten) auf das oder die Verzeichnisse, die berücksichtigt werden sollen. .\" In der Datei genügt es, einfach eine oder mehrere Funktionen zu schreiben, z.B: .\" .\" begruessung() { echo "Hallo, $1" ; } .\" herzlich() { echo "Ist ja riesig, $1, Dich zu sehen" ; } .\" Jetzt muss noch dieser Dateiname mit autoload dateiname bekannt gemacht werden. Daraufhin stehen nach einmaligem Aufruf des Namens der Funktionen die beiden Funktionen dann zur Verfügung. Schreibt man nur den Funktionsrumpf allein dann hat das gegenüber dem Schreiben von Funktionen den Vorteil, sofort ausgeführt werden zu können. autoload-Funktionen müssen nämlich erst einmal aufgerufen werden, damit ihr Rumpf bekannt ist. Beispiel: .\" .\" echo "Ist das schön, $1, Dich zu sehen\!" > ~/.zsh/funktionen/begruessung .\" ist nach Aufruf von autoload begruessung sofort nutzbar. (Siehe AUTOLOADING FUNCTIONS unter 'man zshmisc') .\" Statt in eine "Backslashitis" beim Aufschreiben von Skalar-Variablen mit viel Inhalt zu verfallen (z.B. beim Definieren des Pfades) gibt es bei der Zsh die Möglichkeit, das kleinbuchstabige Gegenüber des großbuchstabigen Variablennamens als eines Arrays zu verwenden und sogar für eigene Variablen mit typeset -T ein "Gegenüber" von einer Skalar-Variable zu einer Feld-Variable durch die Kleinschreibweise der Variablen zu erzielen. .\" Dieser Variante kann man dann ein Feld aus Werten - durch Leerzeichen oder Zeilenumbruch getrennt - zuweisen. Beispiel PATH: .\" .\" alt: PATH=/usr/bin\ .\" :/usr/local/bin/\ .\" :/usr/sbin\ .\" :/usr/local/sbin\ .\" :/usr/X11R6/bin .\" .\" zsh: path=( /usr/bin /usr/local/bin /usr/sbin /usr/local/sbin /usr/X11R6/bin ) .\" Da die Zsh für Feldvariablen runde Klammern braucht (wenn nicht setopt shwordsplit gesetzt ist) sind die Worte in runde Klammern eingeschlossen. .\" Wer allerdings kompatibel zur Sh/Ksh/Bash programmieren muss/will, der muss die Option setopt shwordsplit setzen. .\" Zle - der Zeileneditor der Zsh - ist den Zeileneditoren anderer Shells überlegen. Hier kann man fröhlich mehrere Zeilen schreiben und nach dem Aufruf mit RETURN separat einzelne Zeilen korrigieren. Man muss also nicht mehr immer einen externen Editor aufrufen. .\" Besonders nett dabei: Wo die Bash nur das Manövrieren wie in einer einzigen Zeile zulässt, kann man bei der Zsh bequem mit dem Cursor - wie in einem Editor - über mehrere Zeilen navigieren. .\" Will man innerhalb mehrerer Zeilen editieren, dann muss man entweder mit bindkey "^Xp" push-line-or-edit oder ähnlicher Tastenbelegung diesen Puffer in einen anderen Puffer kopieren oder aber nach einem Control-C erneut die Zeilen zurückholen. .\" Mittels zle -N kann man eigene, sogenannte Widgets (das sind Editier-Funktionen) zle bekannt machen. In den Variablen LBUFFER und RBUFFER liegt die Kommandozeile links bzw. rechts des Cursors, die man so sehr einfach manipulieren kann. Beispiel: .\" .\" klammer() { LBUFFER="\${$LBUFFER" ; RBUFFER="}$RBUFFER" } .\" erzeugt eine Funktion klammer, die man mit bindkey '^g' klammer jetzt an die Taste Control-G zuweisen kann. .\" Noch ein Beispiel für ein User-Widget: .\" .\" wohin() { .\" dirs -v .\" print -n "Wohin? " .\" read WOHIN .\" cd +${WOHIN:=0} .\" } .\" Jetzt muss mit 'zle -N ' "wohin" als User-Widget deklariert werden. Anschließend kann mit 'bindkey '^Ww' wohin' die definierte und deklarierte Editier-Funktion auf 'Control-Ww' gelegt werden. .\" Zusätzlich kann man mit 'autoload zed' sogar einen Editor (der in der Z Shell selber geschrieben ist) benutzen, der dann von seiner Voreinstellung oder durch 'bindkey -e' Emacs-artig, bei Eingabe von 'bindkey -v' vi-artig funktioniert. Gesichert wird allerdings durch 'control-x control-w' oder im Vicmd-Modus mit 'ZZ' und mit dem Befehl control-c bricht man ab. Ruft man zed mit der Option -f oder als fned auf, kann man Funktionen editieren. .\" Als wohltuend empfinden wir bei einem Kommando des Zeileneditors das Kommando insert-last-word, das im Gegensatz zur Bash nicht immer das letzte Wort, sondern bei wiederholtem Aufruf das letzte Wort davor und so weiter aufruft. (Siehe auch 'man zshzle') .\" Die Zsh unterstützt wie ihr Vorbild -die Ksh- Koprozesse. Koprozesse sind eine Möglichkeit, an Parallelprozesse Daten zu übergeben und Daten zu empfangen. Diese Koprozesse werden allerdings mit 'coproc' eingeleitet und nicht wie bei der Ksh mit |& . .\" Mit ' print -p' und mit '>&p ' als Umlenkung kann ich Daten an den Prozeß senden und mit 'read -p und '<&p' als Umlenkung Daten von diesem Prozeß auslesen. Beispiel: .\" .\" coproc ed /tmp/notizen .\" print -p "a" .\" ls -l >&p .\" print -p ".\nwq" .\" schreibt in einen parallel laufenden Koprozess, den altehrwürdigen Ed, die Ausgabe von 'ls -l' und speichert den Inhalt in der Datei /tmp/notizen ab und beendet ed. .\" Weitgehender als ein Coprozess ist das Laden des zpty-Moduls mit 'zmodload zsh/zpty', welches dann ähnliche Steuerungsmöglichkeiten wie das Programm expect bietet. Als Beispiel für die Verwendung von zpty kann das Skript nslookup in /usr/share/zsh/4.x.x/functions/ dienen, was das gleichnamige interaktive Programm durch seine Vervollständigung leichter bedienbar macht. .\" Die Zsh kennt die Formatierungen, die die Ksh kennt. typeset - oben schon kurz bei assoziativen Variabelfeldern erwähnt - ist ein mächtiger Formatierbefehl der Ksh. Mit diesen Formatierungsregeln lassen sich Ausgaben auf unterschiedliche Weise formatieren. .\" .\" typeset -L2 name=werteintrag ;print "[$name]" .\" gibt linksformatiert "[we]" aus, die ersten 2 Buchstaben, umrahmt von []. .\" .\" typeset -lL20 name=WERT;print "[$name]" .\" gibt in Kleinbuchstaben (-l für lower) "[wert ]" aus, wobei 20 - 11 Leerzeichen eingefügt werden. .\" .\" typeset -r RPROMPT=%n .\" schützt den Rechtsprompt vor einem versehentlichen Überschreiben. Die Variable ist jetzt read-only und zsh warnt einen mit "zsh: read-only variable: RPROMPT ". Alle typeset-Befehle können mit einem - statt dem + aufgehoben werden. (Siehe man zshbuiltins unter typeset) .\" Zusätzlich zu typeset kann man auch durch sogenannte Modifier die Ausgabe von print verändern. Beispiel: .\" .\" name="Wert" .\" print "[${(Ll:20:)name}]" .\" ergibt genau die selbe Ausgabe wie .\" .\" typeset -lL20 name .\" Seit Zsh 4.1.1 kann man mit .\" .\" printf "%20s\n" ${(L)a} .\" ähnlich wie in der gleichnamigen C-Funktion auch dieses Ergebnis bekommen, ohne den externen printf-Befehl nutzen zu müssen. .\" Die Ausgabe von Dateinamen kann mittels sogenannter Qualifier spezifiziert werden (siehe man zshexpn unter Glob Qualifier). Beispiele: .\" .\" print -l *(m-1) # listet nur Dateien zeilenweise auf, die vor .\" # bis zu einem Tag modifiziert wurden .\" .\" print -l *(a1) # listet Dateien zeilenweise auf, auf die vor einem .\" # Tag zugegriffen wurde .\" .\" print -l *(@) # listet nur die Links zeilenweise auf .\" .\" ls -doF *(/) # findet nur die Verzeichnisse .\" .\" chmod 640 *(W) # verändert die Rechte aller Dateien, in die .\" # jeder schreiben darf, denn das ist ja meistens .\" # besonders riskant! .\" .\" .\" grep name *(.) # findet nur noch reine Dateien. Damit ist .\" # die unsinnige Meldung "grep: bla: Is a directory" .\" # für alle Zeiten vermeidbar. .\" Um einmal wieder an alte schlechtere Zeiten erinnert zu werden, könnte man auch 'grep name *(^.@)' eingeben. Hiermit werden alle Dateien aufgelistet, mit denen grep nichts anfangen kann, denn '^' ist das Nicht-Zeichen :). .\" .\" .\" gg() { grep -wE "$1" *(.) | less -r } .\" könnte eine kleine Zsh-Funktion sein, um gezielt nach einem Wort und unter Zuhilfenahme von regulären Ausdrücken zu suchen. Ich persönlich (Matthias) benutze allerdings lieber Perl für solche Dinge und habe dafür das Perl-Programm mg entdeckt. .\" Ein sehr schneller Befehl, um DOS-Dateien (keine Verzeichnise) zu Dateien mit kleinen Buchstaben zu machen ist: .\" .\" for i in [A-Z][A-Z]*(.); do mv $i ${i:l} ;done .\" Der Qualifier :l (für lowercase) leistet hier ganze Arbeit. .\" .\" print -l *(LM+3) .\" gibt zeilenweise Dateien aus, die über 3 Megabyte groß sind. .\" Ich kann unter der Zsh komprimierte Email-Pakete lesen, ohne mich zuerst um das Entpacken kümmern zu müssen. Das geht bei gzip-gepackten Dateien z.B. so: .\" .\" mutt -f =(zcat mailfold*.gz) .\" In den =() steht dabei die Aktion, die mit einer Datei gemacht wird, es wird dabei eine temporäre Datei erzeugt und mit ihr z.B. mutt -f aufgerufen. Ein anderes Beispiel: .\" .\" mutt -f =(grepmail "Mustafa Mustermann" ~/mbox) .\" sucht alle Emails von Mustafa Mustermann aus einer sehr großen Email-Datei namens mbox mittels grepmail, einem sehr mächtigen Perl-Programm zum Herausfiltern von Emails, welche einem bestimmten Kriterium entsprechen, heraus. Die temporäre Datei wird selbstverständlich nachher wieder gelöscht. .\" mutt ist ein sehr schönes Mail-Programm, welches auch auf der Kommandozeile funktioniert, das wir sehr empfehlen können. Mit 'mutt -f' liest mutt nicht aus /var/spool/mail sondern die Email-Datei, hier mehrere Emaildateien. Ein anderes Beispiel: .\" .\" lynxbzgrep() { .\" lynx -force_html -dump =(bzip2 -cd $1 | grep $2) .\" } .\" ermöglicht es, mit lynxbz bzip2-gepackte HTML-Seiten nach einem Begriff zu untersuchen. Nötig wird dieser Mechanismus, wenn ein Programm lseek benötigt. (Siehe man 3 lseek) .\" Wird keine temporäre Datei benötigt, dann kann man wie auch bei der Bash '<()' verwenden. Damit erspart man sich dann die manuelle Verwendung von /proc/self/fd oder die manuelle Erzeugung einer "named pipe": .\" .\" lynx -force_html <( gzip -cd komprimiert.html.gz ) .\" ist ein Beispiel, bei dem lynx die Ausgabe von 'gzip -cd komprimiert.html.gz' verarbeitet. .\" Durch intelligente Kommunikation verschiedener Prozesse wird es möglich, dass man zwei Pseudodateien erzeugen und miteinander vergleichen kann: In Shellkreisen wird dies als 'named pipe' bezeichnet, die die Zsh indirekt erzeugt. .\" .\" diff <(zcat erste_datei.gz) <(zcat zweite_datei.gz) .\" vergleicht den Inhalt von zwei komprimierten Dateien miteinander. .\" Nach Setzung von READNULLCMD=less lässt sich eine Datei mit: .\" .\" < datei .\" unter less angucken. Einfach ein < vor die Datei setzen. .\" Es ist ohne Probleme möglich, die Standardausggabe an mehrere Dateien umzulenken: .\" .\" ls >datei1 >datei2 >datei3 .\" oder: .\" .\" ls >> datei1 >> datei2 .\" Man kann auch die Standardeingabe von mehreren Dateien empfangen: .\" .\" less < datei1 < datei2 .\" Es ist möglich, eine Umlenkung in eine Datei und gleichzeitig an eine Pipe zu bewerkstelligen: .\" .\" make >logfile | grep Error .\" Mit ls -lL =emacs kann man beispielsweise in jedem Verzeichnis schauen, wie groß 'emacs' genau ist. Man muss nicht mehr den Pfad angeben. Die Zsh schaut dabei selbst im Pfad nach, wenn man emacs im Pfad hat. Man kann auch bequem Dateien, die im Pfad stehen, auf diese Art editieren. .\" .\" jed =genial.c .\" editiert eine C-Funktion, wenn sie im Pfad gefunden werden kann. .\" Statt eines sehr expliziten aber umständlich zu tippenden find-Befehls kann under der Zsh ** als rekursives Kürzel verwendet werden. Mit: .\" .\" print -l **/*.html .\" findet man alle HTML-Seiten, die in allen Verzeichnissen unterhalb des jetzigen Verzeichnisses vorhanden sind und gibt sie auf je einer Zeile (-l) aus.(**=Rekursion) .\" .\" .\" print -l **/datei.html # sucht die bestimmte Datei in allen .\" # vom aktuellen Verzeichnis abgehenden .\" # Verzeichnissen und gibt genau sie aus. .\" .\" print -l **/*.html~datei.html # gibt alle HTML-Seiten .\" # mit Ausnahme von datei.html zeilenweise aus. .\" .\" grep name **/*.txt # sucht in allen Texten unterhalb des .\" # gegenwärtigen Verzeichnisses nach Dateien .\" # mit Endung .txt. .\" Mit vared kann man alle Umgebungsvariablen editieren. Das finden wir praktisch, weil wir sofort die Variable erreichen und nicht erst in einer Datei wie .zshrc nach ihr suchen müssen. Außerdem wirkt das Editieren der Variablen natürlich sofort. .\" Der Befehl dirs -v zeigt alle Verzeichnisse, in denen man in einer Sitzung gewesen ist zeilenweise an. Wenn man .\" setopt autopushd setzt, kann man nun mit cd +2 das vorletzte Verzeichnis erreichen. .\" Mit der Zsh kann man sehr lange Unterverzeichnisse im Prompt mit einem kurzem oder signifikanteren Namen (named directory) versehen und dann mit ~name aufrufen. Das ist insbesondere dann sehr praktisch, wenn man in einem sehr entfernten Ordner von '/' aus gesehen arbeitet. .\" Ich (Matthias) habe mir eine kleine Zsh-Funktion geschrieben, die mir aus einem langem Verzeichnisnamen einen kurzen erzeugt: .\" .\" .\" zza () { .\" NAMED_DIRECTORY=$PWD:t; # der Name des jetzigen Verzeichnisses wird .\" # an NAMED_DIRECTORY ohne die Hierarchie übergeben. .\" # :t steht für tail. .\" eval $NAMED_DIRECTORY=$PWD; # es findet die Setzung eines named directory statt. .\" cd ~$NAMED_DIRECTORY; # es wird in das named directory gesprungen. .\" # ist mit dem bestehenden Verzeichnis identisch .\" # aber der Name ist kürzer im Prompt. .\" } .\" Eine außerdem sehr praktische Möglichkeit besteht darin, dass man jetzt nicht mehr den ganzen Pfadnamen angeben muss, wenn man eine Datei verschiebt. Z.B.: .\" .\" mv datei.1 ~lm1 .\" könnte die Datei bequem nach /usr/local/man/man1/ verschieben, wenn man lm1=/usr/local/man/man1 gesetzt hat. .\" Bei der Prompt-Darstellung gibt es zwei Möglichkeiten: Entweder weisst man am Ende auch noch den letzten Slash zu: info=/usr/local/info/ Dann wird im Prompt der ganze Name dargestellt. cd ~info springt zwar nach /usr/local/info, aber im Prompt steht: .\" .\" /usr/local/info% .\" Möchte man aber den kurzen Prompt haben, dann muss man so zuweisen: .\" .\" info=/usr/local/info .\" -also ohne Slash am Ende. .\" Die Option autocd erlaubt es, nur den Namen eines Ordners anzugeben. Bei Eindeutigkeit wird dann sofort in diesen Ordner gesprungen. Z.B. springt bin «enter» dann sofort in das bin-Verzeichnis. .\" Es gibt keinen Fehler bei Farbprompts wie unter der Bash1-Shell. Gerade bei der Gliederung des Prompts ist das besonders wichtig. Da die üblichen Escape-Sequenzen sehr unleserlich sind gibt es in der Zsh eine besonders elegante Möglichkeit, um Farben zu definieren. Ein Beispiel: .\" .\" autoload -U colors && colors .\" echo "$fg_bold[red]zsh $fg_no_bold[white]is $bg[blue]$fg_bold[green]nice" .\" Mit RPROMPT lässt sich ein PROMPT auf der rechten Seite definieren: .\" RPROMPT=%l zeigt beispielsweise an, auf welchem Rechner man sich befindet. .\" RPROMPT=%n zeigt den Benutzer an. .\" RPROMPT=%T zeigt die Zeit an. .\" RPROMPT=%D{%d.%m.%y} zeigt das Datum nach deutscher Darstellung an. .\" Selbstverständlich kennt die Zsh auch eine Korrekturmöglichkeit bei falscher Eingabe, die aber nur dann wirksam wird, wenn man das wirklich eingestellt hat. Man setzt in einen solchem Fall einfach: .\" .\" setopt autocorrect .\" Die Korrektur kann durch Setzung eines .\" .\" alias =nocorrect .\" verhindert werden. .\" Um darüber informatiert zu werden, wer alles außer mir sich eingeloggt hat, gibt es das Kommando watch wie unter der Tcsh. .\" .\" .\" watch=(notme) .\" listet z.B. alle Benutzer auf, die nicht ich sind :) .\" Hierbei kann das Format der Ausgabe geändert werde: .\" .\" .\" WATCHFMT='%n eingeloggt auf Terminal %l von %M seit %T ' .\" Wählt man watch=(@vorsicht_ist_angesagt), so werden alle Benutzer aufgeführt, die von dem Server vorsicht_ist_angesagt eingeloggt sind. .\" Positiv herum kann man so natürlich auch alle Freunde erkennen lassen: .\" .\" watch=( < ~/.freunde root) .\" liest alle Freunde aus der Datei .friends in das Feld watch zusätzlich zu root ein. So kann man schnell erkennen, wenn sich Freunde einloggen. .\" Es gibt in der Zsh einen sehr bequemen Wiederholungsbefehl, der von der tcsh abgeschaut ist: repeat. Möchte man z.B. einen Werbemailer böswillig strafen, dann könnte man das so machen: .\" .\" .\" repeat 100 mail -s "spams suck" badcompany@devilsheart.com < flame .\" Dabei sollte allerdings bedacht werden, dass man damit meist harmlose Benutzer trifft, die schlechte Passworte haben und deshalb Räubern auf den Leim gegangen sind. .\" Ruft man ein altes Kommando mit !?kommando auf, hat man die Möglichkeit, vor der erneuten Ausführung zu schauen, ob es sich hierbei auch um das gewünschte Kommando handelt. Man drückt dazu einfach «TAB». Ebenso kann man sich auch die genau betroffenen Dateien eines global wirkenden Befehles (z.B. 'ls *.html') mit «TAB» ansehen. .\" Gerade eben getippte Worte auf der Kommandozeile können mit !# genauer wiedergegeben werden als bei Bash/Tcsh/Ksh. Man gibt einfach an, wo wiederholt werden soll - z.B.: .\" .\" echo ein_langes_wort zweites_langes_wort drei !#1-2 .\" schreibt auf den Bildschirm: 'ein_langes_wort zweites_langes_wort drei ein_langes_wort zweites_langes_wort'. .\" Um die Funktion funct alle 300 Sekunden auszuführen führt man einfach folgenden Befehl aus: .\" .\" periodic funct() PERIOD=300 fortune -s .\" Anmerkung: Allerdings muss dazu auch am Prompt ein Befehl eingegeben werden, sonst kann man natürlich nichts auf dem Bildschirm sehen. .\" Die Zsh kennt den '..' Operator von Pascal (und Perl): .\" .\" echo {1..7} "\nWo ist denn die Bash geblieben?" .\" ergibt: .\" .\" 1 2 3 4 5 6 7 .\" Wo ist denn die Bash geblieben? .\" Die Zsh hat in ihrer sehr mächtigen HISTORY CONTROL ein run-help Kommando, mit dem zu einem Buffer gezielt Informationen abgerufen werden können. Voreingestellt ist hier der Aufruf der Manpage zu dem Kommando. Verändern könnte man diesen Aufruf, in dem man einfach aus: .\" .\" alias run-help=man # ein -> .\" alias run-help=info .\" macht. .\" .\" man_zshall() man zshall # und nachfolgendes Deklarieren von .\" zle -N man_zshall # kann durch Definition von .\" bindkey '^g' man_zshall # nun immer bei Control-G ausgeführt werden. .\" sched ist ein interner Befehl zum automatischen, zeitgebundenen Abarbeiten von Kommandos ähnlich wie bei 'at'. Dabei werden die Kommandos aber nicht ausgeführt und dann als E-Mail zugeschickt, sondern gelangen erst einmal in den Puffer und werden beim nächsten Kommando erst auf dem Bildschirm ausgegeben. .\" .\" sched +0:10 figlet "Du musst jetzt los" .\" führt in 10 Minuten in Großschrift auf dem Bildschirm eine Warnung zum Gehen aus. Dabei ist allerdings das Durchführen des Befehls abhängig von der Eingabe eines nächsten Befehls. .sp Convert images from foo.gif to foo.png: .nf $ for i in **/*.gif; convert $i $i:r.png .fi .sp Download files created with LaTeX2HTML (e.g. the ZSH-Guide): .nf $ for f in http://zsh.sunsite.dk/Guide/zshguide{,{01..08}}.html; do lynx -source $f >${f:t} done .fi .sp Make with dpkg a master-list of everyfile that it has installed: .nf $ diff <(find / | sort) <(cat /var/lib/dpkg/info/*.list | sort) .fi .sp Replace this color escape-sequences: .nf $ autoload colors ; colors $ print "$bg[cyan]$fg[blue]Welcome to man zsh-lovers" >> $TTY .fi .sp Get ASCII value of a character: .nf $ char=N ; print $((#char)) .fi .sp Filename suffix. Note: (N) activates setopt nullglob only for this loop. .nf $ for i in *.o(N); do rm $i done .fi .sp Rename files: 'FOO' to 'foo': .nf $ for i in *(.); mv $i ${i:l} .fi .sp Rename files: 'bar' to 'BAR': .nf $ for i in *(.); mv $i ${i:u} .fi .sp Show all suid-files in $PATH: .nf $ ls -latg ${(s.:.)PATH} | grep '^...s' .fi .\"####################################################### .\"####################################################### .SS "ZMV - multiple move with zsh" Requires 'autoload zmv'. Some examples: .sp Move serially all files (foo.foo > 1.foo, fnord.foo > 2.foo, ..). .nf $ 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 .fi .sp See above, but now only files with a filename >= 30 chars. .\" Anmerkung: es gibt da ein noch genaueres Pattern - FIXME .nf $ c=1 zmv "${(l:30-4::?:)}*.foo" '$((c++)).foo' .fi .sp Replace spaces in filenames with a underline. .nf $ zmv '* *' '$f:gs/ /_' .fi .sp Change the suffix from *.sh to *.pl. .nf $ zmv -W '*.sh' '*.pl' .fi .sp Lowercase/uppercase all files and directories. .nf $ zmv '(*)' '${(L)1}' for lowercase $ zmv '(*)' '${(U)1}' for uppercase .fi .sp Remove the suffix *.c from all c-files. .nf $ zmv '(*).c' '$1' .fi .sp Uppercase only the first letter of all *.mp3 - files. .nf $ zmv '([a-z])(*).mp3' '${(C)1}$2.mp3' .fi .sp Copy the target `README' in same directory as each `Makefile'. .nf $ zmv -C '(**/)Makefile' '${1}README' .fi .sp Rename pic1.jpg, pic2.jpg,.. to pic0001.jpg, pic0002.jpg,... .nf $ zmv 'pic(*).jpg' 'pic${(l:4::0:)1}.jpg' $ zmv '(**/)pic(*).jpg' '$1/pic${(l:4::0:)2}.jpg' # recursive .fi .\"####################################################### .\"####################################################### .SS "MODULES" .P See also \fIman zshmodules\fP\&. Don't forget to run \fIzmodload \-i MODULENAME\fP before using a module\&. Example: \fIzmodload -i zsh/datetime\fP\&. .PD 0 .PD .TP \fBzsh/cap\fP Builtins for manipulating POSIX\&.1e (POSIX\&.6) capability (privilege) sets\&. .TP \fBzsh/clone\fP A builtin that can clone a running shell onto another terminal\&. .sp Creates a forked instance of the current shell ($! is set to zero) and execute ``command'' on /dev/tty8 (for this example): .nf $ zmodload zsh/clone $ clone /dev/tty8 && (($! == 0)) && exec command .fi .TP \fBzsh/compctl\fP The \fBcompctl\fP builtin for controlling completion\&. .TP \fBzsh/complete\fP The basic completion code\&. .TP \fBzsh/complist\fP Completion listing extensions\&. .TP \fBzsh/computil\fP A module with utility builtins needed for the shell function based completion system\&. .TP \fBzsh/datetime\fP Some date/time commands and parameters\&. .sp Do not have GNU date? Let's replace it: .nf $ alias datereplacement='strftime "%Y-%m-%d" $EPOCHSECONDS' $ export DATE=`datereplacement` $ echo $DATE .fi .TP \fBzsh/deltochar\fP A ZLE function duplicating EMACS' \fBzap\-to\-char\fP\&. .TP \fBzsh/example\fP An example of how to write a module\&. .TP \fBzsh/files\fP Some basic file manipulation commands as builtins\&. .nf # search a directory for files containing a certain string then copy those files to another directory. $ IFS=$'\0' $ cp $(grep -lZr foobar .) otherdirectory .fi .TP \fBzsh/mapfile\fP Access to external files via a special associative array\&. .nf # 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=$'\n\n' $ 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 ``'' and ``'', number this empty tags # (ones ending in '/>') so if encountered in the same order, the preceeding tags would become # ``1'' and ``2'' $ cnt=0 $ apfile[data.xml.new]=${(S)mapfile[data.xml]//\ > (#im)*<\/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=\"gone.scr\"* ]]'}) # 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' .fi .TP \fBzsh/mathfunc\fP Standard scientific functions for use in mathematical evaluations\&. .nf $ 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 .fi .TP \fBzsh/parameter\fP Access to internal hash tables via special associative arrays\&. .TP \fBzsh/pcre\fP Interface to the PCRE library\&. .sp Important: requires zsh compiled with pcre-support. Check whether your version supports pcre via `ldd =zsh | grep pcre`. .p PCRE provides support for Perl's regular expressions (regex). You have to compile a regex and can match it afterwards using error codes: .\" FIXME / TODO! .nf $ zmodload zsh/pcre $ pcre_compile '\\s\\d.\\d{3}\.\\d{3} Euro' &&\\ pcre_match ' 1.000.000 Euro' &&\\ echo "matches" || echo "does not match" .fi Note: if you are using complex regular expressions you can improve speed via pcre_study. .TP \fBzsh/sched\fP A builtin that provides a timed execution facility within the shell\&. .TP \fBzsh/net/socket\fP Manipulation of Unix domain sockets .p $ 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>&- .fi .sp In one shell: .nf $ 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>&- .fi .sp In another shell: .nf $ 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>&- .fi .TP \fBzsh/stat\fP A builtin command interface to the \fBstat\fP system call\&. .sp Get size of a file in bytes: .nf $ zmodload -i zsh/stat $ stat -L +size file .fi .sp Equal to GNU's: .nf $ stat -c %s file .fi .sp Comparing file dates: .nf $ 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 .fi .sp List the files of a disk smaller than some other file: .nf $ stat -A max +size some-other-file $ print -rl ./**/*(D.L-$max) .fi .sp List the top 100 biggest files in a disk: .nf $ ls -fld ./**/*(d`stat +device .`OL[1,100]) .fi .sp Get only the user name and the file names from (like ls -l * | awk '{print $3" " $8}'): .nf $ for file; do > stat -sA user +uid -- "$file" && > print -r -- "$user" "$file" > done .fi .sp Get the difference between actual bytes of file and allocated bytes of file: .nf $ print $(($(stat +block -- file) * 512 - $(stat +size -- file))) .fi .sp Find largest file: .nf $ 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 .fi .sp 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: .nf $ 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} .fi .sp Get a "ls -l" on all the files in the tree that are younger than a specified age: .nf $ 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 ~- > } .fi .sp Get file creation date: .nf $ stat -F '%d %m %Y' +mtime ~/.zshrc 30 06 2004 $ stat -F '%D' +mtime ~/.zshrc 06/30/04 .fi .TP \fBzsh/system\fP A builtin interface to various low\-level system features\&. .TP \fBzsh/net/tcp\fP Manipulation of TCP sockets .TP \fBzsh/termcap\fP Interface to the termcap database\&. .nf $ 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 .fi .TP \fBzsh/terminfo\fP Interface to the terminfo database\&. .TP \fBzsh/zftp\fP A builtin FTP client\&. .sp Write ftp scripts as though shell: .nf $ 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 .fi .sp Automatically transfer files using FTP with error checking: .nf $ zftp open host.name.invalid user passwd || exit $ zftp get /remote/file > /local/file; r=$? $ zftp close && exit r .fi .sp Compress and ftp on the fly: .nf $ zftp open host.name.invalid user password $ zftp get $file | bzip2 > ${file}.bz2 $ zftp close .fi .sp Long list of files on a ftp: .nf $ autoload -U zfinit $ zfinit $ zfopen some-host $ zfcd /some/remote/Dir $ cd /some/local/Dir .fi .sp 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 .fi .TP \fBzsh/zle\fP The Zsh Line Editor, including the \fBbindkey\fP and \fBvared\fP builtins\&. .TP \fBzsh/zleparameter\fP Access to internals of the Zsh Line Editor via parameters\&. .TP \fBzsh/zprof\fP A module allowing profiling for shell functions\&. .TP \fBzsh/zpty\fP A builtin for starting a command in a pseudo\-terminal\&. .nf $ 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 .fi .TP \fBzsh/zselect\fP Block and return when file descriptors are ready\&. .nf # 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 .fi .TP \fBzsh/zutil\fP Some utility builtins, e\&.g\&. the one for supporting configuration via styles\&. .RE .RE .\"####################################################### .\"####################################################### .SS "SUBSTITUTION" .sp Path substitution: .nf $ ls -l =zsh # is like: 'ls -l /path/to/zsh' or 'ls -l `which zsh`' .fi .sp Process substitution: .nf $ (vi =(cmd)) # edit output of 'cmd' (called process substitution). .fi .sp Substitution of variables: .nf $ var1=42 $ tmp=var1 $ echo $((tmp)) 42 $ $ var=foo $ tmp=var $ echo ${(P)tmp} foo .fi .\"####################################################### .\"####################################################### .SS "ALIASES" .P Suffix aliases are supported in zsh since version 4.2.0. Some examples: .nf alias -s tex=vim alias -s html=w3m alias -s org=w3m .fi .RS 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. .RE .P Global aliases can be used anywhere in the command line. Example: .nf $ alias -g C='| wc -l' $ grep alias ~/.zsh/* C 443 .fi .P Some more or less useful global aliases (choose whether they are useful or not for you on your own): .nf 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' .fi .\"####################################################### .\"####################################################### .sp Array parameters [array_name=(value1 value2 ... valueN)]. .nf $ stupid=emacs $ echo $stupid[3] a $ .fi .\"####################################################### .\"####################################################### .SS "SHELL-SCRIPTING" This section provides some examples for often needed shellscript-stuff. Notice that you should not use '#!/bin/sh' but '#!/bin/zsh' as the shebang-line because otherwise most examples won't work. .sp Parse options in shellscripts. Example taken from ZWS by Adam Chodorowski (http://www.chodorowski.com/projects/zws/): .nf 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 $* .fi .\"####################################################### .SS "MISC\-EXAMPLES" Hint: A list of valid glob Qualifiers can be found in zshexpn(1). See ``man 1 zshexpn | less -p'' Qualifiers for details. .sp Load all available modules at startup .nf $ typeset -U m $ m=() $ for md ($module_path) m=($m $md/**/*(*e:'REPLY=${REPLY#$md/}'::r)) $ zmodload -i $m .fi .sp Rename all MP3-Files from ``name with spaces.mp3'' to ``Name With Spaces.mp3'': .nf $ for i in *.mp3; do > mv $i ${${(C)i}:s/Mp3/mp3/} > done .fi .sp Download with LaTeX2HTML created Files (for example the ZSH\-Guide): .nf $ for f in http://zsh.sunsite.dk/Guide/zshguide{,{01..08}}.html; do > lynx -source $f >${f:t} > done .fi .sp Replace the unreadable Escape-Sequences: .nf $ autoload colors ; colors $ print "$bg[cyan]$fg[blue]You are an zsh user" >> /dev/pts/3 .fi .sp Filename\-Expansion. .B Note: (N) activates setopt nullglob only for this loop. .nf $ for i in *.o(N); do > rm $i > done .fi .sp Re-linking broken links: .nf $ for f in ./**/*(-@); do > stat +link -A l $f > (cd $f:h & [[ -e $l.gz ]]) & ln -sf $l.gz $f > done .fi .sp Show me all the .c files for which there doesn't exist a .o file: .nf $ c=(*.c) o=(*.o(N)) eval 'ls ${${c:#(${~${(j:|:)${o:r}}}).c}:?done}' .fi .sp Load all available modules at startup: .nf $ typeset -U m $ m=() $ for md ($module_path) m=($m $md/**/*(*e:'REPLY=${REPLY#$md/}'::r)) $ zmodload -i $m .fi .sp Rename all files within a directory such that their names get a numeral prefix in the default sort order: .nf $ 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; done .fi .sp Find (and print) all symbolic links without a target within the current dirtree: .nf $ $ file **/*(D@) | fgrep broken $ for i in **/*(D@); [[ -f $i || -d $i ]] || echo $i $ echo **/*(@-^./=%p) $ print -l **/*(-@) .fi .sp List all plain files that do not have extensions listed in `fignore': .nf $ ls **/*~*(${~${(j/|/)fignore}})(.) # see above, but now omit executables $ ls **/*~*(${~${(j/|/)fignore}})(.^*) .fi .sp Print out files that dont have extensions (require setopt extendedglob dotglob): .nf $ printf '%s\n' ^?*.* .fi .sp List files in reverse order sorted by name: .nf $ print -rl -- *(On) or $ print -rl -- *(^on) .fi .sp Synonymic to ``ps ax | awk '{print $1}''': .nf $ print -l /proc/*/cwd(:h:t:s/self//) .fi .sp Get the PID of a process (without ``ps'', ``sed'', ``pgrep'', .. (under Linux): .nf $ pid2 () { > local i > for i in /proc/<->/stat > do > [[ "$(< $i)" = *\\((${(j:|:)~@})\\)* ]] && echo $i:h:t > done > } .fi .sp for X in 'n' 'o' 'p' 'q' 'r' 's' 't' 'u' 'v' 'w' 'x' 'y'; do ...: .nf $ 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}' .fi .sp Foreach in one line of shell: .nf $ for f (*) print -r -- $f .fi .sp Copy a directory recursively without data/files: .nf $ 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"' '{}' '{}' \; .fi .sp If `foo=23'', then print with 10 digit with leading '0': .nf $ foo=23 $ print ${(r:10::0:)foo} .fi .sp Find the name of all the files in their home directory that have more than 20 characters in their file names: .nf print -rl $HOME/${(l:20::?:)~:-}* .fi .sp Save arrays: .nf $ print -r -- ${(qq)m} > $nameoffile # save it $ eval "m=($(cat -- $nameoffile)" # or use $ m=("${(@Q)${(z)"$(cat -- $nameoffile)"}}") # to restore it .fi .sp Get 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): .nf $ ls -tld **/*(m-2) .fi .sp This will give you a listing 1 file perl line (not like ls -R). Think of an easy way to have a "ls -R" style output with only files newer than 2 day old. .nf $ for d (. ./**/*(/)) { > print -r -- $'\n'${d}: > cd $d && { > l=(*(Nm-2)) > (($#l)) && ls -ltd -- $l > cd ~- > } > } .fi .sp If you also want directories to be included even if their mtime is more than 2 days old: .nf $ for d (. ./**/*(/)) { > print -r -- $'\n'${d}: > cd $d && { > l=(*(N/,m-2)) > (($#l)) && ls -ltd -- $l > cd ~- > } > } .fi .sp And if you want only the directories with mtime < 2 days to be listed: .nf $ for d (. ./**/*(N/m-2)) { > print -r -- $'\n'${d}: > cd $d && { > l=(*(Nm-2)) > (($#l)) && ls -ltd -- $l > cd ~- > } > } .fi .sp Print 42 ``-'': .nf $ echo ${(l:42::-:)} # or use ``$COLUMS'' $ echo ${(l:$COLUMNS::-:)} # and now with colors (require autoload colors ;colors) $ echo "$bg[red]$fg[black]${(l:42::-:)}" .fi .sp Redirect STDERR to a command like xless without redirecting STDOUT as well: .nf $ foo 2>>(xless) # but this executes the command asynchronously. To do it synchronously: $ { { foo 1>&3 } 2>&1 | xless } 3>&1 .fi .sp Rename all MP3-Files from name with spaces.mp3 to Name With Spaces.mp3: .nf $ for i in *.mp3; do > mv $i ${${(C)i}:s/Mp3/mp3/} > done .fi .sp Match file names containing only digits and ending with .xml (requiresetopt kshglob): .nf $ ls -l [0-9]##.xml $ ls -l <0->.xml .fi .sp Remove all "non txt" files: .nf $ rm ./^*.txt .fi .sp Move 200 files from a directory into another: .nf $ mv -- *([1,200]) /another/Dir .fi .sp Convert images (foo.gif => foo.png): .nf $ for i in **/*.gif; convert $i $i:r.png .fi .sp Convert a collection of mp3 files to wave or cdr (e.g. file.wav -> file.mp3): .nf $ for i (./*.mp3){mpg321 --w - $i > ${i:r}.wav} .fi .sp Download with LaTeX2HTML created Files (for example the ZSH-Guide): .nf $ for f in http://zsh.sunsite.dk/Guide/zshguide{,{01..08}}.html; do > lynx -source $f >${f:t} > done .fi .sp Move all files in dir1 and dir2 that have line counts greater than 10 to another directory say "/more10": .nf $ mv dir[12]/**/*.cr(-.e{'((`wc -l < $REPLY` > 10))'}) /more10 .fi .sp Make with dpkg a master-list of everyfile that it has installed: .nf $ diff <(find / | sort) <(cat /var/lib/dpkg/info/*.list | sort) .fi .sp Replace the unreadable Escape-Sequences: .nf $ autoload colors ; colors $ print "$bg[cyan]$fg[blue]You are an zsh user" >> /dev/pts/3 .fi .sp Get ASCII value of a character: .nf $ char=N ; print $((#char)) .fi .sp Filename suffix: Note: The (N) says to use the nullglob option for this particular glob pattern. .nf $ for i in *.o(N); do > rm $i > done .fi .sp Rename files; i. e. FOO to foo and bar to BAR: .nf $ for i in *(.); mv $i ${i:l} # `FOO' to `foo' $ for i in *(.); mv $i ${i:u} # `bar to `BAR' .fi .sp Show all suid-files in $PATH: .nf $ 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) .fi .sp gzip files when containing a certain string: .nf $ gzip ${(ps:\0:)"$(grep -lZ foobar ./*.txt(.))"} .fi .sp 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): .nf $ IFS=$'\n\n'; print -rl -- ${(Oau)${(Oa)$(cat file;echo .)[1,-2]}} .fi .sp Lists every executable in PATH: .nf $ print -l ${^path}/*(-*N) .fi .sp Match all .c files in all subdirectories, _except_ any SCCS subdirectories? .nf $ ls **/*.c~(*/)#SCCS/* .fi .sp List all `README' - files case-insensitive with max. one typo: .nf $ ls **/*(#ia2)readme .fi .sp Print version information of zsh: .nf $ print $ZSH_VERSION .fi .sp Get hostspecific information: .nf $ echo $MACHTYPE $VENDOR $OSTYPE .fi .sp Fast change of directories: .nf alias ...='cd ../..' alias ....='cd ../../..' alias .....='cd ../../../..' alias ......='cd ../../../../..' alias .......='cd ../../../../../..' .fi .sp Mailpath: simple multiple mailpath: .nf 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') .fi .sp Mailpath: dynamic mailpath: .nf typeset -a mailpath for i in ~/Mail/Lists/*(.); do mailpath[$#mailpath+1]="${i}?You have new mail in ${i:t}." done .fi .sp Avoid globbing on special commands: .nf for com in alias expr find mattrib mcopy mdir mdel which; alias $com="noglob $com" .fi .sp For migrating your bashprompt to zsh use the script bash2zshprompt located in the zsh source distribution under 'Misc'. .sp 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. .sp Here are functions to set the title and hardstatus of an \fBXTerm\fP or of \fBGNU Screen\fP 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: .nf 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]" } .fi Put the following line into your ~/.screenrc to see this fancy hardstatus: .nf caption always "%3n %t%? (%u)%?%?: %h%?" .fi .sp Special variables which are assigned or you can assign: .nf $ echo $LINENO $RANDOM $SECONDS $COLUMNS $HISTCHARS $ echo $UID $EUID $GID $EGID $USERNAME $ echo $fignore $mailpath $cdpath .sp Show me all the .c files for which there doesn't exist a .o file: .nf $ c=(*.c) o=(*.o(N)) eval 'ls ${${c:#(${~${(j:|:)${o:r}}}).c}:?done}' .fi .sp Find (and print) all symbolic links without a target within the current dirtree: .nf $ file **/*(D@) | fgrep broken $ for i in **/*(D@); [[ \-f $i || \-d $i ]] || echo $i $ echo **/*(@\-^./=%p) $ print \-l **/*(\-@) .fi .sp Rename files; i. e. FOO to foo and bar to BAR: .nf $ for i in *(.); mv $i ${i:l} # `FOO' to `foo' $ for i in *(.); mv $i ${i:u} # `bar to `BAR' .fi .sp Show all suid-files in $PATH: .nf $ ls \-latg ${(s.:.)PATH} | grep '^...s' .fi .sp List all `README' - files case-insensitive with max. one typo: .nf $ ls **/*(#ia2)readme .fi .sp .SS (RECURSIVE) GLOBBING\-EXAMPLES Search for `README' in all Subdirectories .nf $ print \-l **/README .fi .sp Recursive ``chmod'' .nf $ chmod 700 **/(.) # Only files $ chmod 700 **/(/) # Only directories .fi .sp List files beginning at `foo23' upwards (foo23, foo24, foo25, ..) .nf $ ls -l foo<23\-> .fi .sp Remove spaces from filenames .nf $ for a in ./**/*\\ *(Dod); do mv $a ${a:h}/${a:t:gs/ /_}; done .fi .sp Show only all *.c and *.h - Files .nf $ ls -l *.(c|h) .fi .sp Show .B only all *.c - files and ignore `foo.c' .nf $ ls *.c~foo.c .fi .sp Show only world-readable files .nf $ ls -l *(R) .fi .sp find and delete the files which are older than a given parameter (seconds/minutes/hours) .nf # 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 .fi .sp .B Explanation: .nf ./: to avoid problem with files starting with "\-" **/: recursively descend *.: any file (...): qualifiers: (,): files of type or type : .: regular files D: including dot files mh+1: whose [m]odification time, is more (+) than [1] [h]our in the past. : .: regular files D: including dot files L0: of 0 [L]ength. .fi .sp If you want to remove empty directories afterwards: .nf # ``/'' matches only directories and ``od'' sorted in depth order (so # that dir/subdir is removed before directory). $ rmdir ./**/*(/od) 2> /dev/null .fi .sp .B Note: If you get a arg list too long, you use the builtin rm. For example: .nf $ zmodload zsh/files ; rm -f **/*(mh+6) .fi or use the zargs function: .nf $ autoload zargs ; zargs **/*(mh+6) -- rm -f .fi .sp Delete only the oldest file in a directory: .nf $ rm ./*filename*(Om[1]) .fi .sp Sort the output from `ls \-l' by file size: .nf $ ls -fld *(OL) .fi .sp Find most recent file in a directory: .nf $ setopt dotglob ; print directory/**/*(om[1]) .fi .sp List the top 100 biggest files in a disk .nf $ zmodload \-i zsh/stat ; ls \-fld ./**/*(d`stat +device .`OL[1,100]) .fi .nf $ ls *(L0f.go-w.) .fi .sp Find all files without a valid owner: .nf $ chmod someuser /**/*(D^u:${(j.:u:.)${(f)"$( 1.foo, fnord.foo > 2.foo, ..): .nf $ 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 .fi .sp See above, but now only files with a filename >= 30 chars: .nf $ c=1 zmv "${(l:30-4::?:)}*.foo" '$((c++)).foo' .fi .sp Replace spaces in filenames with a underline: .nf $ zmv '* *' '$f:gs/ /_' .fi .sp Change the suffix from *.sh to *.pl: .nf $ zmv -W '*.sh' '*.pl' .fi .sp lowercase/uppercase all files/directories: .nf # lowercase $ zmv '(*)' '${(L)1}' # uppercase zmv '(*)' '${(U)1}' .fi .sp Remove the suffix *.c from all C-Files: .nf $ zmv '(*).c' '$1' .fi .sp Uppercase only the first letter of all *.mp3 - files: .nf $ zmv '([a-z])(*).mp3' '${(C)1}$2.mp3' .fi .sp Copy the target `README' in same directory as each `Makefile': .nf $ zmv -C '(**/)Makefile' '${1}README' .fi .sp Removing single quote from filenames (recursive): .nf $ zmv -Q "(**/)(*'*)(D)" "\\$1\\${2//'/}" .fi .sp Replace spaces with underscores in filenames (recursive): .nf $ zmv -Q "(**/)(* *)(D)" "\\$1\\${2// /_}" .fi .sp Rename pic1.jpg, pic2.jpg, .. to pic0001.jpg, pic0002.jpg, ..: .nf # Not recursively $ zmv 'pic(*).jpg' 'pic${(l:4::0:)1}.jpg' # Recursively $ zmv '(**/)pic(*).jpg' '$1/pic${(l:4::0:)2}.jpg' .fi .SS TIPS BY ZZAPPER (http://www.rayninfo.co.uk/tips/zshtips.html) .nf !! # 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?:* #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 # will complete matching files anywhere in $PATH startfilename # 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 .fi .\"####################################################### .\"####################################################### .sp Find file containing string 'printf' in /usr/include. .nf $ zargs /usr/include/**/*.h \-\- grep printf /dev/null .fi .sp A solution without zsh could look like: .nf $ find /usr/include -name \\*.h \-exec grep printf /dev/null {} \; .fi .sp Create a directory structure based on an existing one. .nf $ dirs=(**/*(/)) $ cd \-\- $dest_root $ mkdir \-p \-\- $dirs .fi .sp A solution without zsh could look like: .nf $ src=/usr/local $ dst=/opt $ cd "$src" $ find . -type d | cpio -pdmv "$dst" .fi .sp Uncompress file and read it .nf less <(gzip -cd foo.gz) .fi .sp A solution without zsh could look like: .nf $ gzip -cd foo.gz && less foo .fi .sp Print two files and sort them .nf $ sort ' redirection from truncating the given file if it already exists) .TP Spelling correction .sp correct (automatically correct the spelling of commands) correct_all (automatically correct the spelling of each word on the command line) dvorak (dvorak layout) .\"####################################################### .\"####################################################### .SH "LINKS" .TP The Z shell Homepage .B http://www.zsh.org/ .TP The Z shell FAQ .B http://zsh.sunsite.dk/FAQ/ .TP The Z shell wiki .B http://www.zshwiki.org/ .TP Mailinglistarchive .B http://www.zsh.org/mla/ .TP The Z shell reference-card (included in the zsh-lovers debian-package) .B http://zsh.sunsite.dk/Refcard/refcard.ps.gz .TP Adam Spier's UNIX shells page .B http://adamspiers.org/computing/shells/ .TP The Single UNIX (R) Specification, Version 2 - Shell Command Language Index .B http://www.opengroup.org/onlinepubs/007908799/xcu/shellix.html .TP Zzappers Best of ZSH Tips .B http://www.rayninfo.co.uk/tips/zshtips.html .TP The ZSH area on dotfiles.com .B http://www.dotfiles.com/index.php3?app_id=4 .TP Zsh Webpage by Christian Schneider .B http://strcat.neessen.net/zsh/ .TP The zsh-lovers webpage .B http://grml.org/zsh/ .TP IRC channel .B #zsh at irc.freenode.org .SH "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! .sp In alphabetic order: .nf 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 Stephane Chazelas - http://stephane.chazelas.free.fr/ Sven Guckes - http://www.guckes.net/ Sven Wischnowsky - http://w9y.de/zsh/zshrc .fi .SH "SEE ALSO" Manpages of zsh: .nf 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: .nf From Bash to Z Shell by Oliver Kiddle, Jerry Peck and Peter Stephenson ISBN: 1590593766 Also take a look at the section .B LINKS in this manpage. .SH "BUGS" Probably. This manpage might be never complete. So please report bugs, feedback and suggestions to . Thank you! .SH "COPYRIGHT" Copyright \(co 2005 Michael Prokop, Christian Schneider and Matthias Kopfermann. .\"###### END OF FILE ########################################################## .\" vim:tw=60