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 '18 at 19:01
  • do you have $functions[zsh_directory_name] or $zsh_directory_name_functions set by something? – thrig Dec 13 '18 at 19:21
  • echo $functions[zsh_directory_name] prints nothing – Brian Schlenker Dec 13 '18 at 20:04

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. – Brian Schlenker Dec 13 '18 at 21:58

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.