Use pushd and popd for faster CLI navigation

One of my favorite ways to save time on the command-line is to utilize the directory stack to jump between tasks. Today’s article will show you how to do this and provide some tips for effective use.

What is the directory stack?

Most Linux environments have a way for you to put paths on a stack (push) and then take them off in reverse order (pop). This is useful when you have more than one directory that you need to switch between frequently. Let’s take a look at how to do this.

The pushd command

Suppose you need to switch between your project: ~/src/myproject, your web-server: /opt/webserver7/logs and some code examples: ~/examples/othercode often.

You add things to the directory stack with pushd like so:

# switch from project to web server and put on the stack
pushd /opt/webserver7/logs
# Stack is now '/opt/webserver7/logs ~/src/myproject'

# show latest errors
tail -40 errors.log

Now your in your server logs and you want to go to the examples:

# switch from project to web server and put on the stack
pushd ~/examples/othercode
# Stack is now '~/examples/othercode /opt/webserver7/logs ~/src/myproject'

# bring the 3rd directory on the stack to the front (0-based) and rotating the stack
pushd +2
# Stack is now '~/src/myproject ~/examples/othercode /opt/webserver7/logs'

# copy Java example to myproject
cp MyExample.java `dirs | awk '{print $1}'`

The popd command

Now we want to go back to my project to deploy it to our web server. Since we have our directory stack working we can do this quickly:

# go back to myproject
popd
# Stack is now '~/examples/othercode /opt/webserver7/logs'

# deploy stuff
ant dist

For the purposes of this example, let’s pretend we don’t care to go back to the examples. Let’s remove it from the stack:

# remove examples from the directory stack
popd +0
# Stack is now '/opt/webserver7/logs'

One final pop will get me back to my server logs once I test it out in my browser. Of course, we can keep using the stack continuously.

Alternatives and nifty tips

You might not always want to use the directory stack. You can use these really fast shortcuts to navigate to home or back quickly:

# change to home directory quickly in bash
cd

# change to last directory in bash
cd -

Now for some final examples that may help out just a little more:

# print directories on the stack
dirs

# hey just type less
alias p='pushd'
alias o='popd'

Conclusion

Using pushd and popd effectively can help you get around your command-line environment quickly. See the MAN pages for more information.

Take a bit of time to get the hang of it now and it’ll pay off later. Share your other examples or questions!

If you liked this post, please help me share it

