On a modern system it is not especially common to run into the cases where it matters, but it does happen. (In particular, if you use shell operations in vim
such as :r !command
or the in-line !<motion>command
form.)
What would you put under ~/.bashrc? only aliases?
You put things in ~/.bashrc
that would not be inherited by subshells automatically; this means aliases and functions, mostly, although sometimes you have variable settings that you don't want visible outside the shell (this is very rare). It could be argued that those should be exported somehow, but various experimental attempts have run into compatibility issues with trying to hide them within the environment and have mostly been abandoned.
If I want to set an environment variable and add it to the PATH (for example JAVA_HOME) where it would be the best place to put the export entry? in ~/.bash_profile or ~/.bashrc?
You put environment settings in ~/.bash_profile
so that they are given sane initial settings. Sometimes you will want to override these (often this is done by complex environments such as Matlab or Cadence); if you put the environment settings in ~/.bashrc
then shells run from within those environments will lose the environments' customizations, and things may not work properly as a result. This also applies if you use a package like modules, virtualenv, rvm, etc. to manage multiple development environments; putting your settings in ~/.bashrc
means you can't run the environment you want from within your editor, but instead will be forced into the system default.
In a non-login shell, I believe the ~/.bash_profile is not being "picked up".
This is correct; you normally want the initial shell to be a login shell and any shells started under that one to not be login shells. If the initial shell is not a login shell, you won't have a default PATH
or various other settings (including your JAVA_HOME
example).
Most desktop environments launched from display managers (which is to say, the vast majority of graphical logins) do not set up a login environment for the entire desktop, so you are forced to run the initial shell in terminals as a login shell. This causes a number of problems (notably that the PATH
and such available to programs run from e.g. panels is not set up properly, because the panel is not a terminal and has not run ~/.bash_profile
), but is a reasonable compromise given that it is not always possible to sanely run ~/.bash_profile
in the non-interactive environment at the beginning of a session started by a display manager, depending on its contents. It is sometimes suggested to place environment settings in ~/.bashrc
instead of configuring a login shell instead; as discussed above, this works as long as you do not need to override that environment, and causes odd breakages once you do need to do so.
I recently helped diagnose an issue like this on OS X where a user who had placed settings in ~/.bashrc
then later started using rvm
and perlbrew saw odd behavior, because the environments set up by the two were "undone" by ~/.bashrc
inside editors and sudo
(which on OS X, unlike Linux, propagates the user's $HOME
so that their ~/.bashrc
was run by the root shell). Before trying to use those environments, there was no problem; on starting to use them, they were bewildered by the unexpected loss of their settings.
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:
When bash is started non-interactively, to run a shell script,
for example, it looks for the variable BASH_ENV in the environment, expands its value if it appears there, and uses the expanded value as the name of a file to read and execute. Bash behaves as if the following command were executed:
if [ -n "$BASH_ENV" ]; then . "$BASH_ENV"; fi
interactive, login shell:
When bash is invoked as an interactive login shell, or as a
non-interactive shell with the --login option, it first reads
and executes commands from the file /etc/profile, if that file
exists. After reading that file, it looks for ~/.bash_profile, ~/.bash_login, and ~/.profile, in that order, and reads and executes commands from the first one that exists and is readable.
interactive, non-login shell
When an interactive shell that is not a login shell is
started, bash reads and executes commands from
/etc/bash.bashrc and ~/.bashrc, if these files exist. This
may be inhibited by using the --norc option. The --rcfile
file option will force bash to read and execute commands from
file instead of /etc/bash.bashrc and ~/.bashrc.
So, if you want your non-interactive, non-login shell to source ~/.bahsrc
, you will need to set the value of BASH_ENV
to ~/.bashrc
. Add this line to your ~/.bashrc
or ~/.profile
files:
export BASH_ENV=~/.bashrc
Best Answer
People source bash_profile from bashrc instead of the other way around due to local convention.
All the opinion that I've read about how one configures their startup files in
bash
is primarily based on local convention. The local convention usually doesn't mention the big picture in that it doesn't talk much about the non-login, non-interactive case. The funny thing is, and I've looked, but I rarely see anyone mentioncron
in all their talk about why to put variables in one startup file versus the other. In fact, I've not heard one comment say: "/bin/sh is there for a reason. Bash emulates the original Bourne shell, /bin/sh, when invoked as such." For one thing, and I digress slightly, this case is important to people who work with the shell not only interactively, but who provide non-interactive, non-login (unattended or background)cron
scripts that need minimal shell processing i.e. background processing doesn't require the niceties of colored prompts, command history and substitution, a properly defined $TERM variable, etc.Further and with respect to
cron
, what I usually see is people creating minimal search paths or calling programs fully qualified, and not knowing how to deal with output not connected to a terminal (i.e. the non-interactive, non-loginbash
orsh
case) when working with theircron
scripts. This is usually because a good understanding of the shell startup sequence isn't fully understood, which leads to a user implementing their own startup files in a manner that is inconsistent or incoherent with the conventions already established in the local/etc
startup files.Elaborating, the setup done by local convention is laid out in that particular installation and shell's
/etc
files. If one examines any UNIX installation's/etc
files, which are invoked as part of a typicalbash
startup sequence, then one should create their own start-up in a manner that is complimentary to the convention established in those/etc
startup files.The Linux Documentation Project states:
Though the
bash
manual doesn't mention these files that are commonly found in the/etc/skel
directory explicitly, from what I recall, SunOS, Solaris, RedHat, Ubuntu, HP-UX, umips, & Ultrix have/etc/skel
files to pattern a user's shell startup files after. OSX clearly does not - I'm using OSX 10.9.1 right now. Unfortunately, OSX doesn't give you much to go on in terms of how things should be setup in terms of convention, but since OSX is a BSD derivative, I simply used another BSD derivative, and patterned my ownbash
startup sequence after that, adjusting it to fit into the local conventions used in the OSX 10.9.1/etc
startup files.An important point that was mentioned in a parallel comment is that for OSX, the convention is to start every new Terminal as an interactive login shell. This is indeed the default in OSX. There is no problem with this convention as long as the users of an installation are consistent. The default behavior for the Terminal on OSX may be changed to conform with other UNIX distribution's shell startup conventions by making the following change to the Terminal's preferences, in particular, change the setting,
Shells open with:
to issue the/usr/bin/login -f -l whmcclos bash -i
command:With all that as a background or introduction, I will segue into my best advice, for what it's worth.
My best advice:
Examine the files the admins of your UNIX distribution have put in place. Start with the following locations, if they exist. Don't forget to use the
ls -a
command, because some of the files begin with a dot. See how these files are used during startup, and see how your own startup files interact with them:Look in the
bash
manual for the invocation and startup sequence. It is all laid out very well.With all that as a caveat - here is how I did things on my OSX 10.9.1 installation - Other UNIX distributions WILL be different, but what is presented below should work on most if not all UNIX distributions, but use those other UNIX distributions' convention as a guide to tailor the below for your own purposes:
.profile
.bashrc
.bash_profile
So that's my two cents. Keep in mind that my examples have tried to show the control path through the startup files and avoid what any particular site's conventions may impose.