Explanations for each zsh template file
From OS X Scientific Computing
| Return to ZSH on OS X. |
The /etc files
These are the "master" control files for zsh. They control everything else in the next two sections.
/etc/zshenv
The instruction to source the /etc/zshenv file, when present, is hard-coded in the /bin/zsh binary. This file is always run, even if zsh -f is used, so it is best not to put stuff in this file that you only want in an interactive shell session. (Non-interactive sessions include things like shell scripts, which often start with the line #!/bin/zsh -f. If you want various environment variables and PATHS and so on available to shell scripts, it is a good idea to put such things in the zshenv file.
Our /etc/zshenv is basically a skeleton, and it mostly checks for the presence of subsidiary environment files, and if it finds them in expected locations like /Library/init/zsh, it will source each file it finds. This permits greater organization, modularity, and control, but it can make things a bit confusing.
Here is what happens:
We check to see if we are on OS X (Darwin), and if this is true, check to see if Fink is installed.
If you have /sw, it takes care of the rest for you. If you installed fink somewhere else, you need to supply this location manually by editing the file, changing ALT_SWPREFIX to whatever your equivalent of the /sw directory is. If you install the zsh-templates fink package, it does this for you, so don't worry.
We tell zsh where we put all the other files
zsh won't know to look for files in /Library/init/zsh or other locations unless we tell it to. Here we define some variables to point zsh in the right direction:
- ZDOT='/Library/init/zsh' --- This defines where the files in sections two and three below are
- ZDOT_USER='~/Library/init/zsh' --- You can set up your own personal custom set of files in ~/Library/init/zsh and zsh will look here
- ZDOT_TEMPLATE --- If you installed zsh-templates with fink it will look here in addition to $ZDOT, if $ZDOT exists, otherwise instead.
Initialize fink, if present
We then look for Fink files.
The first actual environment setup we perform is to source the /sw/bin/init.sh . This ensures the Fink environment is set up correctly.
If you don't have fink, ...
it is programmed to whine: WARNING!! Fink does not appear to be present. If you really don't have fink, and have no desire to use it, issue the command
touch ~/.finknowarn
to make a dummy invisible file, and this warning will now shut up and go away. That's the last you will have to worry about it. I promise.
Export Environment Variables
The file /Library/init/zsh/environment is now sourced. It is described below in the second section.
Set the PATH Variable
This is probably the single most important task this file performs. If you are having a PATH problem, look here first.
The main trick to setting $PATH is to make certain you haven't left anything out. We go through and systematically test for the presence of every executable directory, and either prepend or append it to the $PATH variable. You should, as a bare minimum, have these in your OS X $PATH:
MIN_PATH=/bin:/sbin:/usr/bin:/usr/sbin:/usr/libexec
So we keep adding on to that. If every executable directory this process tests for exists, you will have the following in your $PATH:
- /sw/bin
- /sw/sbin
- /bin
- /sbin
- /usr/bin
- /usr/sbin
- /usr/libexec
- /usr/X11R6/bin
- /Developer/Tools
- /Library/Tcl/bin
- /opt/local/bin
- /opt/local/sbin
- /usr/local/bin
- /usr/local/sbin
- ~/bin
- ~/.bin
- .
Yes, it adds " . " (the current directory) by default at the end, where it is fairly safe to have it. If you don't want that, comment out the line "APPEND_PATH=$APPEND_PATH:."
The /opt/local paths exist for example if you have installed DarwinPorts.
The command
typeset -U path
keeps $PATH and the cojoined $path array from accumulating duplicates.
Set the FPATH Variable
This is the second-most important task that this file performs.
zsh will look for individual zsh shell script files contained in directories defined in the $FPATH variable and will make them available for loading on demand. (You have to issue commands like "autoload -U zcalc", which is what the function environment files in section two are for).
By default, directories such as /usr/share/zsh/4.2.3/functions and /usr/share/zsh/site-functions are hard-wired into the zsh $FPATH, so we take care not to clobber them. We test for additional function directories, so you could potentially have the following in $PATH if all are present:
- $ZDOT_TEMPLATE/local-functions
- $ZDOT/local-functions
- $ZDOT_USER/my-functions
where those ZDOT variables are defined in 1.1.2.
The command
typeset -U fpath
keeps $FPATH and the cojoined $fpath array from accumulating duplicates.
/etc/zshrc
The instruction to source the /etc/zshrc file, when present, is hard-coded in the /bin/zsh binary. This file is supposedly not run, if zsh -f is used, so it is best to put stuff in this file when you only want in it sourced in an interactive shell session.
Like /etc/zshenv, this is mostly a skeleton file, that looks for other files, and if it finds them, it sources them.
More environment setup
The /etc/zshenv file has already sourced
- /Library/init/zsh/environment
That file has all the environment settings you would normally need even in a non-interactive session. This file source two more environment files:
- /Library/init/zsh/environment.local
- ~/Library/init/zsh/environment.mine
The first of these is described below in the second section. The second is one you can create if you need additional settings. (A more straightforward alternative is to put such things in ~/.zshrc. )
Sanity checks
/etc/zshenv is run before /etc/zshrc. If /etc/zshenv is missing or for some reason didn't get run right, this has some double-checks and warnings that you need to heed.
Define Aliases
Next we define aliases that are contained in the files
- /Library/init/zsh/aliases
- /Library/init/zsh/aliases.local
- ~/Library/init/zsh/aliases.mine
These are described in the next section. The third does not exist unless you create it. Again, ~/.zshrc is a popular alternative.
Define Functions
These directives are interleved with the alias directives. They source files that tell zsh what functions to load, and are further described in the next section. The functions themselves are described in the third section.
- /Library/init/zsh/functions --- define what zsh-supplied functions to load
- /Library/init/zshfunctions.local --- define what zsh-template functions to load
- ~/Library/init/zsh/functions.mine --- your functions can be loaded here (or in .zshrc).
Autocompletion
Finally, we load the autocompletion function compinit last. Almost all of the functions that start with _foo are autocompletion functions, typically for the commands named _foo (although the mapping can be homomorphic).
Programmable autocompletions are one of the most beautiful features of zsh. All autocompletion functions are made available by default. If a completion function is giving undesired behavior, it is best to copy it and edit the file, and then put it in the local-functions directory, where it will be read first.
Files in /Library/init/zsh
Environment files
There are three environment files in /Library/init/zsh. The first two are sourced by default.
- environment -- These are relevant to general use of OS X and should all be harmless
- environment.local -- These are customizations that should all be improvements but some things you may want to turn off
- environment.xtal -- Not read by default. Environment variables only crystallographers will care about.
The /Library/init/zsh/environment file
This sets up the environment in ways that should be helpful to any user of the system
Activating X11 (now off by default)
The first thing this file does is to set up an X11 environment. It is designed to work with the fast-user-switching feature of OS X (10.3 and above) so that multiple users can simultaneously use X11. This has only been developed for X11.app, which Apple supplies, but there is no reason why this cannot be done for other X11.app replacements.
The first feature is turned off by popular demand (what the hell is wrong with people?). You can turn it back on by commenting out the line
export open_apple_x11='skip'
When the above variable is unset, the file issues the command "open -a X11" if X11.app is not already running. I make a point of including it in my login Account startup items, so the shell does not have to do this for me. But if for some reason X11 is not running, this starts X11. You can turn off this behavior for individual users if you don't want it by issuing the command
touch ~/.skipxrc
Sanity checks and minor settings
Next, some sanity checks are performed, to make sure the environment was set up correctly in /etc/zshenv before we got to this point.
Then the variables
zdotdir=/Users/$USER host="--host=powerpc-apple-darwin"
are set.
Everything from this point on is only run if the session is interactive AND it is not a remote (ssh) connection.
On 10.3, some functions rely on having a locatedatabase available, so if this is nonexistent and out of date on 10.3, you are asked to run
sudo /etc/weekly
to update it. This is no longer required on 10.4, where we instead make use of mdfind (the command-line equivalent of spotlight).
The $MANPATH variable
The $MANPATH is assembled using a procedure similar to what was done for $PATH and $FPATH.
The $HELPDIR variable and run-help command
The $HELPDIR is assembled using a procedure similar to that for $PATH and $FPATH and $MANPATH. Note that is is a better implementation that what zsh uses by default, but it is done in such a way as to remain compatible with either the supplied run-help function or my augmented run-help function. man run-help
$HELPDIR and $helpdir are then explicitly tied together like $PATH and $path
Set up X11 $DISPLAY properly for multiple simultaneous users
This will only work if X11.app is running, otherwise it will skip this section but give you a warning:
X11.app does not appear to have been started. If you need to run X-windows programs from Terminal/iTerm, please start X11.app and then preferably a new shell. Type touch ~/.znowarn to get rid of this warning message.
To get rid of the warning, either start X11.app when you log in, or issue
touch ~/.znowarn
There is a rather involved part of the environment script that will set the $DISPLAY variable properly.
If you are the only one logged in, ever,
export DISPLAY=:0.0
would be all you would need, and this is in fact what happens if X11.app is not detected. But say someone else comes along, uses Fast User Switching and logs in while you are still running X11. They will need
export DISPLAY=:1.0
which seems simple enough, until you try to figure out what a third user gets if she logs in after the first user has logged out. This solves the problem. It is a kafkaesqe hack.
Setting zsh Environment Options
There is a long list of possible zsh environment options. These for the most part are set in exactly the way recommended with the zsh distribution, and these entries are what is distributed with the suggested zshenv. I have moved these here for organizational reasons. The option entries are of the form:
setopt \
append_history \
auto_list \
...
NO_sun_keyboard_hack \
unset \
NO_verbose
...
# sh_option_letters \
# NO_sh_word_split \
Notice two things:
- Everything is really on one line. The escape (\) is for the newline, so every entry except the very last noncommented entry needs this.
- Everything commented out comes after the non-escaped new-line at the end. So if you want to turn one of those that is off on, you need to copy and everything except the # sign and paste it in before the end (i.e., the penultimate position). Alternatively, just issue another setopt comand somewhere else, like environment.local or .zshrc.
For individual explanations of each option, I am going to refer you to the Comprehensive Manual
Setting zsh Styles, Tags and so on ('bells and whistles')
Again, most of these settings have been taken directly from the zsh distributed options. There is a lot here. Styles and tags control completion behaviors and other command-line experiences, and can be tailored globally or fine-tuned for individual sets of commands or individual commands. I am going to refer you again to the Comprehensive Manual
Here's one nice example: If you have a command that has more than 10 (you can change the number) possible completions, tabbing through the list can get tedious, so this gives you a reverse-video selection menu in which you can use the arrow keys to find your choice. This is nice if you have 600 files to choose from, for example:
# enable menu selection zstyle ':completion:*' menu select=10
Setting zsh Key Bindings
Most of the Key Bindings are pretty standard, and are distributed with the zshenv sample file. However, there is a check to see if you want to use vi rather than the default emacs key bindings:
if [[ -f ~/.zshvi ]];then
bindkey -v
print "Using vi key bindings!"
else
bindkey -e
fi
So if you want to use vi key bindings, simply issue the command
touch ~/.zshvi
and if you want to go back to the default emacs key bindings, issue
rm ~/.zshvi
The /Library/init/zsh/environment.local file
Many of these entries are specific to zsh-template supplied functions and programmed completions.
More options and local settings
A dummy file ~/.zrefresh is created/touched whenever this file is run. This in turn triggers other updates to keep them refreshed. We also run an mdfind command in the background that will help to speed up the "open -a" completion system.
The remaining instructions are only processed in an interactive session.
An interactive login message will be generated with some basic information. Here is a real example:
Time: 23:21 up 5 days, 15:18, 4 users, load averages: 0.28 0.24 0.23 laptop-wgs.local::/Users/wgscott Initializing zsh version number 4.3.2
I thought cyan was unobtrusive.
The command
typeset -U path manpath fpath
keeps duplicates out of $PATH, $MANPATH and $FPATH (it doesn't hurt to keep doing this).
In general, we don't kill background jobs upon logging out
setopt nohup
Most people use multiple terminal sessions simultaneously, so we would like to share history between terminal sessions
setopt share_history
Local Zstyles
More zsh style settings are now introduced.
For example, if you issue the command string
open -a wor\tab
you would like it to expand to
open -a Microsoft\ Word
putting in the capital letters and transmogrifying "word" or "Word" into "Microsoft\ Word". The following style does all this:
zstyle ':completion:*:*:open:*' matcher 'm:{a-z}={A-Z} r: ||[^ ]=**'
Local Environment Variables
Next we add a few more environment variables. Most of these are navigational short-cuts specific to OS X. for example,
export unstablefink=$SWPREFIX/fink/dists/unstable/main/finkinfo
allows me to issue
cd $un\tab
and the completion system expands this to
cd $unstablefink
which is the equivalent to typing
cd /sw/fink/dists/unstable/main/finkinfo
Finally, if you uncomment the line
# USE_XTAL='YES'
zsh will source the environment.xtal file. By default it does not do so.
Add Your Own Local $PATH and $FPATH Variable Elements Here
If you want to add an element to the $path array systemwide, here is a good place to do so:
if [[ -d /example/path/bin ]]; then
PATH=$PATH:/example/path/bin
fi
Just replace /example/path/bin with the path you have in mind.
A similar template exists for $FPATH, and you can probably figure out how to do this now for $MANPATH.
Host and User names Completions Settings
One of the really nice features of zsh is that it allows username and hostname completions, so the ssh command, for example, will let you complete with any known user name and host name.
ssh wg\tab
completes to
ssh wgscott@
and then another poke on the tab key allows me to complete from a list of all known host names. This is very cool, but the catch is that zsh needs to know what users and hosts to use. By default, it gets this information from /etc/passwd and /etc/hosts. But this isn't great, at least on OS X, where /etc/passwd contains all sorts of "user" names like clamav and www. Worse, /etc/hosts is pretty much empty.
The solution is to be able to edit the completion options easily. Wataru Kagawa developed a very nice GUI interface for doing so. This is controlled with two functions:
Please read those pages for more details about how this works, or just issue the commands to see how it works.
Local Java CLASSPATH variables
The variables
- CLASSPATH
- JAVA_CMD
- JAVA_HOME
- JBOSS_CLASSPATH
- JIKESPATH
are, or can be, set here. This section contributed by Gary Kerbaugh, who knows something about Java, which I sure don't.
The /Library/init/zsh/environment.xtal file
These have environment settings of interest only to crystallographers, and the file is not used by default. It is my gift to my user community.
Alias files
There are two alias files:
- aliases
- aliases.local
The division of the content is rather arbitrary. My aim is to have put all of the stuff you might want to change or take objection to in aliases.local, so you can just skip reading the file but still retain a few useful aliases.
The Library/init/zsh/aliases file
There are only a few aliases (alii?) in this file. These were contributed by Gary Kerbaugh. The file is pretty much self-explanatory.
In zsh, as with bash, the syntax is
alias foo='bar'
In almost all cases, you are better off writing a function of the form
function foo {
command bar "$@"
}
If you have an alias and a function with the same name, the alias prevails. The "command" in the function is important if foo and bar are the same command, as it avoids recursions. (zsh is pretty good about this, but can be outsmarted if the command is aliased as well.)
The Library/init/zsh/aliases.local file
These are more idiosyncratic aliases, some of which you may simply hate and want to comment out. Most are harmless. The one most likely to cause objections is
alias rm="rm -i"
I do this for safety reasons (it prompts you to ask if you really want to remove the file), but there are lots of arguments for why you might not want to do this.
This one I really like, and was able to construct it with the help of Gary Kerbaugh. It is an example of an alias in which it is hard to imagine how to write a function to do the same thing (usually you are better off having functions than aliases):
alias fu='sudo $( fc -ln -1)'
So you type a command, and the reply is that you don't have root permissions. Then you just type the inspirational response
fu
and your command is repeated, with the magical "sudo" prepended.
Sometimes the ordinarily helpful zsh correction mechanism can get irritating, so you can turn it off this way:
alias mkdir='nocorrect mkdir'
There are a number of other aliases in this file that you might like to use, so it is worth reading the file. The last on the list is the
cd?
command. It is a complicated alias to my gdirs command. Typing the command gives a listing of the last 20 unique directories visited, and unlike the standard dirs command, this is shared among terminal sessions:
% cd? 1 /usr/share/zsh/4.3.2/functions 2 /Users/wgscott 3 /Users/wgscott/Desktop ... 20 /Users/wgscott/death_warrants
gdirs gives a selectable gui menu version of this listing.
Function files
There are two function files and one directory in /Library/init/zsh. These are named
- functions
- functions.local
- local-functions/
The /Library/init/zsh/functions file
This file determines which zsh-supplied functions are to be made available to all users of the system. I've attempted to list all that you would conceivably want to turn on.
What is on by default
By default, only a couple are on:
- zcalc
- zmv
and the latter has a useful alias:
alias mmv='noglob zmv -W'
that permits you to batch-rename a set of files with one command, eg:
foo_001.img ... foo_720.img can all be renamed to start with bar_ like this:
mmv foo_*.img bar_*.img
and zsh does the right thing.
User Control Options
Just uncomment any other function entry to get it to make it available.
The /Library/init/zsh/functions.local file
Description
This file does the same thing as the functions file, but for the functions distributed with zsh-templates. I have tried to comment the file to some degree, but the best way to find out what the functions do is to consult the (almost complete) on-line documentation or man pages.
User Control Options
I've tried to group these according to whether or not you might be likely to use them. For further control, at the top of the page, I define three environment variables:
LOAD_ESSENTIAL_FUNCTIONS='YES' LOAD_POSSIBLY_ANNOYING_FUNCTIONS='NO' LOAD_CRYSTAL_FUNCTIONS='NO'
Change 'NO' to 'YES' if you want the second or third batch read by default. Alternatively, if you put a file (even an empty one) called ~/.zlocalfxn in a user's home directory, the 'NO' setting will be over-ridden for that user, so issuing the command
touch ~/.zlocalfxn
is the equivalent to setting the second variable to 'YES' for a single user. Similarly, for the third option, if you have installed crystallographic software via fink, and therefore have
/sw/share/xtal
the crystallography functions that an ordinary user would not want will become available. (These functions reside in a specific subdirectory described in the next section.)
The function files that this file makes available reside in the subdirectory called ....
The /Library/init/zsh/local-functions/ directory
There are five subdirectories in the local-functions directory, in an attempt to organize the functions distributed with zsh-templates. Click on the links to see the most up-to-date listing of the contents.
Functions that begin with _foo are programmed completions for the command foo. (Occasionally there are ancillary completion functions with the underscore prefix as well.)
You can browse an (almost complete) list of functions in the on-line documentation.
Here are the five subdirectories:
darwin/
These are completions and functions that are unique to OS X. For that reason, most of the functions and completions reside in this directory.
etc/
This directory contains shell scripts and other files that are not functions themselves, but that some of the functions need in order to function. The file vim_binary_plist.rc, for example, is read by vim when it encounters a file called foo.plist in binary format. (That file is from Moritz Heckscher).
general/
These are functions and completions that should work on any unix platform (they are not OS X specific, although some have optional features that only work on OS X).
opt/
These are functions that might really annoy you or give unexpected behavior. Some do nothing more than put the command name in a terminal menu bar and tab. These are not loaded by default.
xtal/
These are functions and completions that only crystallographers would find of use.
Others
There are two other entries in /Library/init/zsh. These are called
- man/
- prompt
and contain the manual page entries (for the man command, and html versions) in the subdirectories
The Manual Pages
and
the latter are more easily browsed using either [this link or by pointing a Mozilla-style web browser (eg: Camino, FireFox, SeaMonkey) to the directory /Library/init/zsh/man/html.
Customizing the Command-line Prompt
The file prompt controls the appearance of the shell prompt. By default, this is
zsh-%
for ordinary users, and
zsh-#
for the root user. Many people want something more elaborate, and zsh makes this easy. There is an associated function command called
switch_prompt
that lets you pick from a menu and to change the prompt interactively. The menu gives you the list of zsh-supplied prompts, as well as my "simple" default one, and a very nice one written by Gary Kerbaugh that I have called "kerbaugh". There is also one called "off" that just gives you the percent sign, but it's main function is to clear out residue form some of the more complex prompts if you are switching around.
Functional Clusters
Several sets of functions work together in a cluster or program suite. I've created a separate wiki page to describe ZSH Template Function Suites
| Return to ZSH on OS X. |

