Why are interactive shells on OSX login shells by default?

The way it's supposed work is that, at the point when you get a shell prompt, both .profile and .bashrc have been run. The specific details of how you get to that point are of secondary relevance, but if either of the files didn't get run at all, you'd have a shell with incomplete settings.

The reason terminal emulators on Linux (and other X-based systems) don't need to run .profile themselves is that it will normally have been run already when you logged in to X. The settings in .profile are supposed to be of the kind that can be inherited by subprocesses, so as long as it's executed once when you log in (e.g. via .Xsession), any further subshells don't need to re-run it.

As the Debian wiki page linked by Alan Shutko explains:

"Why is .bashrc a separate file from .bash_profile, then? This is done for mostly historical reasons, when machines were extremely slow compared to today's workstations. Processing the commands in .profile or .bash_profile could take quite a long time, especially on a machine where a lot of the work had to be done by external commands (pre-bash). So the difficult initial set-up commands, which create environment variables that can be passed down to child processes, are put in .bash_profile. The transient settings and aliases which are not inherited are put in .bashrc so that they can be re-read by every subshell."

All the same rules hold on OSX, too, except for one thing — the OSX GUI doesn't run .profile when you log in, apparently because it has its own method of loading global settings. But that means that a terminal emulator on OSX does need to run .profile (by telling the shell it launches that it's a login shell), otherwise you'd end up with a potentially crippled shell.


Now, a kind of a silly peculiarity of bash, not shared by most other shells, is that it will not automatically run .bashrc if it's started as a login shell. The standard work-around for that is to include something like the following commands in .bash_profile:

[[ -e ~/.profile ]] && source ~/.profile    # load generic profile settings
[[ -e ~/.bashrc  ]] && source ~/.bashrc     # load aliases etc.

Alternatively, it's possible to have no .bash_profile at all, and just include some bash-specific code in the generic .profile file to run .bashrc if needed.

If the OSX default .bash_profile or .profile doesn't do this, then that's arguably a bug. In any case, the proper work-around is to simply add those lines to .bash_profile.


Edit: As strugee notes, the default shell on OSX used to be tcsh, whose behavior is much saner in this respect: when run as an interactive login shell, tcsh automatically reads both .profile and .tcshrc / .cshrc, and thus does not need any workarounds like the .bash_profile trick shown above.

Based on this, I'm 99% sure that the failure of OSX to supply an appropriate default .bash_profile is because, when they switched from tcsh to bash, the folks at Apple simply didn't notice this little wart in bash's startup behavior. With tcsh, no such tricks were needed — starting tcsh as a login shell from an OSX terminal emulator Just Plain Works and does the right thing without such kluges.


The main reason that X terminal applications run non-login shells by default is that in the beginning of time, your .Xsession would have run the .profile to set up your initial login items. Then, since that was all set up already, terminal apps didn't need to run it, they could run the .bashrc. Discussion of why this would matter is at https://wiki.debian.org/DotFiles:

Let's take xdm as an example. pierre comes back from vacation one day and discovers that his system administrator has installed xdm on the Debian system. He logs in just fine, and xdm reads his .xsession file and runs fluxbox. Everything seems to be OK until he gets an error message in the wrong locale! Since he overrides the LANG variable in his .bash_profile, and since xdm never reads .bash_profile, his LANG variable is now set to en_US instead of fr_CA.

Now, the naive solution to this problem is that instead of launching "xterm", he could configure his window manager to launch "xterm -ls". This flag tells xterm that instead of launching a normal shell, it should launch a login shell. Under this setup, xterm spawns /bin/bash but it puts "-/bin/bash" (or maybe "-bash") in the argument vector, so bash acts like a login shell. This means that every time he opens up a new xterm, it will read /etc/profile and .bash_profile (built-in bash behavior), and then .bashrc (because .bash_profile says to do that). This may seem to work fine at first -- his dot files aren't heavy, so he doesn't even notice the delay -- but there's a more subtle problem. He also launches a web browser directly from his fluxbox menu, and the web browser inherits the LANG variable from fluxbox, which is now set to the wrong locale. So while his xterms may be fine, and anything launched from his xterms may be fine, his web browser is still giving him pages in the wrong locale.

On OS X, the user environments aren't started by a pile of shell scripts, and launchd doesn't source .profile at any time. (That's sort of a shame, since it means it's a lot more annoying to set environment variables, but such is life.) Since it doesn't, when would it run .profile? Only if you ssh'd in? That seems kind of pointless, since many boxes will never be targets of ssh. Might as well make the terminals run login shells by default, so that .profile will be run sometime.

What about .bashrc, then? Is it useless? No. It still has the purpose that it had in the days of the VT100. It is used for any time you open a shell other than opening a Terminal window. So if you shell out of Emacs or vi, or if you do a su user.


I don't know why they would have done that. However, here's my guess.

To start with, it's worth noting that on a GNU/Linux system, you can of course switch to vt1, vt2, etc. You get a login shell there. On an OS X system, there's no equivalent. The only way to access the UNIX underpinnings is through a terminal emulator or through single user mode (disclaimer: I've never actually used single user mode; it's commandline-driven IIRC but I may be wrong). Therefore, in OS X whatever the default is in the emulator is the default for the entire system.

Now, why would you make the default a login shell? There are a couple (read: not many) reasons I can think of to do this.

  • It provides a consistent user experience if you SSH into the box. (Especially important for the server edition of OS X - presumably if you're running an OS X server, you're a newbie.)
  • The default shell of OS X used to be tcsh. This is about as wild a guess as you can get, but it may be that tcsh normally did something when run as a login shell, and the historical pattern stuck. (I doubt it, though - maybe one of the older regulars could tell us.)
  • "We are Apple. We are the vendors of the largest UNIX distribution on the planet. It doesn't matter how trivial our reasons are; if we make a decision, your tool must deal with it."

Honestly, I've been using Darwin for ~6 years and I can't answer this question properly. It doesn't really make sense to me, either.

To answer your subquestion, bash is not patched or anything (at least for this). The default terminal emulator runs login shells by default, and presumably iTerm copies that.

Tags:

Bash

Osx