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!
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
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.
@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.
From Reddit:
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″
I’ve always prefered aliasing ‘+’ for pushd, and ‘-’ for popd
No faster way to navigate your directories.
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.
@Nico:
Most interesting. It’s almost like aliasing on the fly as well.
you could also ^R then type any piece of the path, ^R to cycle through the others in your history.
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
}
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.
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
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 ?
@George:
Nice, thanks!
@Stu:
Interesting. I didn’t realize that was possible. I wish I knew a way to do that.
[...] Use pushd and popd for faster CLI navigation – Eric Wendelin’s Blog [...]
It`s so intersting!!! I’ll share it!
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.
for command binding to keystrokes on linux
in $HOME/.inputrc (defines readline keybinds)
“\eOA”: “pushd\n”
For me, this binds Ctrl-Up to pushd followed by a newline.
To get the sequence to use for the keybind press Ctrl-V in your terminal followed by the keystroke you desire. Replace ^[ with \e and you should be good to go. To reload your .inputrc in an existing terminal window, press Ctrl-x Ctrl-r.
For more info on readline magic, see `man readline`
[...] The current directory stack (I use pushd and popd) [...]