Bash and Zsh shells have very different ways to start, and this can be an issue when we switch from one to the other and back.
First, we distinguish two
states for the shell:
- Login/non-login shell,
- interactive/non-interactive shell.
To indicate to a shell that it is a login shell, the calling process will
simply add a
- in front of his name (thus the shell will be called
-zsh). Some shells (like bash) allow command
line argument to fake login shells.
In a script, we can tell wether we are a login shell or not in a simple way:
shopt -q login_shell
[[ -o login ]]
A shell is interactive if it is invoked without argument (or at least none that imply a command).
In a script, we can tell wether we are an interactive shell:
[[ $- == *i* ]]
(It is possible to have an interactive shell with a script, for instance if a file is sourced).
Zsh behavior when invoked
- In all cases,
~/.zshenvare sourced (in this order).
- If it is a login shell,
~/.zprofileare sourced (in this order)
/etc/zprofileis chosen at compile-time and can vary depending on the system (On Archlinux it is
- If we have an interactive shell,
~/.zshrcare sourced (in this order).
- Finaly, if it is a login shell (again!),
~/.zloginare sourced (in this order).
Bash behavior when invoked
- If it is a login and interactive shell,
/etc/profileis sourced, and then the first existing one in
- If it is an interactive non-login shell,
- Finaly, if the shell is non-interactive,
$BASH_ENVis sourced (if available).
Bash behavior when invoked as sh
In many distributions,
sh is simply a soft link to
bash. In that case, bash will behave in a different way when
- If it is an interactive login shell,
$ENVis a file, it is also sourced.