173

Now that I've upgraded to Catalina and I am using the new ZSH shell, I've noticed that ~/.bash_profile has been replaced with ~/.zprofile and since installing iTerm2 shell integration, it added a ~/.zshrc file.

Looking at the ZSH documentation on Startup/Shutdown Files, there are a number of files (located in the home directory $HOME or ~/):

  • .zprofile (login shell)
  • .zshenv (environment variables)
  • .zshrc (interactive shell)
  • .zlogin (login shell)
  • .zlogout (when the shell exits)

What is also confusing is that ~/.zprofile and ~/.zlogin are both for login shells, so, things can get confusing as to what to put where.

What startup/shutdown files should be used when setting up the ZSH shell environment and how/what should they be configured?

Allan
  • 101,432
  • 3
    The ZSH documentation you mentioned in your question, explains in detail in which sequence zsh is looking for those files. All of them are optional, and you are the master of your account: There is no law telling you which command you have to put into which file. Just put them whereever they do what you want, given the type of shell you are using (login/non-login; interactive/non-interactive). Don't forget that environment variables are inherited by their child processes. – user1934428 Dec 30 '21 at 09:47

1 Answers1

223

This is an attempt to write a canonical QA for this issue, as per the Meta post: Where is the list of canonical questions stored for Ask Different? I expect it to be periodically edited with the goal of becoming a comprehensive information resource.

What should be used in ZSH on a Mac

I posted a more narrowly scoped question on Unix & Linux and got some clarification on how these files "work." Here's the summary of that answer and what I've learned in my research as to what, in my opinion should be used in a ZSH environment on a Mac.

  • .zprofile

    .zlogin and .zprofile are basically the same thing - they set the environment for login shells1; they just get loaded at different times (see below). .zprofile is based on the Bash's .bash_profile while .zlogin is a derivative of CSH's .login. Since Bash was the default shell for everything up to Mojave, stick with .zprofile.

  • .zshrc

    This sets the environment for interactive shells2. This gets loaded after .zprofile. It's typically a place where you "set it and forget it" type of parameters like $PATH, $PROMPT, aliases, and functions you would like to have in both login and interactive shells.

  • .zshenv (Optional)

    This is read first and read every time. This is where you set environment variables. I say this is optional because is geared more toward advanced users where having your $PATH, $PAGER, or $EDITOR variables may be important for things like scripts that get called by launchd. Those run under a non-interactive shell 3 so anything in .zprofile or .zshrc won't get loaded. Personally, I don't use this one because I set the PATH variable in my script itself to ensure portability.

  • .zlogout (Optional)

    But very useful! This is read when you log out of a session and is very good for cleaning things up when you leave (like resetting the Terminal Window Title)

For an excellent, in-depth explanation of what these files do, see What should/shouldn't go in .zshenv, .zshrc, .zlogin, .zprofile, on Unix/Linux.


Some Caveats

Apple does things a little differently so it's best to be aware of this. Specifically, Terminal initially opens both a login and interactive shell even though you don't authenticate (enter login credentials). However, any subsequent shells that are opened are only interactive.

You can test this out by putting an alias or setting a variable in .zprofile, then opening Terminal and seeing if that variable/alias exists. Then open another shell (type zsh); that variable won't be accessible anymore.

SSH sessions are login and interactive so they'll behave just like your initial Terminal session and read both .zprofile and .zshrc

Order of Operations

This is the order in which these files get read. Keep in mind that it reads first from the system-wide file (i.e. /etc/zshenv) then from the file in your home directory (~/.zshenv) as it goes through the following order.

.zshenv.zprofile.zshrc.zlogin.zlogout


1 A login shell is simply a shell, whether local or remote, that allows a user to authenticate to the system. These shells are typically interactive shells.

2 In interactive mode, they [the shell] accept input typed from the keyboard. (GNU Bash Reference Manual, 1.2 What is a Shell?)

3 When executing non-interactively, shells execute commands read from a file. (Ibid.)

Allan
  • 101,432
  • 4
    Zsh is a UNIX command interpreter (shell) usable as an interactive login shell and as a shell script command processor. Of the standard shells, zsh most closely resembles ksh but includes many enhancements. It does not provide compatibility with POSIX or other shells in its default operating mode. Zsh has command line editing, builtin spelling correction,programmable command completion, shell functions (with autoloading), a history mechanism, and a host of other features. – fd0 Apr 17 '20 at 17:49
  • What version of KSH uses a file named .login? ATT KSH cares about /etc/profile, ~/.profile, and whatever file is referenced by $ENV, or ~/.kshrc if $ENV is not set. MKSH cares about profile and substitutes mkshrc. Were I you, I'd lose the references to KSH and Bash, neither is relevant to the subject of your FAQ. – Marc Wilson Aug 12 '20 at 20:48
  • @Marc - it was supposed to be CSH...sorry for the typo and it was only mentioned just once – Allan Aug 12 '20 at 22:06
  • 1
    Not all versions of osx had bash as the default shell before 10.3 or4 had a csh based one – mmmmmm Nov 17 '20 at 13:01
  • If you are trying to make this canonical please keep options out of the answer vi have had t I support scripts across different unix systems. Executables are in different places so the way to deal is adjust the path outside the script in say places like.zshenv – mmmmmm Nov 17 '20 at 19:42
  • @mmmmmm I don't fully understand what you're trying to say, but assuming it's to do with it's canonical-ness, it's canonical to Ask Different, not canonical with respect to POSIX compliance. – Allan Nov 17 '20 at 19:47
  • The c I moment Personally, I don't use this one because I set the PATH variable in my script itself to ensure portability. Is opionated I see case s not to do this. For other see examples of how autoconf reads the environment to run executables eg where is python. You set the path outside the script to run on macports and brew and python.org or conda installations. Agreed he final run file is hard coded but you supply a script that does not hard code but reads the environment which is what.zshenv does – mmmmmm Nov 17 '20 at 20:01
  • Please...help me out here..."The c I moment Personally," - Due to the typos, I really can't understand what you're tying to convey. As for how you do things..this is not what this answer is about - it's the purpose for the different files and what should be placed in them. This is not about writing scripts for portability across platforms/computers or best practices for scripting or using Homebrew/MacPorts. – Allan Nov 17 '20 at 20:11
  • 6
    There is a big caveat to modifying PATH in .zshenv which I detail here: https://apple.stackexchange.com/q/432226/105377 – rgov Dec 09 '21 at 16:55
  • 3
    See also to understand the difference between a login shell and an interactive shell: https://stackoverflow.com/questions/18186929/what-are-the-differences-between-a-login-shell-and-interactive-shell – stwr667 Jun 27 '22 at 07:15
  • 1
    If this is to be canonical - then the /etc files need to be mentioned anmd also Apple's path_helper – mmmmmm Jan 31 '23 at 16:36
  • I'm not seeing how /etc files and Apple's path_helper applies to the original question, @mmmmmm Can you elaborate? – Allan Jan 31 '23 at 17:18
  • I was thinking of the whole zsh startup not just this question. The particular point is where you set $PATH as zsh manual (which the Linux and Uix answer agrees with) and makes your comments on what goes in .zshrc differ from those two. – mmmmmm Jan 31 '23 at 17:23
  • I note that PATH can potentially two different places - one is denoted "optional" and for "advanced users." To which one are you referring? – Allan Jan 31 '23 at 17:45
  • .zshrc - where you suggest env variables are set - but others say .zshenv - and Apple does /etc/zprofile – mmmmmm Jan 31 '23 at 18:37
  • 1
    If you put a PATH in .zprofile, it will not have effect on non-interactive shells. This will cause issues when running launchd or cron jobs. Apple puts the PATH there, but it isn’t the optimal location. – Allan Jan 31 '23 at 18:46
  • I have a question: I have installed python through pyenv, yet packages are wrongly installed to a homebrew folder and thus not working in the virtualenv. Might this be to zsh zprofile or bashrc setup? https://stackoverflow.com/questions/75394287/installed-python-packages-will-stay-in-site-packages-3-10?noredirect=1#comment133032563_75394287 – user236381 Feb 10 '23 at 04:47
  • @user236381 No not the shell profiles - it will be the way you are installing your python packages - that is a totally separate question. – mmmmmm Feb 21 '23 at 13:45
  • Excellent write-up. I feel like I was just getting good enough to be dangerous with Bash, and Apple had to go and do something like this!!! – aremmell Mar 24 '23 at 00:03
  • @aremmell, you can stick with Bash if you like. I still write my scrips in Bash - just use the shebang #! /usr/bin/env bash at the top of your scrips and it will execute in a bash environment. – Allan Mar 24 '23 at 00:33