6. Directory Stacks

If you use csh, you may know about directory stacks. The pushd command puts the current directory on the stack, and changes to a new directory; the popd command pops a directory off the stack and changes to it.

Example 6.1: pushd and the directory stack
phoenix% cd
phoenix% PROMPT='Z %~> '
Z ~> pushd /tmp
/tmp ~
Z /tmp> pushd /usr/etc
/usr/etc /tmp ~
Z /usr/etc> pushd /usr/bin
/usr/bin /usr/etc /tmp ~
Z /usr/bin> popd
/usr/etc /tmp ~
Z /usr/etc> popd
/tmp ~
Z /tmp> pushd /etc
/etc /tmp ~
Z /etc> popd
/tmp ~

zsh’s directory stack commands work similarly. One difference is the way pushd is handled if no arguments are given. As in csh, this exchanges the top two elements of the directory stack:

Example 6.2: pushd swaps top two
Z /tmp> dirs
/tmp ~
Z /tmp> pushd
~ /tmp

unless the stack only has one entry:

Example 6.3: pushd with one entry
Z ~> popd
/tmp
Z /tmp> dirs
/tmp
Z /tmp> pushd
~ /tmp
Z ~>

or unless the PUSHD_TO_HOME option is set:

Example 6.4: PUSHD_TO_HOME option
Z ~> setopt pushdtohome
Z ~> pushd
~ ~ /tmp

As an alternative to using directory stacks in this manner, we can get something like a directory history by setting a few more options and parameters:

Example 6.5: Directory history with AUTOPUSHD
~> DIRSTACKSIZE=8
~> setopt autopushd pushdminus pushdsilent pushdtohome
~> alias dh='dirs -v'
~> cd /tmp
/tmp> cd /usr
/usr> cd bin
/usr/bin> cd ../pub
/usr/pub> dh
0       /usr/pub
1       /usr/bin
2       /usr
3       /tmp
4       ~
/usr/pub> cd -3
/tmp> dh
0       /tmp
1       /usr/pub
2       /usr/bin
3       /usr
4       ~
/tmp> ls ~2/df
/usr/bin/df
/tmp> cd -4
~>

Note that ~2 expanded to the second directory in the history list, and that cd -3 recalled the third directory in the list.

You may be wondering what all those options do. AUTO_PUSHD made cd act like pushd. (alias cd=pushd is not sufficient, for various reasons.) PUSHD_MINUS swapped the meaning of cd +1 and cd -1; we want them to mean the opposite of what they mean in csh, because it makes more sense in this scheme, and it’s easier to type:

Example 6.6: PUSHD_MINUS with cd +n
~> dh
0       ~
1       /tmp
2       /usr/pub
3       /usr/bin
4       /usr
~> unsetopt pushdminus
~> cd +1
/tmp> dh
0       /tmp
1       ~
2       /usr/pub
3       /usr/bin
4       /usr
/tmp> cd +2
/usr/pub>

PUSHD_SILENT keeps the shell from printing the directory stack each time we do a cd, and PUSHD_TO_HOME we mentioned earlier:

Example 6.7: PUSHD_SILENT hides stack
/usr/pub> unsetopt pushdsilent
/usr/pub> cd /etc
/etc /usr/pub /tmp ~ /usr/bin /usr
/etc> cd
~ /etc /usr/pub /tmp ~ /usr/bin /usr
~> unsetopt pushdtohome
~> cd
/etc ~ /usr/pub /tmp ~ /usr/bin /usr
/etc>

DIRSTACKSIZE keeps the directory stack from getting too large, much like HISTSIZE:

Example 6.8: DIRSTACKSIZE limits stack
/etc> setopt pushdsilent
/etc> cd /
/> cd /
/> cd /
/> cd /
/> cd /
/> cd /
/> cd /
/> cd /
/> dh
0       /
1       /
2       /
3       /
4       /
5       /
6       /
7       /