This article is an attempt to answer the following questions1:
- What is the difference between
- Why doesn’t Terminal.app read my
~/.bashrcon Mac OS X?
When Bash is invoked, it reads and executes commands from its startup files to set up the shell environment.
There are a couple conditions Bash checks to determine which startup files are read (and which ones are not) when the shell is invoked:
Am I a login shell?
- the first character of argument zero is a
argv == '-'when the shell is invoked as
- started with the
Am I an interactive shell?
- started without non-option arguments and without the
-c option, whose standard input and error are both connected to terminals
- started with the -i option
This allows for the following four combinations:
|login shell||non-login shell|
|interactive shell||interactive login shell||interactive non-login shell|
|non-interactive shell||non-interactive login shell||non-interactive non-login shell|
When you login to a system, the first process spawned under your user ID is usually an interactive login shell. Normally there is some configuration that should only happen once when the user logs in, and Bash provides this capability by sourcing login specific startup files.
First, the login shell sources
/etc/profile, if that file exists. Next, it looks for any of the following files in this order:
~/.profile. If it finds one that exists and is readable, Bash sources the file. Bash will also source these same files if the shell is started as a non-interactive login shell when started with the
Additionally, before a login shell exits, Bash reads and executes commands from the file
~/.bash_logout, if it exists.
Once the user is logged into the system, additional shells can be started within the existing session (for example, from the command line or started with a terminal program like
xterm). These are usually invoked as an interactive non-login shell which normally inherits the environment from the parent login shell. However, since this is not a login shell
~/.bash_profile is NOT read when Bash is invoked. Instead, Bash expects settings for interactive non-login shells to be put in
~/.bashrc, so it reads and executes this file (if the file exists).
If Bash is invoked as a non-interactive non-login shell (for example, to run a shell script), only the environment inherited from the parent shell is used (none of the startup files above will be read). In addition, 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.
An exception to the behavior above is when Bash is being executed by the remote shell daemon (rshd or sshd). When Bash is being run with its standard input connected to a network connection, it reads and executes commands from
~/.bashrc, if that file exists and is readable.
It’s important to note that there are other conditions Bash checks which influence the startup behavior. For example, Bash can be invoked in a compatibility mode with the name
sh to emulate the behavior of the
sh shell. It can also be started in POSIX mode by specifying the
--posix option. These and other startup modes are described in detail at Bash Startup Files.
Of course, Terminal.app on Mac thinks different…
When you launch Terminal, a new window is opened and the following command is invoked2:
login -pfl $USER /bin/bash -c exec -la bash /bin/bash
The default shell is
/bin/bash, but can be configured with a custom shell in the Terminal preferences.3
Since Terminal starts each new window as an interactive login shell,
~/.bash_profile is sourced while
~/.bashrc is not.
To ensure that
~/.bashrc is sourced when Bash is invoked as a login shell in Terminal, you need to add the following to
# if this is an interactive shell include ~/.bashrc [[ $- == *i* ]] && . $HOME/.bashrc
Bash completion from MacPorts requires Bash version 4.1 or later, and at the time of this writing, the version of Bash that ships with OS X is too old (3.2.51(1)-release on Mavericks). Make sure to toggle Terminal -> Preferences -> Startup -> Shells open with to Command (complete path):
/opt/local/bin/bash. For more details, see the Bash Completion How To. ↩︎