One piece of advice that I’ve seen a lot in discussions on really tricking out one’s UNIX (&c.) shell is either setting an alias from
pushd or turning on a shell option that accomplishes this1. Sometimes the plan includes other aliases or functions to move around on the directory stack, and the general sell is that now you have something akin to back/forward buttons in a web browser. This all seems to be based on the false premise that
pushd is better than
cd, when the reality is that they simply serve different purposes. I think that taking
cd out of the picture and throwing everything onto the directory stack greatly reduces the stack’s usefulness. So this strategy simultaneously restricts the user to one paradigm and then makes that paradigm worse.
It’s worth starting from the beginning here.
cd changes directories and that’s about it. You start here, tell it to go there, now you’re there.
pushd does the same thing, but instead of just launching the previous directory into the ether, it pushes it onto a last in, first out directory stack.
pushd is helped by two other commands –
popd to pop a directory from the stack, and
dirs to view the stack.
% mkdir foo bar baz % for i in ./*; pushd $i && pushd % dirs -v 0 ~/test 1 ~/test/foo 2 ~/test/baz 3 ~/test/bar
dirs is a useful enough command, but its
-v option makes its output considerably better. The leading number is where a given entry is on the stack, this is globbed with a tilde.
~0 is always the present working directory (
$PWD). You’ll see in my little snippet above that in addition to
pushding my way into the three directories, I also call
pushd on its own, with no arguments. This basically just instructs
pushd to flip between
% pushd; dirs -v 0 ~/test/foo 1 ~/test 2 ~/test/baz 3 ~/test/bar
This is very handy when working between two directories, and one reason why I think having a deliberate and curated directory stack is far more useful than every directory you’ve ever
cded into. The other big reason is the tilde glob:
% touch ~3/xyzzy % find .. -name xyzzy ../bar/xyzzy
So the directory stack allows you to do two important things: easily jump between predetermined directories, and easily access predetermined directories. This feels much more like a bookmark situation than a history situation. And while
zsh (and presumably
bash) has other tricks up its sleeves that let users make easy use of predetermined directories, the directory stack does this very well in a temporary, ad hoc fashion.
cd actually gives us one level of history as well, via the variable
$OLDPWD, which is set whenever
$PWD changes. One can do
cd - to jump back to
zsh has one more trick up its sleeve when it comes to the directory stack. Using the tilde notation, we can easily change into directories from our stack. But since this is basically just a glob, the shell just evaluates it and says ‘okay, we’re going here now’:
% pushd ~1; dirs -v 0 ~/test 1 ~/test/foo 2 ~/test 3 ~/test/baz 4 ~/test/bar
Doing this can create a lot of redundant entries on the stack, and then we start to get back to the cluttered stack problem that started this whole thing. But the
pushd builtins in
zsh know another special sort of notation, plus and minus. Plus counts up from zero (and therefore lines up with the numbers used in tilde notation and displayed using
dirs -v), whereas minus counts backward from the bottom of the stack. Using this notation with either
pushd (it is a feature of these builtins and not a true glob) essentially pops the selected item off of the stack before evaluating it.
% cd +3; dirs -v 0 ~/test/baz 1 ~/test/foo 2 ~/test 3 ~/test/bar % pushd -0; dirs -v 0 ~/test/bar 1 ~/test/baz 2 ~/test/foo 3 ~/test
…and this pretty much brings the stack concept full circle, and hopefully hits home why it makes far more sense to curate this stack versus automatically populating it whenever you change directories.
zsh, the option is