The most common problem caused by misuse of shell startup files is that if you define environment variables in .bashrc
as opposed to .profile
, they are not defined in applications that are not launched from a shell in a terminal but rather from a GUI menu.
Defining environment variables from .bashrc
is generally not a good idea, but that's primarily because it's generally useless as the variables should already have been set at login time. It can cause a problem in practice if you (or an application) have deliberately changed the value of a variable (e.g. PATH
) in a program and you launch a shell from that program and expect the setting to have remained the same.
You can avoid the problem of environment variables being reset by defining a “sentinel” value, and not defining anything if the sentinel value is set:
if [ -z "$JMLANE_PROFILE_READ" ]; then
export ...
export JMLANE_PROFILE_READ=1
fi
Another problem caused by terminals starting login shells is that there are things that should only be done once when you log in, for example starting a password agent (e.g. ssh-agent
), or initiating a session (e.g. running startx
in certain circumstances). The sentinel variable avoids these issues.
A shell inside a terminal is always interactive. As long as you source .bashrc
from .bash_profile
when the shell is interactive, you don't need to worry about the terminal starting a login shell.
An additional wart of bash's startup file handling is that .bashrc
is read by non-interactive shells invoked by rshd or sshd. For example, when you do rsync somefile host.example.com:
, if your login shell on host.example.com
is bash, you can use .bashrc
there to set the path to include rsync
. You can tell you're in this situation because .bashrc
is read from a non-interactive shell.
## .bashrc
if [[ $- != *i* ]]; then
# either .bashrc was executed explicitly or this is a noninteractive rsh/ssh session
fi
Best Answer
To make bash parse a file when invoked as a non-interactive shell, you need to set the environment variable
BASH_ENV
to point to that file. Fromman bash
(section on INVOCATION):So where to set
BASH_ENV
?Either: If you want a variable to be available to the environment system-wide, a good place to put it is
/etc/environment
. This file is specifically made for system-wide environment variable settings. It is not parsed by the shell but by the PAM modulepam_env
, so you can not use shell syntax or variable expansion within, but only simple assignments of the following type:or
Changes will take effect at the next login/authentication, so switch to a new tty console or logout and re-login to your session.
On a standard desktop system, this should work for all types of authenticated sessions using PAM, including console logins, ssh and display managers, but also daemons such as atd and cron. If everything works as expected, then you are done and there is no need to read on.
However, mistakes do occasionally sneak into the PAM configuration files of some programs/distributions, so if
/etc/environment
is not parsed by a certain type of program, make sure that the necessary PAM module is loaded in the PAM configuration file for that program in/etc/pam.d
:(Note: The
readenv
flag which turns reading of the config file on/off should not actually be needed, since it is set to on (1) by default - but it doesn't hurt to make sure either.)Or: If you are working on a system that does not provide
pam_env
, then the best alternative that comes to my mind would be write a simple init script (or service unit file on systemd) that parses a custom config file (such as/etc/default/environment
) at boot.