I am using prompt pure as my prompt in zsh. Internally it uses print -Pn ... to print out the current directory. For some reason, if I have an environment variable set that matches the beginning of the current directory, that environment variable name will be substituted into the output.

For example,

> export SOME_DIR=/home/bschlenk/some/path
> cd ~/some/path/deeper/nested/path
> print -Pn %~

How do I prevent it from substituting random environment variables into the path that happen to match? I want it to print out the current path, with /home/bschlenk substituted with ~, but no other substitutions.

  • I can't reproduce the behavior with a fairly stock zsh. Perhaps there's additional processing brought in somewhere?
    – Jeff Schaller
    Dec 13, 2018 at 19:01
  • do you have $functions[zsh_directory_name] or $zsh_directory_name_functions set by something?
    – thrig
    Dec 13, 2018 at 19:21
  • echo $functions[zsh_directory_name] prints nothing Dec 13, 2018 at 20:04

1 Answer 1


From the documentation of %~:

if it has a named directory as its prefix, that part is replaced by a ~ followed by the name of the directory, but only if the result is shorter than the full path

A reference follows to dynamic and static named directories. What you're seeing is a static named directory

They may also be defined if the text after the ~ is the name of a string shell parameter whose value begins with a /.

So if the value of the variable SOME_DIR is /home/bschlenk/some/path then ~SOME_DIR is a static named directory whose value is /home/bschlenk/some/path. The prompt expansion %~ sees /home/bschlenk/some/path and abbreviates it to ~SOME_DIR.

But that's not the whole story. In fact, the abbreviation only happens if SOME_DIR has been “activated” by the use of ~SOME_DIR. This is documented under the option auto_name_dirs, which removes the need for prior activation, but defaults off.

Any parameter that is set to the absolute name of a directory immediately becomes a name for that directory, that will be used by the %~ and related prompt sequences, and will be available when completion is performed on a word starting with ~. (Otherwise, the parameter must be used in the form ~param first.)

A parameter that is activated for %~ substitution (and completion after ~) shows up as an entry in the named directory hash table which you can list with hash -d.

We've put the pieces together to understand what's going on. How can you solve your problem? It depends what caused SOME_DIR to be activated.

If you have the option auto_name_dirs turned on, then obviously you should turn it off.

If you've used ~SOME_DIR previously, you can deactivate it with

unhash -d SOME_DIR

This is not permanent: it'll pop up again if you use ~SOME_DIR again. But given that you can use $SOME_DIR wherever you can use ~SOME_DIR, ~SOME_DIR is not a very useful feature.

If you can't get rid of what makes SOME_DIR a named directory and you want to abbreviate the current directory with nothing but $HOME~, you can implement this transformation manually.

if [[ $PWD = $HOME ]]; then
elif [[ $PWD = $HOME/* ]]; then

and then use print -rn $HPWD instead of print -Pn %~.

If you can't prevent SOME_DIR from becoming a named directory and you can't change the code that uses %~, it gets trickier. You can empty the directory hash table with hash -r, but there's no way to make this local to a function (only to a subshell).

  • Thank you for the detailed answer! auto_name_dirs was set, probably by a script I'm sourcing in my .zshrc file. I added an unsetopt AUTO_NAME_DIRS right afterwards, and now %~ is only replacing $HOME. Dec 13, 2018 at 21:58

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .