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
Shell invocation is a bit of a complicated thing. The bash and dash man pages has INVOCATION
sections about this.
In summary they says (there is more detail in the man page, you should read it):
When bash is | it reads
-------------------------------|----------
login shell | /etc/profile and then the first of ~/.bash_profile, ~/.bash_login or ~/.profile that exists.
|
interactive non-login shell | /etc/bash.bashrc then ~/.bashrc
|
non-interactive shell | The contents of $BASH_ENV (if it exists)
|
interactive (as "sh") | The contents of $ENV (if it exists)
-
When dash is | it reads
-------------------------------|---------
login shell | /etc/profile then .profile
|
interactive shell | The contents of ENV (it it exists, can be set in .profile as well as in initial environment)
I don't know about other shells offhand as I never use any of them. Your best bet might be to set a couple environment variables to point at the common location script and manually source that (when appropriate) in the couple of cases that doesn't cover.
Best Answer
What you describe is normal behavior. Starting bash with the
-c
option will launch an non-interactive, non-login shell. This means that bash will not source any of its classic configuration files but the variable$BASH_ENV
instead. As explained in the bash man page:non-interactive, non-login shell:
interactive, login shell:
interactive, non-login shell
So, if you want your non-interactive, non-login shell to source
~/.bahsrc
, you will need to set the value ofBASH_ENV
to~/.bashrc
. Add this line to your~/.bashrc
or~/.profile
files: