Shell configuration files

Shell Types
There are roughly three Unix shells in wide use:
 * sh and bash
 * tcsh, a csh-like shell
 * zsh (advanced sh-like shell)

The following sh-like shells is ignored:
 * ksh

Shell invokations
You can invoke a shell in different ways: Also, shells differentiate between: Note that a crontab script is a non-login script, but does not keep environment variables.
 * interactive: from a shell
 * non-interactive: as a shell script
 * login shell: first login, a new terminal window or ssh connection is opened
 * non-login shell: process started from a shell, environment variables are kept

As you can see bellow, the miscellaneous configure files are a complete mess. There can be system-wide and user-defined configurations, either always invoked or for a specific situation. For example, .bashrc is only invoked for interactive non-login invocations. Zsh even has two user-defined configuration files that are executed for login shells: .zprofile and .zlogin. To top it off, some shell also have a logout configuration file.

Available Shell Configuration Files
This section lists the possible configuration files for each shell in the order when they are called.

sh
Login files in order:

For interactive commands, use the follow code in the configuration file: case $- in *i*)    # commands for interactive use only     ... esac

bash
Login files in order:

Logout files in order:

If bash is run with the name "sh", it behaves as sh instead of bash.

zsh
Login files in order:

Logout files in order:

Note: for Debian, the global files are in /etc/zsh/ instead of /etc/

csh
Login files in order:

Logout files in order:

tcsh
Login files in order:

The order of /etc/csh.login and /etc/csh.cshrc may be reversed. The order of ~/.login and ~/.tcshrc, ~/.cshrc and ~/.history</tt> may be reversed.

Login files in order:

Desired Configuration Files
Instead of thinking about what configuration files are available, I think it is better to think what kind of configuration are logically required:
 * 1) Global settings. No real usage, use local variables and local settings instead.
 * 2) Environment variables. E.g. PATH=/usr/local/bin:/usr/local/bin:/opt/local/bin:/bin:/usr/bin:/usr/sbin:/usr/X11R6/bin</tt>. This should only be sourced for login shells, not consecutive forks. This allows users to override settings before forking. E.g. PATH=$PATH:.; mycommand</tt>.
 * 3) Local variables and local settings. E.g. unlimit</tt>, bindkey "^B" backward-word</tt>. This should only be sourced for interactive shells.
 * 4) Aliases. E.g. alias mv='nocorrect mv -i'</tt>. This should only be sourced for interactive shells.
 * 5) Auto-completion configuration. E.g. zstyle ':completion:*:*:*' hosts $ssh_config_hosts</tt>. This should only be sourced for interactive shells.
 * 6) Startup programs. E.g. biff, motd, clear, fortune, etc. This should only be sourced for interactive login shells.

What should go where?
We can now determine the most appropriate configuration files:

Sh considerations

 * 1) $ENV</tt> should be set to .bashrc</tt> by /etc/profile</tt> and /etc/csh.login</tt>. This makes sh behave more like bash. The last one is important if you fork a sh script from a tcsh shell.
 * 2) sh cron jobs should manually include /etc/profile</tt>.
 * 3) when running "sudo sh</tt>", $ENV</tt> is not executed. The workaround for this is to have users run "sudo -s</tt>" instead.

Bash considerations

 * 1) ~/.bash_profile</tt> calls both <tt>.profile</tt> and <tt>.bashrc</tt> manually. This avoids duplication of local settings from <tt>.bashrc</tt> to <tt>.profile</tt>.
 * 2) <tt>.bashrc</tt> should call <tt>/etc/bashrc</tt> manually.

Zsh considerations
I created two files, <tt>.zshalias</tt> and <tt>.zscompl</tt> which are sourced by <tt>.zshrc</tt>. This gives more focussed configuration files: source ~/.zalias source ~/.zshcompl

<tt>.zlogin</tt> runs for both interactive and non-interactive shells. Ideally, it should only run for interactive shell. I'm sure there is a trick to check for this, but since my <tt>.zlogin</tt> is empty, I haven't bothered to find out.

My ZSH files: .zshenv, .zprofile, .zshrc, .zshalias, .zshcompl, and .zshlogin

More on ZSH config files:
 * ZSH files. Miscellaneous ZSH links.
 * Example ZSH file in distribution

Invokation Order
Note that the execution order is different for each shell. Csh first calls csh.cshrc, then csh.login, but sh first calls profile, then bashrc:

Template Files
It is possible and recommended to add a few well-commented shell scripts to the users home directory. The following folders are copied when a new user is created:
 * Linux: /etc/skel
 * Mac OS X: /System/Library/User Template/*.proj/

Misaligned <tt>PATH</tt> for ZSH shell on Mac OS X
Mac OS 10.6 (Snow Leopard) and up always set the <tt>$PATH</tt> environment variable in <tt>/etc/zshenv</tt> (using <tt>/usr/libexec/path_helper</tt>). This causes the PATH to get changed if a child shell is called, for example using <tt>sudo -s</tt> or a shell invoking a shell script.

[freek@mymac] ~% echo $PATH /usr/local/bin:/opt/local/sbin:/opt/local/bin:/bin:/sbin:/usr/bin:/usr/sbin:/usr/X11R6/bin:/Developer/usr/bin:. [freek@mymac] ~% sudo -s [root@mymac] ~# echo $PATH /usr/bin:/bin:/usr/sbin:/sbin:/usr/local/bin:/usr/X11/bin:/usr/local/sbin:/opt/local/sbin:/opt/local/bin:/usr/X11R6/bin:/Developer/usr/bin:.

The simple fix is to set the PATH in <tt>/etc/zprofile</tt> instead of <tt>/etc/zshenv</tt>:

sudo mv /etc/zshenv /etc/zprofile

(Note that Mac OS X 10.5 had this call in <tt>/etc/zprofile</tt>. They probably changed to make it consistent for scripts, by making it harder for users to override the PATH. I disagree with that decision.)