Navigating the Directory Stack in ‘bash’

Written by Aijaz Ansari. Filed under Computers. Tagged , , , , . Bookmark the Permalink. Post a Comment. Leave a Trackback URL.

Barracks by the Taj MahalIf you’re like me, you spend a lot of time jumping from project to project in a Linux shell.  I find that I have to switch back and forth between directories.  The bash shell has commands to maintain a stack of directories.  I’ve written some functions that use these utilities to make directory navigation easier. I’ve found these functions very useful, and perhaps you will too. Let’s see them in action first with some examples, and then look at the code:

In this first snippet, I start working in the Documents/Training/qt/ch1 directory:

$ pwd
/Users/aijaz
$ cd Documents/Training/qt/ch1/
$ ls
p1    t2
$

Now let’s say I have to work in the TaskForest lib directory for a while:

$ cd ~/Projects/projects/taskforest/lib/TaskForest/
$ ls -l
total 352
-rw-r--r--   1 aijaz  aijaz   8816 May 25  2009 Calendar.pm
...
-rw-r--r--   1 aijaz  aijaz   4558 May 25  2009 TimeDependency.pm
$

Now my work gets preempted because I have to work in the ‘rates’ directory:

$ cd ~/tc/config/rates/
$ ls -l
total 27544
drwxr-xr-x  21 aijaz  aijaz       714 Sep  3  2007 Text
...
-rwxr-xr-x   1 aijaz  aijaz       569 Sep  3  2007 findVoipAccess.pl
$

After finishing my work in the rates directory, I want to get back to what I was doing, but I can’t remember exactly what where I was before I got interrupted. So I enter the ‘d’ command which displays the stack of directories. Every time I used the ‘cd’ command, the system pushed the directory I was in onto a stack. The ‘d’ command displays the stack and prompts me for an entry. If I enter a number, it pushes the directory that’s at that position in the stack to the top, and enters that directory.

$ d
 0  ~/tc/config/rates
 1  ~/Projects/projects/taskforest/lib/TaskForest
 2  ~/Documents/Training/qt/ch1
 3  ~
#: 2
$ pwd
/Users/aijaz/Documents/Training/qt/ch1
$ d
 0  ~/Documents/Training/qt/ch1
 1  ~/tc/config/rates
 2  ~/Projects/projects/taskforest/lib/TaskForest
 3  ~
#: q
$

You can see that when I entered ’2′ above, the ‘d’ command pushed the ‘~/Documents/Training/qt/ch1′ directory to the top of the stack and entered that directory. You can see the modified directory stack above. I entered ‘d’ again to view the directory stack, but this time entered ‘q’ to do nothing.

I’ve also created the ‘p’ command, which pops the current directory off the top of the stack and enters the directory that was under it.

$ p
$ pwd
/Users/aijaz/tc/config/rates
$ d
 0  ~/tc/config/rates
 1  ~/Projects/projects/taskforest/lib/TaskForest
 2  ~
#: q
$

Now let’s have a look at the code that makes this work. You can copy and paste this code directly into your .bashrc file.

# An enhanced 'cd' - push directories
# onto a stack as you navigate to it.
#
# The current directory is at the top
# of the stack.
#
function stack_cd {
    if [ $1 ]; then
        # use the pushd bash command to push the directory
        # to the top of the stack, and enter that directory
        pushd "$1" > /dev/null
    else
        # the normal cd behavior is to enter $HOME if no
        # arguments are specified
        pushd $HOME > /dev/null
    fi
}
# the cd command is now an alias to the stack_cd function
#
alias cd=stack_cd

# Swap the top two directories on the stack
#
function swap {
    pushd > /dev/null
}
# s is an alias to the swap function
alias s=swap

# Pop the top (current) directory off the stack
# and move to the next directory
#
function pop_stack {
    popd > /dev/null
}
alias p=pop_stack

# Display the stack of directories and prompt
# the user for an entry.
#
# If the user enters 'p', pop the stack.
# If the user enters a number, move that
# directory to the top of the stack
# If the user enters 'q', don't do anything.
#
function display_stack
{
    dirs -v
    echo -n "#: "
    read dir
    if [[ $dir = 'p' ]]; then
        pushd > /dev/null
    elif [[ $dir != 'q' ]]; then
        d=$(dirs -l +$dir);
        popd +$dir > /dev/null
        pushd "$d" > /dev/null
    fi
}
alias d=display_stack

3 Comments

  1. Mehul
    Posted March 10, 2010 at 8:54 pm | Permalink

    So here’s what I’ve been using since the early 90′s:

    # set the title of an xterm to $PWD
    function xtitle()
      {
        if test "$TERM" = "xterm" -o "$DISPLAY" != ""; then
            ROOT=''
            if test "$UID" = "0"; then ROOT='# '; fi
            HOSTNAME=`hostname | tr [a-z] [A-Z]`
            echo -e "\33]2;$HOSTNAME $ROOT  $PWD\07"
            echo -e "\33]1;$HOSTNAME $ROOT  $PWD\07"
       fi
      }
    
    function cd()
      {
        if [ x"${1}" = x ]
        then
          builtin cd "${HOME}"
        else
          builtin cd "${1}"
        fi
        xtitle
      }
    
    function pd()
      {
          if [ x"${1}" = x ]
          then
              builtin pushd +1
          else
              builtin pushd "$1"
          fi
          xtitle
      }
    
    function po()
      {
          if [ x"${1}" = x ]
          then
              builtin popd +0
          else
              builtin popd "$1"
          fi
          xtitle
      }
    
    function sd()
    {
       builtin dirs -v
    }
    

    I put them in my ~/Env/bash/funcs file which gets sourced by ~/.bashrc

    Comment updated by Aijaz – Tried to format code with syntax highlighter. No other changes.

  2. Posted April 8, 2010 at 9:44 pm | Permalink

    How you find ideas for articles, I am always lack of new ideas for articles. Some tips would be great

    • Aijaz Ansari
      Posted April 10, 2010 at 3:38 pm | Permalink

      holgie:

      I keep a list of topics in a Google Docs document. Whenever I come across something I thing would be interesting to write about, I add it to that list. If it’s a web page I sometimes tag it on delicious.com. That way I can come back and write about any of the topics when I have the time.

      Hope that helps,

      Aijaz

Post a Comment

Your email is never published nor shared. Required fields are marked *

*
*

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>