I am using macOS and my shell is zsh. By default, my system's home directory is /Users/njohn. I created a symlink to this path, /usr/local/home. I put HOME="/usr/local/home" in my .zshrc. I did this so that first, I can quickly cd .. from my home directory, and I'll be in /usr/local where all my homebrew packages and config files live. Its a really simple shortcut. I also like being able to use cd and arrive at my symlinked path rather than the normal one, which is far away in the filesystem from things I'd like to feel closer to.

Could this possibly break anything? Is there a safer or better way I could accomplish the same thing?


Disclaimer: I do not, and have not used MacOS, so I'm not entirely sure what—if any—irregularities or subtle differences may exist between Mac and *nix.

To answer your question, the only scenario I could imagine "breakage" with this setup is when a given program attempts to do something with your home directory and it either doesn't follow symlinks by default (or not at all, for some reason). If whatever hypothetical program tries to read/write some file in your home directory, and it doesn't resolve your /usr/local/home symlink, things will likely break. Though the likelihood of such a scenario is beyond me.

That said, I think that you would be better off with an approach that doesn't modify your $HOME variable. Changing your $HOME variable to something other than what the system understands your home directory to be for the lifetime of every interactive shell you start is ugly, hackish, and bound to cause subtle problems. I'll provide you with three better alternatives.

Option 1: A more appropriately placed symlink

If you want to stick with a symlink, simply make a symlink to /usr/local from your home directory, get rid of the /usr/local/home link that you have now, and remove the line changing your $HOME variable from your .zshrc. For example:

% [~] ln -s /usr/local uloc
% [~] cd uloc
% [~/uloc] realpath .

Similar to what you have currently, you can quickly get to /usr/local from your home directory, except this way you don't need to change $HOME.

Option 2: Named Directories

Since you're using Zsh, I would recommend using a named directory. Instead of HOME=/usr/local/home, do something like the following, replacing uloc with a short name of your choice:


Then, you can quickly switch to this directory from anywhere in the following ways:

# With no special options set
% cd ~uloc

# Slightly shorter
% setopt cdable_vars
% cd uloc

# Even shorter
% setopt cdable_vars auto_cd
% uloc

As you can see, if you have a variable that expands to a path, you can cd to it in Zsh if you prefix it with a ~ character, similar to how you can use ~user as a shortcut for /home/user. You can have as many named directories as you want, so you can have quick access to any directory that you use frequently, not just /usr/local as in your case.

The cdable_vars option allows you to omit the ~ for named directories when using cd, and auto_cd means that if you enter a "command" that is actually a directory—named or literal—Zsh will automatically cd to that directory. Combining these two allows you rapid access to a desired directory no matter where you are. Contrary to option 1, since you're not relying on a symlink, cding to this named directory will actually put you in that directory, such that pwd would return /usr/local and not /Users/njohn/uloc.

Option 3: Using CDPATH

This approach can be used by itself, or in tandem with option 2.

You can also make use of $CDPATH, which is a special variable like $PATH that holds a list of directories. Unlike $PATH however, directories in $CDPATH will be used as the "root" for relative paths given to cd if the given path is not found under the current directory. To demonstrate, consider the following:

# Zsh ties lowercase variants of the *PATH variables together as arrays. See zshparam(1) for details
% [~/foo] cdpath=(/usr/local)
% [~/foo] ls
bar/ baz/
% [~/foo] cd share
% [/usr/local/share]

Since there was no directory named share in ~/foo, Zsh consulted $CDPATH for places where share might be a child directory. Since /usr/local was in $CDPATH, and share is a child directory of /usr/local, you are able to cd share from inside of ~/foo. You can go deeper as well; for example, if stuff was a subdirectory of /usr/local/share, you could get there by executing cd share/stuff.

Note: unlike in Bash, Zsh will always look in the current directory before trying directories in $CDPATH, unless a . is included in $CDPATH. In that case, Zsh strictly abides by the order of directories in $CDPATH.

This allows you even more convenience, since as you said, you often need access to your homebrew packages and configs, you can cd into one of those subdirectories from anywhere, without needing any sort of prefix!

As already mentioned, you can combine this with named directories. To pull an example from my own dotfiles:


# I split my configuration up into separate files that live in separate
# directories, which all live under a 'modules' directory inside ~/.zsh
% [~] cd modules/directory
% [~ZSH/modules/directory] cd modules/git
% [~ZSH/modules/git]

Further Reading

I recommend becoming more familiar with Zsh and its many features*. Here are some man pages and other topics you can look into:

  • symlink(7) — Describes symlinks in detail and how they're interacted with.
  • zshexpn(1), "Static named directories" — Explains named directories, and the rest of the man page describes all forms of expansion in Zsh.
  • zshparam(1), "PARAMETERS USED BY THE SHELL" — Includes descriptions for special variables like cdpath and the like
  • zshoptions(1) — Details all options that control Zsh behavior via the setopt builtin. Includes more in-depth explanations of cdable_vars and auto_cd than this answer provides.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.