Understanding Bash startup scripts
Posted on février 28, 2018 in computer-science
Most bash users know about the potential existence of the scripts .bashrc
, .bash_profile
, .profile
, .bash_login
in their HOME
directory. The role of these scripts is to setup the environment, that is, define the PATH, PS1, (prompt), EDITOR,... variables, aliases and functions, and maybe perform other tasks.
These scripts get executed at startup, but not systematically. To understand when they are processed, it is important to know that shells come into four flavors, depending on whether they are interactive or non-interactive, and login or non-login.
A few examples:
-
when you are already logged in, that is, you have opened a session, if you open a new terminal, you get an interactive non-login shell.
-
when you connect to a remote computer with
ssh remote
, you get an interactive login shell. -
when you execute a command on a remote computer with
ssh remote command
, the script or the command is executed in a login non-interactive shell. -
When you execute a script starting with
#! /bin/bash
, it is launched in a non-interactive non-login shell.
Now for the rules:
-
Login shells first execute
/etc/profile
, then look for~/.bash_profile
,~/.bash_login
and~/.profile
, in that order, and reads and executes commands from the first one that exists. -
Non-login interactive shells read and execute
/etc/bash.bashrc
, then~/.bashrc
(if they exist). -
Non-interactive scripts typically do not execute and prior script; they just inherit the environment from which they are called (but this behavior can be changed if a variable
BASH_ENV
exists, which specifies the name of a script to be executed before the non-interactive shell; seeman bash
)
Here are the implications:
-
Anything that should be available to a script MUST be in
~/.profile
, not.bashrc
, that is why the PATH should be defined in~/.profile
rather than.bashrc
. Another reason, is that scripts using/bin/sh
will also read.profile
. Ideally, because~/.profile
might be red by/bin/sh
, it should only contain stuff NOT specifically related to bash -
If you launch an application by clicking in a graphical shell (e.g. gnome), the application will only knows about the environment that was created at login. In particular, it will not know about stuff in
.bashrc
. . -
~/.bashrc
should contain anything that one might need at an interactive command line, like the prompt, aliases, environment variables for interactive applications. -
~/.bashrc
is reloaded every time you start a new copy of bash while~/.profile
is loaded only once, at log in (or if you explicitly call bash with the-l
option)
Recommendations:
-
~/.bashrc
must not print anything on the terminal. This can screw upsftp
for example. If you want to print stuff from .bashrc, check that it is executed interactively by adding the line[[ $- == *i* ]] || return
at the top. -
~/.bash_profile
should just load.profile
and.bashrc
(in that order) -
make sure that
~/.bash_login
does not exist (https://superuser.com/questions/789448/choosing-between-bashrc-profile-bash-profile-etc)
For more information, check out http://mywiki.wooledge.org/DotFiles