Initialization Files for Bash and Zsh
First of all, bash and zsh are only two shells out of various choices, but they are the most common ones (bash is by default in many Linux distributions, and zsh for most macOS users).
One should notice that most of their initialization files are different, while they share some of them because both shells are Bourne-compatible shells.
Shell Types
Shells are invoked with two properties: whether it is interactive and login.
- interactive login shell:
- log into a remote computer via ssh;
- sudo -i or sudo --login or su -
- log in local machine using TTY
- TTY here roughly represents those terminals created by OS at start up. On Ubuntu 20.04, it creates 7 TTY’s (1 for GUI login page, 2 for GUI, 3-7 are for text-only, can be used when the computer brokes; they can be triggered via ctrl + alt + [1-7]). Command tty and who tells relevant information.
- interactive non-login shell: open a new terminal
- non-interactive non-login shell: run a script
- non-interactive login shell: rarely occurred
To check if the current shell is interactive, use echo $- to see if it contains character i.
To check if the current bash shell is login, use shopt login_shell; for zsh shell, check if l is contained in echo $-.
Bash
Here are two ways to roughly categorize initialization files:
By scope:
- System-wide files: /etc/profile, scripts in /etc/profile.d, /etc/bash.bashrc (all located at /etc, effective for all users)
- Local files: ~/.profile, ~/.bashrc, etc. (all located at ~ (home directory), so it varies per user! usually, the home directory for super user (root) and normal users are different)
By shell type:
- Login shell: /etc/profile, ~/.profile, etc.
- Non-login shell: /etc/bash.bashrc, ~/.bashrc
This answer provides a great comprehensive explanation of details in bash initialization, it is worth your time reading through it.
This site provides this graph of init files invocation process in bash (though its depiction does not cover all cases).
Let’s talk about two major scenarios when one wants to modify the shell environment.
How to configure Bash for current user and all shell types?
The answer could simply be ~/.bashrc, but it may depend on your distribution.
It is widely seen that we can customize a particular user’s (bash) shell by modifying ~/.bashrc. This only affects this user, so commands will not take effect when you type commands like sudo <commands>.
However, unlike described above, it may bring into effect on both non-login and login shells. Let’s take a look at the file ~/.profile (on Ubuntu 20.04)
1# if running bash
2 if [ -n "$BASH_VERSION" ]; then
3 # include .bashrc if it exists
4 if [ -f "$HOME/.bashrc" ]; then
5 . "$HOME/.bashrc"
6 fi
7 fi
Though it is called by the login shell, it will also call .bashrc (usually used for non-login shell) if using bash.
How to configure Bash for all users and all shell types?
Similarly, just modify /etc/bash.bashrc.
But appended commands should be written at the beginning of this file because the script returns when this line detects that it is not an interactive shell
1# If not running interactively, don't do anything
2 [ -z "$PS1" ] && return
Even in a login shell, /etc/profile may call /etc/bash.bashrc if it uses bash. Still, please check if this applies to your distribution.
Further reading
Zsh
- /etc/zsh/zshenv and ~/.zshenv are loaded under every circumstance;
- login shell: /etc/zsh/zprofile and ~/.zprofile
- interactive shell: /etc/zsh/zshrc and ~/.zshrc
- login shell again: /etc/zsh/zlogin and ~/.zlogin
How to configure zsh for all users and all shell types?
To bring changes into effect for all users and all shell types, one can try to modify /etc/zsh/zshenv, but it does not recommend commands other than setting environment variables. Alternatively, one can modify /etc/zsh/zprofile and /etc/zsh/zshrc simultaneously.
One of my demands is to deactivate vanilla rm command (replaced by trash command) under any circumstance by setting an alias to it. Therefore, I modified both bash and zsh init files
- specifically, /etc/bash.bashrc, /etc/zsh/zprofile and /etc/zsh/zshrc
Disclaimer: my solution may be not elegant enough (may be redundant or even missing corner cases). In particular, users can unalias them.
Use soft link
Another demand is to copy my configuration files to the root user.
Use soft links to get a configuration copy from those who have already established zsh
The following creates soft links under $HOME folder (only soft link works for directory):
- ln -s /home/<user>/.zshrc $HOME/.zshrc
- ln -s /home/<user>/.oh-my-zsh $HOME/.zshrc
Then, change the owner and group of these two directories to root using chown, e.g.
chown root: /home/<user>/.zshrc
Change Shell
View each user’s login shell through cat /etc/passwd last column.
cat /etc/shells show paths of all available shells.
You can change it via chsh -s <shell path> [<username>], e.g. chsh -s /bin/bash and chsh -s /bin/zsh root. Alternatively, usermod -s <shell path> <username>.
To bring changes into effect, you need to log out.
How to log out?
For terminals, simply exit. For GUI desktop, you need to log out by clicking the button in the power off menu. Then, log in back.
To check which shell you are using, simply echo $SHELL.