Why do people source bash_profile from bashrc instead of the other way round?
Solution 1:
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 mention cron
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-login bash
or sh
case) when working with their cron
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 typical bash
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:
/etc/skel/ The default files for each new user are stored in this directory. Each time a new user is added, these skeleton files are copied into their home directory. An average system would have: .alias, .bash_profile, .bashrc and .cshrc files. Other files are left up to the system administrator.
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 own bash
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:
/etc/bashrc
/etc/profile
/etc/skel/.bash_logout
/etc/skel/.bashrc
/etc/bash.bashrc
/etc/bash_completion
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
# ~/.profile: executed by the command interpreter for login shells.
# This file is not read by bash(1), if ~/.bash_profile or ~/.bash_login
# exists. Note, however, that we will have a ~/.bash_profile and it
# will simply source this file as a matter of course.
# See /usr/share/doc/bash/examples/startup-files for examples.
# The files are located in the bash-doc package.
# From here on out, I basically set up my PATH, LD_LIBRARY_PATH, and anything else I'd like
# global to running programs and how those programs find their libraries. This is shared by
# `cron`, so we really don't want interactive stuff, here. Also, I setup my environments
# for brew, macports, and fink here, essentially with setting PATH, and invocation of those
# package initialization file as in:
# Brew and locally compiled stuff:
export PATH=/usr/local/bin:$PATH
export PATH=/usr/local/sbin:$PATH
# The following line puts gnu utilities without the prefix "g" in the path
# i.e. tar/gtar:
export PATH=$PATH:/usr/local/Cellar/coreutils/8.21/libexec/gnubin
# MacPorts shoves stuff in /opt, so to get at that stuff...
export PATH=/opt/local/bin:$PATH
export PATH=/opt/local/sbin:$PATH
# Set up for using Fink, which lives in /sw:
[ -e /sw/bin/init.sh ] && . /sw/bin/init.sh
# My stuff:
export PATH=~/perl:$PATH
export PATH=~/bin:$PATH
export PATH=.:$PATH
.bashrc
# ~/.bashrc: executed by bash(1) for non-login shells.
# see /usr/share/doc/bash/examples/startup-files (in the package bash-doc)
# for examples
# If not running interactively, don't do anything
[ -z "$PS1" ] && return
# From here on out, I put in things that are meaningful to interactive shells, like aliases,
# `shopt` invocations, HISTORY control, terminal characteristics, PROMPT, etc.
.bash_profile
# ~/.bash_profile: executed by the command interpreter for login shells.
# Because of this file's existence, neither ~/.bash_login nor ~/.profile
# will be sourced.
# See /usr/share/doc/bash/examples/startup-files for examples.
# The files are located in the bash-doc package.
# Because ~/.profile isn't invoked if this files exists,
# we must source ~/.profile to get its settings:
if [ -r ~/.profile ]; then . ~/.profile; fi
# The following sources ~/.bashrc in the interactive login case,
# because .bashrc isn't sourced for interactive login shells:
case "$-" in *i*) if [ -r ~/.bashrc ]; then . ~/.bashrc; fi;; esac
# I'm still trying to wrap my head about what to put here. A suggestion
# would be to put all the `bash` prompt coloring sequence functions as
# described on http://brettterpstra.com/2009/11/17/my-new-favorite-bash-prompt/
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.
Solution 2:
why do we put everything in bash_profile in the first place?
.profile was originally used by /bin/sh, using .profile allows backwards compatibility.
Unless you are using mac, everything isn't put in bash_profile. It is put in bashrc
wouldn't it make more sense and be more consistent with the linux community to put everything in bashrc and have bash_profile source that?
It is common to put system information into the shell that is loaded when you connect to the machine (uptime, packages needing updating, cpu temp ect...). If bashrc sourced bash_profile, you would see all that information every time you opened a new shell.
In Unix:
.bash_profile is loaded by login shells
.bashrc is loaded by interactive shells
Except for Mac, which loads the login shell for every new terminal (interactive or not)
Additional Resources
difference between bashrc and bash-profile
Where are environment variables specified