Since this is about the shell, I’m going to make a plug for my friend Dave Kerr’s amazing ebook: Effective Shell. If you’re going to muck about in terminals/shells, you really ought to go read it.
No. Really. I’ll wait. You’d be stupid not to. Go read it, or at least start reading it, then come back.
OK. Now that you’re a shell ninja, and know how some strong shell-fu can make an engineer more powerful… let’s talk variables and imports.
If you’ve ever so much as setup a dev environment and installed some non-trivial tools, you’ve likely encountered installation guidance like this (example from reactnative.dev, as of 08.22):
Note how they’re already qualifying the fact that you might have to put these exports in one file if you use bash, or in another file if you use Zsh. But they’re not done yet. They go on to clarify that if you’re ever using some shell other than the one you already configured, you’ll then still need to source those variables into your current shell:
So… sure… you could do all that. And, you could wrestle with the fact that other bits of your system (such as XCode) will periodically open up their own choice of shell (often bash), in a non-interactive way, where you can’t even exercise this option. And so everything will break. And you could accept that as inevitable. (Sucker.)
OR, you could take advantage of a simple and inexplicably overlooked option which makes this whole problem go away. In addition to the shell-specific files already mentioned above…
…there is by default another, more universal file on POSIX-compliant systems:
~/.profile. (That’s the user-specific version for your own account. In theory, you could also tinker with
etc/profile, but as a general rule I prefer to stick to messing about with my user files rather than system-level ones.)
Sure, you could run around manually source-ing some other profile into your current shell… but why would you? Why not go with the even easier and more sustainable option of ensuring that you always have all the same environment variables in all your shells?
First, instead of copying them hither and yon… simply place all needed variables/exports into one place:
~/.profile instead of repeating them across all the bash/zsh-specific versions.
Then, open up your user’s shell-specific configuration files (such as
~/zprofile… or those for rbash, dash, tmux, etc. ) and add to them all a single simple line:
[[ -s "$HOME/.profile" ]] && source "$HOME/.profile"
# SOURCE the master sh .profile, for concerns shared across all shells, login and non-login [[ -s "$HOME/.profile" ]] && source "$HOME/.profile" # Load the default .profile # Everything after this should be specific to your Zsh/bash login shells
That’ll do it. You should now have all the same variables in all your shells, because they’re all
source-ing from the same location.
And, if you’d maybe like to embellish that with some explanatory comments so you remember what’s happening here:
# SOURCE the master .profile, for concerns shared across all shells, login and non-login [[ -s "$HOME/.profile" ]] && source "$HOME/.profile" # Everything after this should then be specific to your interactive shells
I have also found it useful to provide an indicator so I can tell when these variables have been imported successfully into a given shell, so I include this at the end of
###### LAST echo ".profile is sourced"
Once that’s done, I find that my individual shell config files can be very lean and mean, with only shell-specific items. For instance, my
~/.zshrc can exclusively be about Zsh customizations like the amazing
oh-my-zsh, which won’t do me any good over in
~/.bashrc. Meanwhile, it’s only in
~/.profile that I need to write universal workflow utility scripts and project aliases such as:
alias rns="cd ~/PROJECTS/react-native-scaffold && nvm use --lts"
If you want to be more surgical, it may be useful to understand the difference between –
profile files and –
rc files, between interactive shells and non-interactive shells, and login vs. non-login shells. Maybe check out this article and/or this one, or go finish reading the related topics in Effective Shell. That said… it’s complicated, especially for Mac users, which is why I’ve been pretty general about which files you might need to import the
~/.profile into. YMMV.