Shell configuration files

From Exterior Memory
Jump to: navigation, search

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:

  • interactive: from a shell
  • non-interactive: as a shell script

Also, shells differentiate between:

  • 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

Note that a crontab script is a non-login script, but does not keep environment variables.

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:

Order File When? Recommended usage
1. /etc/profile login shell
2. ~/.profile login shell
3. $ENV always

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:

Order File When? Recommended usage
1. /etc/profile interactive login
2. ~/.bash_profile
or ~/.bash_login
or ~/.profile
interactive, login (non-fork) For environment variables
3. ~/.bashrc interactive, non-login (fork) For aliases and options
4. $BASH_ENV non-interactive

Logout files in order:

Order File When? Recommended usage
1. ~/.bash_logout interactive, "logout" (non-fork)

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

zsh

Login files in order:

Order File When? Recommended usage
1. /etc/zshenv always Should be empty.
2. ~/.zshenv always Hardly used
3. /etc/zprofile login shell
4. ~/.zprofile login shell For environment variables
5. /etc/zshrc interactive
6. ~/.zshrc interactive For aliases and options
7. /etc/zlogin login shell
8. ~/.zlogin login shell For running external commands (msgs, biff, fortune, clear)

Logout files in order:

Order File When? Recommended usage
1. ~/.zlogout login shell
2. /etc/zlogout login shell

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

csh

Login files in order:

Order File When? Recommended usage
1. /etc/csh.cshrc always
2. /etc/csh.login login shell
3. ~/.cshrc always For aliases and options
4. ~/.login login shell For environment variables

Logout files in order:

Order File When? Recommended usage
1. ~/.logout login shell
2. /etc/csh.logout login shell

tcsh

Login files in order:

Order File When? Recommended usage
1. /etc/csh.cshrc always
1. /etc/csh.login login shell
3. ~/.tcshrc
or ~/.cshrc
always
3. ~/.history
or $histfile
login shell
3. ~/.login login shell
3. ~/.cshdirs
or $dirsfile
login shell

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

Login files in order:

Order File When? Recommended usage
1. ~/.logout login shell
2. /etc/csh.logout login shell

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. This should only be sourced for login shells, not consecutive forks. This allows users to override settings before forking. E.g. PATH=$PATH:.; mycommand.
  3. Local variables and local settings. E.g. unlimit, bindkey "^B" backward-word. This should only be sourced for interactive shells.
  4. Aliases. E.g. alias mv='nocorrect mv -i'. This should only be sourced for interactive shells.
  5. Auto-completion configuration. E.g. zstyle ':completion:*:*:*' hosts $ssh_config_hosts. 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:

File Type Scope Zsh Sh / Bash Csh / Tcsh
Global settings Always .zshenv N/A .cshrc
Environment variables Login .zprofile .profile .login
Local settings Interactive .zshrc .bashrc .cshrc
Aliases, autocompletion Interactive .zshrc .bashrc .cshrc
Startup programs Login + Interactive .zlogin N/A .cshrc

Sh considerations

  1. $ENV should be set to .bashrc by /etc/profile and /etc/csh.login. 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.
  3. when running "sudo sh", $ENV is not executed. The workaround for this is to have users run "sudo -s" instead.

Bash considerations

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

Zsh considerations

I created two files, .zshalias and .zscompl which are sourced by .zshrc. This gives more focussed configuration files:

source ~/.zalias
source ~/.zshcompl

.zlogin 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 .zlogin is empty, I haven't bothered to find out.

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

More on ZSH config files:

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:

File Type Zsh order Sh order Csh order
systemwide login: 1st (/etc/zprofile) 1st (/etc/profile) 2nd (/etc/csh.login)
user defined login: 2nd (~/.zprofile) 2nd (~/.profile) 4th (~/.login)
systemwide interactive 3rd (/etc/zshrc) 3rd (/etc/bashrc) 1st (/etc/csh.cshrc)
user defined interactive 4th (~/.zshrc) 4th (~/.bashrc) 3rd (~/.cshrc)

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/


Bugs

Misaligned PATH for ZSH shell on Mac OS X

Mac OS 10.6 (Snow Leopard) and up always set the $PATH environment variable in /etc/zshenv (using /usr/libexec/path_helper). This causes the PATH to get changed if a child shell is called, for example using sudo -s 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 /etc/zprofile instead of /etc/zshenv:

sudo mv /etc/zshenv /etc/zprofile

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