Unix & Linux Stack Exchange is a question and answer site for users of Linux, FreeBSD and other Un*x-like operating systems. It's 100% free, no registration required.

Sign up
Here's how it works:
  1. Anybody can ask a question
  2. Anybody can answer
  3. The best answers are voted up and rise to the top

Is it a good idea to use the following alias:

cd() {
    pushd $1;

in bash?

I think this would be very useful, since I can then use a series of popds instead of just a cd - once.

Is there any case where this might be a problem?

share|improve this question
I know in zsh there's a setting to do just this. Not sure what it is though. Is it necessary to do a function instead of just alias cd=pushd? – Falmarri Nov 23 '10 at 18:15
I'd second the alias over the function. – alesplin Nov 23 '10 at 18:17
Why not alias a new name instead. How about pd? Are you the only user and administrator of your system? – Kevin Cantu Nov 23 '10 at 18:23
@Falmarri The zsh option is autopushd – Michael Mrozek Nov 23 '10 at 19:05
Strictly speaking, that's a function, not an alias (but all the better). – tripleee Jul 24 '13 at 17:49
up vote 25 down vote accepted

Personally, I have these in my bashrc and use them all the time:

  if [ $# -eq 0 ]; then

  builtin pushd "${DIR}" > /dev/null
  echo -n "DIRSTACK: "

  builtin pushd > /dev/null
  echo -n "DIRSTACK: "

  builtin popd > /dev/null
  echo -n "DIRSTACK: "

alias cd='pushd'
alias back='popd'
alias flip='pushd_builtin'

You can then navigate around on the command-line a bit like a browser. cd changes the directory. back goes to the previous directory that you cded from. And flip will move between the current and previous directories without popping them from the directory stack. Overall, it works great.

The only real problem that I'm aware of is the fact that it's then a set of commands that I'm completely used to but don't exist on anyone else's machine. So, if I have to use someone else's machine, it can be a bit frustrating. If you're used to just using pushd and popd directly, you don't have that problem. And while if you just alias cd put not popd, you won't have the issue of back not existing, you'll still have the problem that cd doesn't do quite what you expect on other machines.

I would note, however, that your particular implementation of cd doesn't quite work like cd in that the normal cd by itself will go to your home directory, but yours doesn't. The version that I have here doesn't have that problem. Mine also appends DIRSTACK onto the front of the dirs print out, but that's more a matter of personal taste more than anything.

So, as I said, I use these aliases all the time and have no problem with them. It's just that it can be a bit frustrating to have to use another machine and then find them not there (which shouldn't be surprising, but they're one of those things that you use so often that you don't think about them, so having them not work like you're used to can still be surprising).

share|improve this answer
Excellent advice! Vi/Vimperator users can configure the <C-o> to popd for authentic experience. – progo Mar 20 '11 at 17:38
@progo can you explain how flip will change directory with popping from the directory stack? – Jonathan. Sep 3 '13 at 11:42

This isn't a direct answer to the question, but I fell in love with the directory history window in 4DOS. So much so that I wrote my own version for Linux (and Cygwin). I've never gotten around to making it an easy-to-install utility, but if you know your way around a Bash prompt, it shouldn't be that hard to get running. Your question inspired me to put it into a Git repo and upload it to GitHub: dirhistory.

Basically, it's a daemon that collects directory changes from all your shells, and a Cdk program that displays the history and lets you pick any directory to switch to (so you're not limited to a stack). I find it really useful, and have it bound to Ctrl-PageUp, just like 4DOS did. (I even patched PuTTY so it would send Ctrl-PageUp to Bash.)

share|improve this answer

For me pushd/popd/dirs is close-to-helpful, but lacking. So I created a 'wrapper' around these called 'navd', implemented as essentially a set of 20 aliases. (One of them is a function, really.) The code is below, but here is a brief explanation first.

(One nice thing about "navd" and working on other people's machines: There is a "no-install" form of running it: As one option you can simply paste-in the commands that implement "navd" at the bash-prompt, and for the duration of that bash-session for that machine it will work. That gives a zero foot-print in the file-system. Put those commands in .bashrc for a "real" install, of course.)


navd <path>;   -- will make that path the current dir AND will add it to the stack
                         AS A BONUS: If a relative path is used, this command is added to history
                         with an absolute path instead. This improves navigation even if
                         a person only uses history ... because very often relative-path
                         change-dir type commands in history are useless -- because you would
                         have to have the directory they were originally issued from as
                         the current directory in order for such a command to work correctly.
navd           -- shows the stack, with index numbers for convenience
navd0          -- makes the first entry on the stack (read left-to-right) **the current dir**
navd1          -- makes the second entry on the stack (read left-to-right) **the current dir**
navd9          -- makes the tenth entry on the stack (read left-to-right) **the current dir**
navd-1         -- makes the first entry on the stack WHEN READ RIGHT-to-LEFT(!) **the current dir**
navd-9         -- makes the 9th entry on the stack WHEN READ RIGHT-to-LEFT(!) **the current dir**

Any of the nineteen navd<N> commands rotates the stack so that the directory that becomes current dir also now displays at the front of the stack. Positive <N> values find a dir counting from the left, with indexing starting at zero. Negative <N> values find a dir counting from the RIGHT, with indexing starting at -1. (This follows the convention of how array-indexes can be used in Java and other languages.)

Note: Any "navd" command displays the same stack that "pushd" and "dirs" uses -- but displays it WITHOUT the left-most entry that "dirs" would display (since that's not really on the stack -- it's the current directory and with "dirs" that left-most entry changes if a cd command is entered). (The "cd <path>" command does not affect any behavior of navd though it certainly does affect the behavior of pushd/dirs/popd. Also ... I love "cd -" to go "back" once, and "cd -" does not affect the behavior of navd either.)

Bonus: There can be 19 more aliases which do NOT rotate the stack, but merely change dir to the place indicated on the stack.

 nav0 ... nav9   and   nav-1  ... nav-9

2nd Bonus: "navh" shows navd <path> commands from history, for easily loading up the stack with cut-n-paste. (Each is listed only once even if it is in history multiple times, and the list is sorted.)


Three key behaviors:

  1. If you clear the stack and repeat a specific "navd <path>" command, that path will go on the stack. That's what I want and expect ... but pushd doesn't do that -- it puts the current dir you are navigating AWAY FROM on the stack -- so the effect on the stack is variable (feels unpredictable) when you repeat the command.

  2. "navd <path>" will not put the same path on the stack twice.

  3. "navd <path>" puts itself into command history with the absolute path even if the relative path was typed in for the command.

For me, the last three behaviors described make using a "navd <path>" command from history much more helpful than using a "pushd <path>" from history. I really can re-use history to go places. And when I do so I don't "spoil" my stack.

If you can and want to wrap your brain around it, you can switch between using navd and pushd/dirs/popd. Both use the same stack; just with a different style. For example, use "popd" to remove things from the "navd" stack, or use "dirs -c" to clear the navd stack.

Think of pushd/dirs/popd as "how do I retrace my steps?". Think of navd as "how do I hold on to a set of favorite directories, and easily switch between them?".

Paste the following into a terminal window, and you can immediately start using navd for the duration of that terminal-session. This is all the code there is to this feature.

# Add 1 function and many related aliases for something like "pushd", called "navd". http://unix.stackexchange.com/a/229161
# Think of pushd/dirs/popd as "how do I retrace my steps?".
# Think of navd as "how do I hold on to a set of favorite directories, and easily switch between them?"
# Pseudo-code to explain each part of the "navd" bash function just below:
#              If no arguments to the 'navd' command:
#                  If stack has entries, then print the stack one-line-per-dir with each line numbered.
#                  Else, if stack is empty, automatically run the equivalent of the navh command.
#              Else (there **are** arguments to the 'navd' command):
#                  If arg is '--help' or '/?' then show help.
#                  Else
#                      Change to dir given as argument (the "arg-dir"), and do a few chores:
#                      If arg-dir does not match the PWD we arrived at ... this means a relative path was used ...
#                          ... but (magically!) put the **absolute** path into history, instead of the relative path.
#                      Set a flag if the arg-dir is already in the stack.
#                      If the flag is set then just show the stack (on one line), else ADD to stack and show the stack.
navd () {
    if [[ $1 == '' ]]; then
        if dirs +1 >null 2>&1; then
            dirs -p | perl -ne 'print (-1+$cn++); print "$_"' | grep -v "^-1";
            echo "The navd stack is empty. Now running 'navh' in case that's helpful. navd --help works."
            history | perl -ne "if (m/^\s*\d+\s+navd [~.\/]/) {s/^\s*\d+\s+/  /;s/\/$//;print}" | sort -u
        if [[ $1 == '/?' || $1 == '--help' ]]; then
            echo "The 'navd' functionality is nothing but one bash function and a set of aliases."
            echo "It offers a different style of handy directory navigation than pushd/popd."
            echo "It uses the same 'stack' as pushd. Look in the .bashrc file for details."
            echo "    (Think of pushd/dirs/popd as 'how do I retrace my steps?'."
            echo "     Think of navd as 'how do I remember a set of favorite directories,"
            echo "     and easily switch between them?'.)"
            echo "As of 10/2015, this link has more info: http://unix.stackexchange.com/a/229161"
            echo "Here is the set of navd-related aliases. None need any parameter:"
            alias | grep 'alias nav' | cut -d= -f1 | grep -v '-' | grep -v 'navh'
            alias | grep 'alias nav' | cut -d= -f1 | grep '-'
            echo "alias navh  # The 'navh' alias is empty until a 'navd <path>' is run. Short for nav-history."
            echo "---- To get started, simpy type navd followed by your favorite path. ----"
            echo "---- navd with no param shows stack. nav0 navigates to first on stack. ----"
            cd $1 >/dev/null;
            if [[ `echo $1 | perl -pe 's/\/$//;s/^~/$ENV{'HOME'}/'` != $PWD ]]; then history -s `echo navd $PWD | perl -pe 's/$ENV{'HOME'}/~/'`; fi;
            myflag=`dirs | perl -ne '@a=split();$pwd=shift(@a);$flag=0;foreach (@a) {if ($_ eq $pwd) {$flag=1}};print $flag'`;
            if [[ $myflag == 1 ]]; then dirs | cut -s -d' ' -f2-20; else pushd .>/dev/null; dirs | cut -s -d' ' -f2-20; fi;
# Aliases for navigating and rotating the "pushd" stack in the style of "navd":
alias navd0='cd `dirs -l +1`;dirs | cut -s -d" " -f2-20' # "-l" is dash-L, and expands "~" to denote the home dir. Needed inside back-ticks.
alias navd1='cd `dirs -l +1`;pushd -n +1;cd `dirs -l +1`;dirs | cut -s -d" " -f2-20'
alias navd2='myd=$PWD;cd `dirs -l +1`;for i in {1..2};do pushd -n +1>/dev/null;cd `dirs -l +1`;done;cd $myd;cd `dirs -l +1`;dirs | cut -s -d" " -f2-20'
alias navd3='myd=$PWD;cd `dirs -l +1`;for i in {1..3};do pushd -n +1>/dev/null;cd `dirs -l +1`;done;cd $myd;cd `dirs -l +1`;dirs | cut -s -d" " -f2-20'
alias navd4='myd=$PWD;cd `dirs -l +1`;for i in {1..4};do pushd -n +1>/dev/null;cd `dirs -l +1`;done;cd $myd;cd `dirs -l +1`;dirs | cut -s -d" " -f2-20'
alias navd5='myd=$PWD;cd `dirs -l +1`;for i in {1..5};do pushd -n +1>/dev/null;cd `dirs -l +1`;done;cd $myd;cd `dirs -l +1`;dirs | cut -s -d" " -f2-20'
alias navd6='myd=$PWD;cd `dirs -l +1`;for i in {1..6};do pushd -n +1>/dev/null;cd `dirs -l +1`;done;cd $myd;cd `dirs -l +1`;dirs | cut -s -d" " -f2-20'
alias navd7='myd=$PWD;cd `dirs -l +1`;for i in {1..7};do pushd -n +1>/dev/null;cd `dirs -l +1`;done;cd $myd;cd `dirs -l +1`;dirs | cut -s -d" " -f2-20'
alias navd8='myd=$PWD;cd `dirs -l +1`;for i in {1..8};do pushd -n +1>/dev/null;cd `dirs -l +1`;done;cd $myd;cd `dirs -l +1`;dirs | cut -s -d" " -f2-20'
alias navd9='myd=$PWD;cd `dirs -l +1`;for i in {1..8};do pushd -n +1>/dev/null;cd `dirs -l +1`;done;cd $myd;cd `dirs -l +1`;dirs | cut -s -d" " -f2-20'
alias navd-1='cd `dirs -l -0`;pushd -n -0>/dev/null; dirs | cut -s -d" " -f2-20'
alias navd-2='myd=$PWD;cd `dirs -l -0`;pushd -n -0>/dev/null;cd `dirs -l -0`;pushd -n -0>/dev/null;cd $myd;cd `dirs -l +1`;dirs | cut -s -d" " -f2-20'
alias navd-3='myd=$PWD;cd `dirs -l -0`;for i in {1..2};do pushd -n -0>/dev/null;cd `dirs -l -0`;done;cd $myd;cd `dirs -l +1`;dirs | cut -s -d" " -f2-20'
alias navd-4='myd=$PWD;cd `dirs -l -0`;for i in {1..3};do pushd -n -0>/dev/null;cd `dirs -l -0`;done;cd $myd;cd `dirs -l +1`;dirs | cut -s -d" " -f2-20'
alias navd-5='myd=$PWD;cd `dirs -l -0`;for i in {1..4};do pushd -n -0>/dev/null;cd `dirs -l -0`;done;cd $myd;cd `dirs -l +1`;dirs | cut -s -d" " -f2-20'
alias navd-6='myd=$PWD;cd `dirs -l -0`;for i in {1..5};do pushd -n -0>/dev/null;cd `dirs -l -0`;done;cd $myd;cd `dirs -l +1`;dirs | cut -s -d" " -f2-20'
alias navd-7='myd=$PWD;cd `dirs -l -0`;for i in {1..6};do pushd -n -0>/dev/null;cd `dirs -l -0`;done;cd $myd;cd `dirs -l +1`;dirs | cut -s -d" " -f2-20'
alias navd-8='myd=$PWD;cd `dirs -l -0`;for i in {1..7};do pushd -n -0>/dev/null;cd `dirs -l -0`;done;cd $myd;cd `dirs -l +1`;dirs | cut -s -d" " -f2-20'
alias navd-9='myd=$PWD;cd `dirs -l -0`;for i in {1..8};do pushd -n -0>/dev/null;cd `dirs -l -0`;done;cd $myd;cd `dirs -l +1`;dirs | cut -s -d" " -f2-20'
# BONUS commands (beyond the 20). Aliases for navigating but NOT rotating the "navd" stack:
#      Help in remembering: "navd<#>" does more and both changes the PWD and rotates the stack, but "nav<#>" does less
#            (and has one letter less) since "nav<#>" only changes the PWD. Also "navd<#>" acts like the pushd-related command: dirs
#      There is no "nav" command (with no number) so that there will be no conflict if any program called "nav" is used.
alias nav0='cd `dirs -l +1`;dirs | cut -s -d" " -f2-20'
alias nav1='cd `dirs -l +2`;dirs | cut -s -d" " -f2-20'
alias nav2='cd `dirs -l +3`;dirs | cut -s -d" " -f2-20'
alias nav3='cd `dirs -l +4`;dirs | cut -s -d" " -f2-20'
alias nav4='cd `dirs -l +5`;dirs | cut -s -d" " -f2-20'
alias nav5='cd `dirs -l +6`;dirs | cut -s -d" " -f2-20'
alias nav6='cd `dirs -l +7`;dirs | cut -s -d" " -f2-20'
alias nav7='cd `dirs -l +8`;dirs | cut -s -d" " -f2-20'
alias nav8='cd `dirs -l +9`;dirs | cut -s -d" " -f2-20'
alias nav9='cd `dirs -l +10`;dirs | cut -s -d" " -f2-20'
alias nav-1='cd `dirs -l -0`;dirs | cut -s -d" " -f2-20'
alias nav-2='cd `dirs -l -1`;dirs | cut -s -d" " -f2-20'
alias nav-3='cd `dirs -l -2`;dirs | cut -s -d" " -f2-20'
alias nav-4='cd `dirs -l -3`;dirs | cut -s -d" " -f2-20'
alias nav-5='cd `dirs -l -4`;dirs | cut -s -d" " -f2-20'
alias nav-6='cd `dirs -l -5`;dirs | cut -s -d" " -f2-20'
alias nav-7='cd `dirs -l -6`;dirs | cut -s -d" " -f2-20'
alias nav-8='cd `dirs -l -7`;dirs | cut -s -d" " -f2-20'
alias nav-9='cd `dirs -l -8`;dirs | cut -s -d" " -f2-20'
# BONUS command (beyond the 20). Alias for showing 'history' of all navd commands that add to the stack.
#                Can be used in a new terminal session to quickly add recently used dirs to the navd stack.
alias navh='history | perl -ne "if (m/^\s*\d+\s+navd [~.\/]/) {s/^\s*\d+\s+/  /;s/\/$//;print}" | sort -u'
# Note: When 'navd <relative-path>' is used, then by bash-magic the navd command puts 'navd <absolute-path>' into history,
#       instead. This allows the output of "navh" to be useful regardless of the directory that is current when it is run.

These aliases are based on "bash" commands. Special care is taken to preserve the normal behavior of "cd -". (A lot of the time I use "cd -" instead of bothering with either pushd or navd -- because "cd -" is very handy for going back to the last "place" you were, or switching between only 2 places, and it works everywhere with no install.)

These commands can, of course, be put into the .bashrc file for a more permanent installation of them.

share|improve this answer
Dana, you appear to have two separate accounts with the same name. You can merge them fairly easily. – roaima Oct 28 '15 at 18:14

Your Answer


By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.