Introduction to Z Shell
This is an expanded version of a message I wrote about Zsh ("z shell") a couple of years ago, after switching to it from a background in tcsh and bash.
Completions:
In zsh, you have vast control over completions. For example, if I type
% cvs a<TAB>
I get the following possible completions:
add admin annotate
And if I tab again, I start going through the list. By completing on "add", I can do:
% cvs add <TAB>
This results in it prompting me only with the files that are not in CVS. Cool, eh? It does this by checking CVS/Entries, and filtering based on those files.
The following completion works for man pages, so that "man perl<TAB>" lists every Perl man page--all 129 of them, only about 3 of which I can remember. This is from my zsh configuration file:
manpath=( $(man -w | sed -e 's/:/ /g') )
# Manual page completion
man_glob () {
local a
read -cA a
if [[ $a[2] = [0-9n]* ]] then
# specific section in manual ('n' is Tcl)
# strip off .gz (if any), then the section number.
reply=( $^manpath/man$a[2]/$1*(N:t:s/.gz//:r) )
else
# any section in manual
reply=( $^manpath/man*/$1*(N:t:s/.gz//:r) )
fi
}
compctl -f -K man_glob man
(Note that a similar function, from which this was adapted, uses the pattern
$1*(N:t:r), but that strips only the first suffix, so
/usr/share/man/man1/perlstyle.1.gz gets incorrectly converted to
perlstyle.1 instead of perlstyle.)
Directory aliases:
You can set "usernames" to directories, using the tilde syntax. Since my directories tend to be very deeply nested, especially with Java packages, this gives me a nice short summary of where I am. For example:
~drj% cd ~mcw ~mcw% pwd /opt/projects/code/subdirectory/anothersubdirectory/foo/bar
It "remembers" this, even when I'm moving around. So doing "cd .." and "cd bar" doesn't mess it up. And it can write the short name into the xterm title bar.
Alternative to "find":
Listing files recursively is far easier than doing, for example find .
-name "*.cpp" -mtime -2. For example, to list .cpp files changed within
the past two days:
~drj% ls **/*.cpp(m-2) src/Main.cpp syntj/src/SyntaxAnalyzer.cpp
To list all the directories (/) that were not (+) modified (m) within the past hour (1), excluding (~) any "doc" directories (*doc*):
~drj% ls -1d **/*~*doc*(mh+1/) astj/src/ src/ statj/src/ syntj/src/
Notice that files are always in alphabetical order, another useful feature.
Prompt:
The "right prompt" can also be set, via the RPROMPT variable.
This could be useful for reminders.
jpace@rigel ~drj % [... edit area ...] replace CDR
Process subtitution:
This feature automatically creates temporary files for retaining output of a process, useful for when you need multiple inputs into a second program. For example, to compare the lists of files of two hierarchies, thus showing the .cpp files that have been added and removed:
% comm -3 =(cd modifile.0; ls -1 **/*(.)) =(cd modifile; ls -1 **/*(.))
buildrpms
CVS/Entries
CVS/Repository
CVS/Root
CVS/Template
[ ... other files ... ]
The subcommand =(cd modifile.0; ls -1 **/*(.)) subcommand
changes directories, lists the files (.) in the older version of the project,
and captures that output. (In reality, it's written to a temporary file, the
name of which is passed to the comm command.)
So this is the equivalent of:
% cd modifile.0; ls -1 **/*(.) > /tmp/oldversion % cd .. % cd modifile; ls -1 **/*(.) > /tmp/newversion % cd .. % comm -3 /tmp/oldversion /tmp/newversion % rm /tmp/oldversion /tmp/newversion
but requires far less typing.
Here is my Z-shell environment.