Latest change: Sat Nov 22 21:44:36 CET 2003
An abstract description of the ZSHELL's features.
The ZSH is a great shell (aka "command line interpreter") which can make it a lot easier for beginners. However, even the Linux community has not really discovered it yet even though it has considerable advantages over bash and tcsh and a lot in common with sh and ksh.
This page lists describes some of ZSH's features to give you an idea of what is possible. Hopefully this is an alternative to your reading the fine manual - which, by the way, has almost 19,00 lines on an 80 column terminal for zsh 4.1.1.
have a lot of fun!
Sven Guckes webpage-zsh-lover(at)guckes.net Matthias Kopfermann matthi(at)infodrom.north.de
The string [zsh] is presented at the start of line to indicate that the following command is entered with a ZSH. It's just a precaution in case other examples are presented with eg the bash or the ksh.
"EOL" stands for "end-of-line".
Compatibility. The ZSH is based on ksh and also includes some features of bash and tcsh. There are many books on shells and shell scripting so there is lots of information about how this kind of program works and can be handled.
Emulation Modes.
For those who already know the basic shells (sh, csh, ksh)
there are emulation modes which tune the zsh such that it
behaves just like one of them, eg with emulate sh
.
(see the zshbuiltins manual, section "emulate" ). [link!]
Mind you, the emulation is not perfect. But it certainly
eases its use if you have used other shells before.
Configurability! The ZSH has over 130 options which allows adaption to the user's preferences and a lot of flexibility.
Modularity. The ZSH is modular. You can leave out all the modules and thus get a shell with a lot less memory than eg bash.
Expandability. There are a lot of expansion commands. This allows to expand command prefixes *and* parameter prefixes, prefixes of files and directory name, as well as expansion on environment variables,
man zshcompsys
-->
[Programmable expansion have been available since bash 2.04 since April 2000. However, the ksh does not have that feature at all.]
Instead of using a lot of extra options you can now
adjust the shell's expansions with the use of functions.
This also means that you can quickly generate
more completions by simply editing existing ones.
And ZSH already ships with quite a few completions,
eg try xterm -fn <TAB>
.
More examples for completions [using the old scheme up to 3.1.5]:
compctl -g '*(/)' cd
-
this makes "cd" complete on subdirs only.
compctl -k '(`command`)'
-
this allows to complete on all sorts of useful things,
eg complete on email addresses for the mailer
or on ftp addresses for the ftp client.
compctl -g '*.class(:r)' java
-
this will chop off the file extension on completion
which is useful eg with the java compiler.
(who would otherwise try to open "foo.class.class").
An alias name will only be expanded when it is the first word within the command.
However, a global alias will also be expanded when it occurs elsewhere.
Example:
alias -g L=' |less'
this allows to enter 'L' at the end of a command chain
to get the output piped to the "less" pager:
[zsh] cut -d: -f 5 /etc/passwd | sed 's/ .*//' | sort | uniq -c | sort -n L
Filename Exclusions.
The filename patterns are good for finding complicated matches,
however, there is usually no way to *exclude* some matches.
ZSH however allows the '^' to be used as a NOT operator, meaning
"match all dirs/files *not* matching the following pattern".
For example, ^(bar|foo)
would leave out "bar" and
"foo" from the list of all dirs+files in the current directory.
More specifically, ls ^(*.bz2|*.gz)
would list
all dirs+files not ending in either ".bz2" or ".gz".
ZSH allows to take away matches with the '~' character.
This requires setopt extended_glob
to be set.
Furthermore,
grep foo bar*~(*.gz|*.bz|*.bz2|*.zip|*.Z)
searches for "foo" in all files starting with "bar"
except those with an extension which
indicates that the data has been compressed.
As this list of extensions is already quote long for typing you might want to abbreviate it with a global alias. Make sure that the global aliases have a unique name; It's probably best to use an unusual character as their initial, eg the '§'.
alias -g §k="*~(*.bz2|*.gz|*.tgz|*.zip|*.z)"
Then ls -d §nk
will list all compressed files.
Use unalias '§k'
to get rid of the alias.
Mind the ticks around the alias name - because
if they were missing then the ZSH would expand them.
There is an alternative to stuffing all functions into one huge setup file: You can put each function into its own file, put them into some directories, point at these with $FPATH, and select their loading by means of autoload function .
man zshmisc
|
For each variable written in capital letters, eg PATH, there exists a variable by the same name in lowercase letters. If the upperase name is a list of items then the lowercase one contains these items separated by spaces.
Example:[zsh] echo $PATH /home/guckes/bin:/usr/local/bin:/usr/bin:/bin:/usr/bin/X11:/usr/games [zsh] echo $path /home/guckes/bin /usr/local/bin /usr/bin /bin /usr/bin/X11 /usr/games
This makes it a lot easier when dealing with such lists:
|
Note: When you are inside a "for" loop then the ZSH indicates this by indenting the input line with "for>".
And this makes assigning a value to a variable easier, too:
[zsh] path=( /home/guckes/bin /usr/local/bin /usr/bin /bin /usr/bin/X11 /usr/games ) [zsh] echo $PATH /home/guckes/bin:/usr/local/bin:/usr/bin:/bin:/usr/bin/X11:/usr/games [zsh] path=( array> /home/guckes/bin array> /usr/local/bin array> /usr/bin array> /bin array> /usr/bin/X11 array> /usr/games array> )
Again, ZSH helps to see the current context with showing a special input prompt, "array>".
You can now easily modify this input by going back to the command and move the cursor into the input, line by line, editing them, or even delete some:
path=( /home/guckes/bin /usr/local/bin /usr/bin /bin )
The input line of shells can be long, and even be *very* long. But these are displayed as *one* long line which gets broken across several lines on screen. A long line simply gets unreadble, very much like program code which is presented in one long line.
The ZSH has a builtin line editor which allows editing across several lines on screen - but *with* EOLs, so it allows to split up the input line into several lines making editing and reading a lot easier for the user. You can move the cursor between the parts of the input line up and down.
See also: man zshzle
The command insert-last-word
inserts the last word from the previous command line.
This easily reuses the word without having to type it in again yourself.
Simply type 'ESC' followed by '_' (underscore)
[zsh] ls -l .newsrc.news-cis-dfn-de [zsh] ln -s ESC_ .newsrc [zsh] ln -s .newsrc.news-cis-dfn-de .newsrc
[zsh] bindkey | grep insert-last-word "^[." insert-last-word "^[_" insert-last-word
See also: man zshzle
The print command is similar to "echo" - but allows to sort the input and set the output in columns.
Example: Print the list of letters on the keyboard in columns after they are sorted (option "-o").
[zsh] print -o -C 4 q w e r t y u i o p \ a s d f g h j k l z x c v b n m a h o v b i p w c j q x d k r y e l s z f m t g n u
Note that the last row spells "gnu"! :-)
And if you'd liked to check up on the expandos for the prompt then you can use option "-P" for this without the need to change PS1 at all:
The ZSH supports co-processes (just like the ksh). This allows to
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 mitcoproc
eingeleitet und nicht wie
bei der Ksh 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 notizen
und dann irgendwann
ls -l >&p
und nach einer Weile vielleicht
echo ".\nw " >&p
schreibt in einen parallel laufenden Koprozess, den altehrwürdigen Ed, Daten.
The typeset command is like "echo" - but a lot more powerful. It can align text, uppercase/lowercase it,
typeset -L2 name=werteintrag ;print "[$name]"
gibt linksformatiert "[we]" aus, die ersten 2 Buchstaben, umrahmt von [].
typeset -lL20 name=WERTEINTRAG;print "[$name]"
gibt in Kleinbuchstaben (-l für lower) "[werteintrag ]" 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.
See also: man zshbuiltins
, section "typeset"
man zshexpn
|
print -l *(m-1)
nur Dateien, die vor bis zu einem Tag
modifiziert wurden.print -l *(a1)
findet Dateien, auf die vor einem Tag zugegriffen wurde. print -l *(@)
findet nur die Links.ls -doF *(/)
findet nur die Verzeichnisse.chmod 640 *(W)
verändert die Rechte aller Dateien, in die jeder schreiben darf.
Das ist ja besonders riskant!
grep name *(.)
findet nur noch reine Dateien. Damit ist
die unsinnige Meldung "grep: bla: Is a directory" für alle Zeiten vermeidbar. 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 benutze allerdings lieber perl für solche Dinge und
habe dafür mg
entdeckt.
for i in [A-Z][A-Z]*(.); do mv $i ${i:l} ;done
ist ein sehr schneller Befehl,
um Dos-Dateien zu Dateien mit kleinen Buchstaben zu machen. Der Qualifier
:l (für lowercase) leistet hier ganze Arbeit.
print -l *(Lk+50)
gibt Dateien aus, die über 50 Kilobytes groß sind.
mutt -f =(zcat mailfold*.gz)
=()
steht 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 =(cat mail1 mail2 mail3 mail4)
ruft mutt mit einer temporären Datei, die
diese 4 Mailordner enthält, auf.
(mutt ist ein sehr schönes Mail-Programm, das ich empfehlen kann.
Mit mutt -f liest mutt nicht aus /var/spool/mail, sondern die Email-Datei,
hier mailfolder.gz)
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.
Noch viel besser: Statt einer temporären Datei kann man sogar einen
Koprozess bequem aufrufen, indem man <()
lynx -force_html <( gzip -cd komprimiert.html.gz ) ist kein
Problem . Hier wird lynx, was keine komprimierten Dateien lesen kann, mit dem
Output von gzip -cd komprimiert.html.gz
, besser einer named pipe
gespeißt, sehr cool!
Durch intelligente Kommunikation verschiedener Prozeße wird es möglich, daß 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 zweiter komprimierter Dateien miteinander.
Nach Setzung von READNULLCMD=less läßt sich eine Datei mit
< datei
unter less angucken.
Einfach ein <
vor die Datei setzen.
ls >datei1 >datei2 >datei3
oder
ls >> datei1 >> datei2
less < datei1 < datei2
make >logfile | grep Error
ls -l =emacs
kann ich beispielsweise in jedem Verzeichnis
gucken, wie groß emacs genau ist.
Ich muß nicht mehr den Pfad angeben.
Die Zsh guckt für mich im Pfad nach, wenn ich emacs im Pfad habe.
Ich kann auch beqüm Dateien, die im Pfad stehen, auf diese Art editieren.
jed =genial.c
editiert eine C-Funktion, wenn sie im Pfad gefunden werden kann.
print -l **/*.html
finde ich alle Html-Seiten, die
in allen Verzeichnissen unterhalb des jetzigen Verzeichnisses vorhanden
sind und gebe 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.
vared Variable
kann ich alle Umgebungsvariablen editieren.
Das finde ich praktisch, weil ich sofort die Variable erreiche und
nicht erst in einer Datei wie .zshrc nach ihr suchen muß.
Außerdem wirkt natürlich das Editieren der Variablen sofort.
dirs -v
zeigt mir alle Verzeichnisse, in denen ich in einer Sitzung
gewesen bin zeilenweise an, wenn ich wähle: setopt autopushd
Ich kann nun mit cd +2 das vorletzte Verzeichnis erreichen.
zzz () {
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.
}
mv datei.1 ~lm1
könnte meine Datei bequem nach /usr/local/man/man1/
verschieben, wenn ich lm1=/usr/local/man/man1
gesetzt haben sollte.info=/usr/local/info/
Hier 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 muß man so zuweisen:
info=/usr/local/info
, also ohne Slash am Ende.
autocd
erlaubt es, nur den Namen eines Ordners anzugeben.
Bei Eindeutigkeit wird dann sofort in diesen Ordner gesprungen.
z.B. springt bin
dann sofort in mein
bin-Verzeichnis.
%{ %}
eingerahmt werden.
Also zum Beispiel:%{^[[31m%}%~ %{[0m%}
.RED_PROMPT='%{^[[31m%}'
OFF_PROMPT='%{[0m%}'
RPROMPT=%l
zeigt mir beispielsweise an, auf welchem Rechner
ich mich befinde.RPROMPT=%n
zeigt den Benutzer an.RPROMPT=%T
zeigt die Zeit an.RPROMPT=%D{%d.%m.%y}
zeigt das Datum nach deutscher Dartstellung an.
setopt autocorrect
.alias <befehl>=nocorrect <befehl>
verhindert werden.
watch
wie unter der Tcsh.watch=(notme)
listet z.B alle Benutzer auf, die nicht ich sind :)
WATCHFMT='%n eingeloggt auf Terminal %l von %M seit %T '
watch=(@vorsicht_ist_angesagt)
, so werden alle Benutzer
aufgeführt, die von dem Server vorsicht_ist_angesagt eingeloggt sind.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. repeat
.
Möchte ich z.B. einen Werbemailer böswillig strafen,
dann könnte ich das so machen:
repeat 100 mail -s "spams suck" badcompany@devilsheart.com < flame
Dabei sollte allerdings bedacht werden, daß man damit meist harmlose Benutzer trifft, die schlechte Passworte haben und deshalb Räubern auf den Leim gegangen sind.
!?kommando
auf, habe ich die Möglichkeit,
vor der erneuten Ausführung zu gucken, ob es sich hierbei auch um das
gewünschte Kommando handelt. Ich drücke einfach TAB.
Ebenso kann man sich auch die genau betroffenen Dateien eines
global wirkenden Befehles (z.B. ls *.html) mit TAB ansehen.
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.
echo {1..7}"\n Wo ist Microsoft geblieben?"
ergibt: 1 2 3 4 5 6 7
Wo ist Microsoft geblieben?
echo "17*35" = $[17*35]
alias run-help=info
macht.
wohin () {
dirs -v
print -n "Wohin? "
read WOHIN
cd +${WOHIN:=0}
}
kann mit bindkey w wohin
auf Control-Ww
gelegt werden.
Dazu muß vorher zle -N
wohin deklariert worden sein, dieses User-Widget
wirkt beim nächsten Aufruf der Shell.
man_zshall() man zshall
und nachfolgendes Deklarieren von
zle -N man_zshall
kann durch Definition von
bindkey man_zshall
nun immer
bei ^Z
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 email zugeschickt, sondern gelangen
erst einmal in den Puffer und werden beim nächsten Kommando erst
auf dem Bildschirm ausgegeben.
sched +0:10 sysvbanner "Du mußt jetzt los"
führt in
10 Minuten in Großschrift auf dem Bildschirm eine Warnung zum gehen aus,
wenn dann das nächste Kommando eingegen wird, sonst erst beim Kommando, wenn das auch Stunden später sein sollte.
The name ZSH derives from Zhong Shao, teaching assistant at Princeton university (now [2004] at Yale). Paul Falstad thought that his login name, "zsh", was a good name for a shell.
Paul released zsh 1.0 to alt.sources on December 16th 1990.