Responses (17)

  1. johnvh says:

    Another ‘bookmarking’ alternative that was suggested to me, and I now use fairly often – a new shell from shell. I find that, along with ‘cd -’ is very handy, although not as flexible as pushd/popd.


    $ cd some/real/long/dir/path/
    #do stuff there...

    $ bash
    #new shell within shell

    $ cd another/real/long/dir/path
    #do stuff here...

    $ ^d
    #exit shell, now youre back in original shell where you left off

  2. Joseph Garvin says:

    Is there a way to have it automatically maintain a history, and have a one character alias for going back a directory and a one character alias for going forward (like a web browser’s history)? AFAIK “cd -” is like the flashback button on a TV remote: it’ll flip back and forth between the same two folders over and over.

  3. @Joseph:
    You might be able to use bash ‘history’ to do some of what you ask. You could also do: alias z=’pushd . && popd’ to try keeping your dir stack nicely populated.

    You’re exactly right about ‘cd -’, it’s just like the Recall button.

    If anyone else has other solutions, I’d love to hear them.

  4. From Reddit:

    If you’re using ZSH, you can add “setopt autopushd” to your .zshrc and switching directories will use pushd automatically. It supports many other pushd-related options too (pushdignoredups, pushdminus, pushdsilent, pushdtohome, etc.)

  5. Daniel Engel says:

    Add to your .bashrc:

    # Fan of directory stacks.
    alias d=”dirs”
    alias pu=”pushd”
    alias po=”popd”
    alias 1=”pushd”
    alias 2=”pushd +2″
    alias 3=”pushd +3″
    alias 4=”pushd +4″
    alias 5=”pushd +5″
    alias 6=”pushd +6″

  6. jhz says:

    I’ve always prefered aliasing ‘+’ for pushd, and ‘-’ for popd
    No faster way to navigate your directories.

  7. Nico says:

    I use a much better abstraction that I co-authored with Will Fiveash:

    http://blogs.sun.com/nico/entry/ksh_functions_galore

    This way I can “save” directories and recall them using sub-string (actually, glob) matching, and I can list them, remove them, …

    % pwd
    /
    % cd /tmp
    /tmp
    % cdinit
    % cdsv
    % cdto foo
    % cdto ../bar
    % cdto foobar/baz
    % cdls
    0 /tmp
    1 /tmp/foo
    2 /tmp/bar
    3 /tmp/foobar/baz
    % cdto 0
    /tmp
    % cd /
    % cdto foo
    /tmp/foo
    % cdto baz
    /tmp/foobar/baz
    % cdto bar
    /tmp/bar
    %

    And you can save listings to files and source them back. Very handy for working in large source projects. E.g., I can say “cdto ssh” and instantly I’m in $SRC/cmd/ssh” in a shell where I’m working on OS/Net Nevada.

  8. @Nico:
    Most interesting. It’s almost like aliasing on the fly as well.

  9. Michael says:

    you could also ^R then type any piece of the path, ^R to cycle through the others in your history.

  10. simonmar says:

    I’ve been using this scheme for years now. cd = pushd, b = go backwards (popd), f = go forwards (kind of like “unpopd”).


    alias b='pushd +1'
    alias f='pushd -0'

    cd () {
    if [ "$*" = "" ]; then
    pushd $HOME >/dev/null
    else
    pushd "$*" >/dev/null
    fi
    }

  11. This article and its responses, particularly Nico’s, has inspired me to experiment with modifying the CDPATH, which both cd and pushd use.

    Here’s an example of what I’ve come up with. I show the CDPATH, try to pushd to FileMaker, which fails. Then I add the path to FileMaker to the CDPATH, after which, pushd now works.

    $ printenv CDPATH
    .:/Users/ge:/Users/ge/Desktop:/Users/ge/Documents:/Users/ge/Documents/Politics:/Library/WebServer/Documents:/Users/ge/Documents/ruby_and_rails/rails/projects
    $ pushd FileMaker
    -bash: pushd: FileMaker: No such file or directory
    $ cdppush ~/Documents/tech/
    $ pushd FileMaker
    /Users/ge/Documents/tech/FileMaker
    ~/Documents/tech/FileMaker ~/Documents/tech/FileMaker ~/.profile.d

    I created two functions in a file that I source from bash to implement these functions: The names could be better.

    function cdppush()
    {
    set +o nounset
    #echo “$# args”;
    if [ "X${1}" = "X" ]; then
    #echo “cding to home”;
    builtin cd;
    else
    #echo “adding ${1} to CDPATH”;
    CDPATH=”${*}”
    CDPATH=$CDPATH:.
    CDPATH=$CDPATH:$HOME
    CDPATH=$CDPATH:$HOME/Desktop
    CDPATH=$CDPATH:$HOME/Documents
    CDPATH=$CDPATH:$HOME/Documents/Politics
    CDPATH=$CDPATH:/Library/WebServer/Documents
    CDPATH=$CDPATH:$HOME/Documents/ruby_and_rails/rails/projects
    export CDPATH
    echo “added ${1} to CDPATH [$CDPATH]“;
    fi
    }

    function cdpreset()
    {
    CDPATH=.
    CDPATH=$CDPATH:$HOME
    CDPATH=$CDPATH:$HOME/Desktop
    CDPATH=$CDPATH:$HOME/Documents
    CDPATH=$CDPATH:$HOME/Documents/Politics
    CDPATH=$CDPATH:/Library/WebServer/Documents
    CDPATH=$CDPATH:$HOME/Documents/ruby_and_rails/rails/projects
    export CDPATH
    }

    It can’t do pattern searches but it should be easy to remember to say ‘pushd Documents’ for example.

  12. I’m sorry about the formatting of the previous comment. It needs more width.

    And I left a couple of vestigial comments in the code, which was derived from another function. Ignore the comments.

    – ge

  13. Stu says:

    In tcc (4nt) I’ve set keyboard shortcut aliases for pushd / popd so

    alias @@alt-down=pushd
    alias @@alt-up=popd
    - the @@ means the alias is run immediately

    Keyboard shortcut aliases are one thing I really miss in unix terminals – is there any way of doing this ?

  14. @George:
    Nice, thanks!

    @Stu:
    Interesting. I didn’t realize that was possible. I wish I knew a way to do that.

  15. [...] Use pushd and popd for faster CLI navigation – Eric Wendelin’s Blog [...]

  16. art-shkola says:

    It`s so intersting!!! I’ll share it!

  17. Tuk says:

    A very userfriendly alternative to homegrown directory navigation utilities is cdargs: http://www.skamphausen.de/cgi-bin/ska/CDargs . It lets you easily add favorite folders and jump to them. And it even has tab-completion.

Leave a Reply