Explanations for each zsh template file

From OS X Scientific Computing

Return to ZSH on OS X.

zsh_on_osx.png



Contents



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:

  1. Everything is really on one line. The escape (\) is for the newline, so every entry except the very last noncommented entry needs this.
  2. 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

/Library/init/zsh/man/man7

and

/Library/init/zsh/man/html

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.