Tag Archives: initialization

Bash / Zsh customization

AAPL changed the default shell from bash to zsh in either Mojave or Catalina. I ignored that, since nothing they’ve done lately betrays any understanding of Unix. But even after I moved back to bash using chsh, my Mac keeps reminding me that I’m doing it wrong. So I thought to myself: what if I did migrate to zsh? Or, rather, what’s keeping me from doing it? (Aside from AAPL being the ones to recommend it, I mean.)

Well, I know bash syntax pretty well, and I’ve got a bunch of shell scripts I wouldn’t want to find the bash-isms in. But OSX still includes bash, so running a shell script in bash is as simple as putting the right shebang up top. Assuming you have shell initialization working.

I do have it working. I think. I never know for sure. It’s a baling wire and chewing gum contraption, I admit.

The problem is that bash initialization is impossible to figure out. And even if you do figure it out, then you have to figure out what /etc/profile and /etc/bashrc and who-knows-what are invoking and in what order.

But if I don’t figure it out, I’ll always be to afraid to find out if zsh is worth using. Fortunately, I have a handy guide I can use to get a zsh initialization working.

Bash Initialization

Every time I monkey with my .profile or .bashrc file I regret it.(.profile is what graybeards like me use instead of using .bash_profile like all the young people who won’t stay off my lawn.)

If you’re like me, you get those confused all the time, so let’s go to the bash(1) man page. (Amazingly, it is a man page and not an info node. Ahem.) Here’s the salient bit of that 37,000 word tome:

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. The –noprofile option may be used when the shell is started to inhibit this behavior.

When a login shell exits, bash reads and executes commands from the files ~/.bash_logout and /etc/bash.bash_logout, if the files exists.

When an interactive shell that is not a login shell is started, bash reads and executes commands from ~/.bashrc, if that file exists. 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 ~/.bashrc.

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

but the value of the PATH variable is not used to search for the file name.

Got all that? The key is that your .profile is read first for login shells and .bashrc for non-login shells. There’s no reason why you should ever worry about what order they get invoked in, because there’s no reason to invoke them both at all. Except if you want to observe the DRY principle. In which case they should both invoke a separate startup file of your own design.