Softpanorama
May the source be with you, but remember the KISS principle ;-)

Contents Bulletin Scripting in shell and Perl Network troubleshooting History Humor

Pushd / popd / dirs troika

News Advanced Unix filesystem navigation Recommended Links Reference pushd popd dirs DIRSTACK
NCD clones Shell Dotfiles Shell Prompts Customarization Orthodox File Manager Paradigm. tac command tail
Subshells Brace Expansion Unix shells history bash Tips and Tricks Tips Sysadmin Horror Stories Humor Etc

Those commands, which create a stack for directories in shell, were initially introduced in C-shell. The semantec of each of the commands in pushd/popd/dirs troika generally correspond to their names:

dirs  - this command does not change state of the stack. If you need to go to, say, firth command from the top of the stack without changing stack you can use the command cd `dirs +5`
dirs [+N | -N] [-clvp]
Display the list of currently remembered directories. Directories are added to the list with the pushd command; the popd command removes directories from the list.
+N
Displays the Nth directory (counting from the left of the list printed by dirs when invoked without options), starting with zero.
-N
Displays the Nth directory (counting from the right of the list printed by dirs when invoked without options), starting with zero.
-c
Clears the directory stack by deleting all of the elements.
-l
Produces a longer listing; the default listing format uses a tilde to denote the home directory.
Causes dirs to print the directory stack with one entry per line.
-v
Causes dirs to print the directory stack with one entry per line, prefixing each entry with its index in the stack.
 
popd  -- this command changes the stack, typically removing the top item. When no arguments are given, popd removes the top directory from the stack and performs a cd to the new top directory.
The elements are numbered from 0 starting at the first directory listed with dirs i.e., popd is equivalent to popd +0.
popd [+N | -N] [-n]
+N
Removes the Nth directory (counting from the left to right in the list printed by dirs), starting with zero.
-N
Removes the Nth directory (counting from the right of the list printed by dirs), starting with zero.
-n
Suppresses the normal change of directory when removing directories from the stack, so that only the stack is manipulated.
pushd Saves the current directory on the top of the directory stack and then cd to dir. With no arguments, pushd  exchanges the top two directories.
pushd [dir | +N | -N] [-n]
+N
Brings the Nth directory (counting from the left of the list printed by dirs, starting with zero) to the top of the list by rotating the stack.
-N
Brings the Nth directory (counting from the right of the list printed by dirs, starting with zero) to the top of the list by rotating the stack.
-n
Suppresses the normal change of directory when adding directories to the stack, so that only the stack is manipulated.
dir
Makes the current working directory be the top of the stack, and then executes the equivalent of `cd dir'. cds to dir.
DIRSTACK
An array variable (see section Arrays) containing the current contents of the directory stack. Directories appear in the stack in the order they are displayed by the dirs builtin. Assigning to members of this array variable may be used to modify directories already in the stack, but the pushd and popd builtins must be used to add and remove directories.
 
Assignment to this variable will not change the current directory. If DIRSTACK is unset, it loses its special properties, even if it is subsequently reset.

The operations with stack were enhanced in zsh and then in bash by introducing the ability to use +/- with ~ . This feature is best described in the zsh documentation (note that in zsh the stack is 1-based, with the current directory treated as the 0th element):

Each word is checked to see if it begins with an unquoted ~. If it does, then the word up to a  /, or the end of the word if there is no  /, is checked to see if it can be substituted in one of the ways
described here. If so, then the  ~ and the checked portion are replaced with the appropriate substitute value.

~ by itself is replaced by the value of $HOME. A  ~ followed by a  + or a  - is replaced by the value of $PWD or $OLDPWD, respectively.

~ followed by a number is replaced by the directory at that position in the directory stack. ~0 is equivalent to ~+, and ~1 is the top of the stack. ~+ followed by a number is replaced by the directory at that position in the directory stack. ~+0 is equivalent to ~+, and ~+1 is the top of the stack. ~- followed by a number is replaced by the directory that many positions from the bottom of the stack. ~-0 is the bottom of the stack. The PUSHD_MINUS option exchanges the effects of ~+ and ~- where they are followed by a number.

~ followed by anything not already covered is looked up as a named directory, and replaced by the value of that named directory if found. Named directories are typically home directories for users on the system. They may also be defined if the text after the  ~ is the name of a string shell parameter whose value begins with a  /. It is also possible to define directory names using the -d option to the hash built-in.



NEWS CONTENTS

Old News ;-)

[ Sep 17, 2012 ] bash Tricks From the Developers of the O'Reilly Network

April, 2005 | O'Reilly ONLamp Blog

directory stack

Long ago having aliased "pu" and "po" to pushd and popd, I've moved on to showing my current directory stack with

alias d='dirs -v'

and rolling through the stack with

alias r='pushd +1'

and single numerical values aliased to go to that directory that comes from the dir listing, eg.

alias 3='pushd +3 > /dev/null ; dirs -v'

Another single letter alias I like is "p", which I have used for displaying and setting my PATH variable, but the code is lengthy so I won't burden you with how

p - 4
p --
p ++ /some/dir

does what you want.

[indiana-discuss] pushdopd&co. in bash-ksh93 ... - was Re scope

Roland Mainz roland.mainz at nrubsig.org
Wed Sep 12 09:32:34 PDT 2007


Hi!

----

[Sorry for the late reply, this one was apparently rotting in my
Drafts/-folder for a long time... ;-( ]

Tim Bray wrote:
> On Aug 8, 2007, at 10:56 AM, Richard Elling wrote:
> > pushd/popd and dirs came from csh.  They are invaluable when you only
> > had a terminal.  They are so invaluable that ksh code to implement
> > them
> > is on pp 244-247 of "The Kornshell Command and Programming
> > Language" by
> > Bolsky and Korn, ISBN 0-13-516972-0.
> 
> Right, well, I have a 24" screen with (at this moment in time) 3
> terminals active, all of which have several directories pushed.
> 
> I'm not religious about shells.  I am *passionate* that when we
> manage to get a Linux/OS-X user to try Indiana, they don't get rude
> shocks in the first three minutes because some basic piece of
> infrastructure that's wired into their muscle memory doesn't work.
> 
> If I get on Solaris and !! or !prefix-of-somerevious-command or
> pushd/popd doesn't work, *that's a bug*.  I don't want to micromanage
> how we fix it.   -Tim

Erm, technically the problem of "pushd/"popd" is that several shells
define "pushd" and "popd" with slightly different functionality/options
and there is no POSIX specification which could be used as guidance
(neither is it possible to just tack-on some functions to the shell
without checking whether this is allowed by the POSIX shell spec) ...

... but for interactive ksh93 sessions the solution is AFAIK quite easy:
ksh93 has a feature called "FPATH" which specifies a path (similar like
the "PATH" variable) from which shell functions can be loaded
dynamically at runtime. For ksh93 shipped with Solaris >= 11/B72 in
interactive mode this could be used to load the matching functions
"pushd"/"popd"/"dirs" from /usr/demo/ksh/fun/ via adding a
-- snip --
FPATH+="/usr/demo/ksh/fun/"
-- snip --
to /etc/ksh.kshrc

BTW: As a mid- or long-term project we'd like to add a larger shell
function library at the /usr/lib/shell/ksh/ directory (see CR 6601968
("RFE: Add /usr/lib/shell/ksh/ as a place to store loadable shell
functions")) which would move "pushd"/"popd"/"dirs" out of the demo
directory to something like /usr/lib/shell/ksh/org/opensolaris/dirutil/
, giving non-interactive shell scripts a permanent location they can
rely on.

----

Bye,
Roland

Push'n'Pop - Bash macro to simulate Tcsh cd functionality

I really like the directory bookmark/browsing ability of tcsh when aliasing the pushd command to cd. Using bash, I would naturally like to have the same abilities, but this turns out to be far from obvious to achieve.

The following listing is of a tcsh session displaying the desired functionality:

$ cd dir3
$ dirs
 0  ~/tmp/dir1/dir2/dir3
 1  ~/tmp/dir1/dir2
 2  ~/tmp/dir1
 3  ~/tmp
$ cd +2
$ pwd
/home/user/tmp/dir1
$ dirs
 0  ~/tmp/dir1
 1  ~/tmp
 2  ~/tmp/dir1/dir2/dir3
 3  ~/tmp/dir1/dir2
$ 

To get the above behavior a few settings needs to be put into the ~/.tcshrc initializations file:

# .tcshrc

alias dirs 'dirs -vl'

set dunique
set pushdsilent 
set pushdtohome 
alias cd 'pushd \!*'

Things gets a little complicated when trying to mimic these tcsh settings in bash, because no counterparts exists. This does, of course, not mean that it is not possible, but is does mean that scripting is necessary:

# .bashrc

alias dirs='dirs -v'
cd() {
   MAX=10
   LEN=${#DIRSTACK[@]}

   if [ $# -eq 0 ] || [ "$1" = "-" ]; then
      builtin cd "$@"
      pushd -n $OLDPWD > /dev/null
   else
      pushd "$@" > /dev/null || return 1
   fi

   if [ $LEN -gt 1 ]; then
      for i in `seq 1 $LEN`; do
         eval p=~$i
         if [ "$p" = "$PWD" ]; then
            popd -n +$i > /dev/null
            break
         fi
      done
   fi

   if [ $LEN -ge $MAX ]; then
      popd -n -0 > /dev/null
   fi
}

When this function is put into the ~/.bashrc initialization file, the bash cd command behave exactly as it does in tcsh.

Re bash feature request pushd -v, popd -v

Dave Rutherford
Fri, 15 Jul 2005 21:22:51 -0700 

On 7/15/05, Ben Horowitz <[EMAIL PROTECTED]> wrote:
> I grew to appreciate one feature of tcsh: the ability to use
> the commands pushd -v, and popd -v.
>
> As you know, when the bash pushd and popd commands are successful,
> they print the directory stack.  In tcsh, one can additionally issue
> the command pushd -v, which is like the bash commands pushd followed
> by dirs -v.  This feature appears not to be available in bash.
>
>   tcsh> pushd -v /tmp
>   0       /tmp
>   1       /

Does this do the trick?

pushd ()
{
    local verbose=0;
    if [ "$1" = "-v" ]; then
        verbose=1;
        shift;
    fi;
    builtin pushd "$@";
    if [ $verbose -eq 1 ]; then
        for w in $@;
        do
            echo "$w    ${DIRSTACK[$w]}";
        done;
    fi
}

Barely tested (and with bash 3.0 at that), but it seems to do
what you want.  popd would be very similar, of course.

Dave
===
Here's a first cut.  Salt to taste (yes, you should use getopts):

pushd()
{
        local es
        case "$1" in
        -v)     vflag=y; shift ;;
        esac

        builtin pushd "$@"
        es=$?
        [ -n "$vflag" ] && dirs -v
        return $es
}

-

Backtracking with bash

I was working with linux quite a bit today, and frequently changing between directories, when I wondered if there was a way to go back to the directory I was in previously.

Turns out there is a way:

 cd ~-
So if I was doing something like this:
[pete@bigred /]$ cd /etc
[pete@bigred etc]$ cd /usr/local
[pete@bigred local]$ cd ~-
[pete@bigred etc]$ pwd
/etc
If you want to create a command so you don't have to type ~- you can create an alias:
alias cdb='cd ~-'
This ~- thing works great if you only need to go back one directory, but what if you wanted to go back two directories. Continuing the last code sample:
[pete@bigred etc]$ cd ~-
[pete@bigred local]$ cd ~-
[pete@bigred etc]$ pwd
/etc
We are back to /etc and not / our starting point. What I want is something that keeps a history of the directories I've been to.

It turns out that the Bash (the "Bourne again shell") has a directory stack builtin. Three command line tools for manipulating the stack are avaliable dirs, pushd, and popd. More info about the directory stack in bash here.

If we pushd a directory onto the directory stack, we can retreive the top of the stack using dirs +1. I tried setting up some aliases to get it to work the way I wanted:

alias cdd='pushd'
alias cdb='cd `dirs +1`'
Those worked a bit, but I ran into a lot of problems, especially when in the home directory. Also when you run pushd, popd, or dirs it always prints the contents of the stack, I don't know how to suppress that. So I figured I would post it here, and see if anyone can come up with a solution, or if anyone knows of a better way of going about this.

Isn't it funny how software developers will spend hours of time trying to save a few seconds of their future time.

Comments

On 01/23/2004 at 1:19:30 AM MST John wrote:

cd - works. I don't think you need cd ~-.

On 04/24/2004 at 4:50:56 AM MDT Pritam wrote:

You can suppress the output redirecting the output to /dev/null e.g.

pushd <dir-name> >> /dev/null popd >> /dev/null

On 07/11/2007 at 2:13:43 PM MDT Freddy wrote:

You can use small script from http://fvue.nl/cdots which defines 1-7 dots commands:

$/usr/local/share> ... sh[Tab]

$/usr/share>

More bashing

Just add the following to your ~/.bashrc or if you want to make this work system wide add this to /etc/bashrc:
#redefine pushd and popd so they don't output the directory stack
pushd()
{
    builtin pushd "$@" > /dev/null
}
popd()
{
    builtin popd "$@" > /dev/null
}

#alias cd so it uses the directory stack
alias cd='pushd'
#aliad cdb as a command that goes one directory back in the stack
alias cdb'popd'

The redefinition of pushd and popd redirects their output to /dev/null instead of your terminal. This prevents them from displaying the entire stack every time they are called

Re:pushd and popd (and other tricks) (Score:1) 

by camh (32881) on Wednesday March 10, @06:25PM (#8526528)

alias pd pushd

alias po popd

Similar to what I have, except I use pp instead of pd (because its faster to type) and pp without args takes you to your home directory (like cd without args). To go along with it, I use

alias r "pushd +1"

alias rr "cd "$OLDPWD"

If you're working within a number of directories, use pp to get to them and then use r to rotate between the directories. rr is convenient to quickly cd somewhere else to do something and then get back again.

pushd and popd (and other tricks) (Score:5, Informative) 

by Komi (89040) <cgguenNO@SPAMattglobal.net> on Wednesday March 10, @02:41PM (#8524004)
(http://slashdot.org/) I've read throught the tcsh man pages and stole from other people and probably the least-known most useful trick I've found is pushd and popd (which I realias to pd and po), and of course directory stack substitution. Here's a snippet of code that's really useful:

alias pd pushd
alias po popd

cd /incredi/bly/long/path/name
pd /some/other/incredi/bly/long/path/name
cp *.mp3 =1 # =1 is the first entry on the dirstack
po # returns you back to first place

The other major time saver I use are sed and awk. I used each for a specific purpose. Sed works great for substitution, and awk I use to grab columns of data. Here's a sample of how I'd use both together. This will list the home directories of the users on a machine. It's simple, but there's a ton you can do with this technique.

who | awk '{print $1}' | sort | uniq | sed 's@^@/home/@g'

Here's other stuff I have grouped by sections in my .cshrc

First, I have my shell variables. The comments say what they do. The most important one is autolist.

set autolist # automatically lists possibilities after ambiguous completion
set dunique # removes duplicate entries in the dirstack
set fignore=(\~) # files ending in ~ will be ignored by completion
set histdup=prev # do not allow consecutive duplicate history entries
set noclobber # output redirection will not overwrite an existing file
set notify # notifies when a job completes
set symlinks=ignore # treats symbolic directories like real directories
set time=5 # processes that run longer than $time seconds will be timed.

Second, bindkeys are pretty neat. I rebind the up and down arrow keys. By default they scroll up and down one at a time through the history. You can bind them to search the history based on what you've typed so far.

bindkey -k up history-search-backward # up arrow key
bindkey -k down history-search-forward # down arrow key

Third, completes allow for customizing tab completion. When I change directories, tab only completes directory names. This also works for aliases, sets, setenvs, etc.

complete cd 'p/1/d/'
complete alias 'p/1/a/'
complete setenv 'p/1/e/'
complete set 'p/1/s/'

Fourth, I have all my aliases. I had to cut a bunch because of the lameness filter.

alias cwdcmd 'ls'
alias precmd 'echo -n "\033]0;$USER@`hostname` : $PWD\007"'
alias pd 'pushd'
alias po 'popd'
alias dirs 'dirs -v'
alias path 'printf "${PATH:as/:/\n/}\n"'
alias ff 'find . -name '\''\!:1'\'' rint \!:2*'
alias aw 'awk '\''{print $'\!:1'}'\'''
alias sub 'sed "s@"\!:1"@"\!:2"@g"'

Re:pushd and popd (and other tricks) (Score:1)

by MasterLock (581630) on Wednesday March 10, @03:23PM (#8524465)

Two of my most handy aliases (tcsh and 4DOS/4NT) are:

alias mcd 'md \!*; cd \!*'

alias rcd 'setenv OLD_DIR `pwd`;cd ..;echo $OLD_DIR;rd "$OLD_DIR"; unsetenv OLD_DIR' Usage: ~/> mcd junkDir ~/junk> -- do commands, unzip files, et cetera -- ~/junk> rcd ~/> -- back where you were and the dir is gone --

Re:pushd and popd (and other tricks) (Score:1, Informative)
by Anonymous Coward on Wednesday March 10, @03:25PM (#8524497)

alias pd pushd
alias po popd

cd /incredi/bly/long/path/name
pd /some/other/incredi/bly/long/path/name
cp *.mp3 =1 # =1 is the first entry on the dirstack
po # returns you back to first place


cd /some/directory/
cd /another/directory/
cp *.mp3 ~-
cd ~-

Re:pushd and popd (and other tricks) (Score:2, Informative)

by MasterLock (581630) on Wednesday March 10, @03:33PM (#8524577)

f my most handy aliases (tcsh and 4DOS/4NT) are:

alias mcd 'md \!*; cd \!*'

alias rcd 'setenv OLD_DIR `pwd`; cd ..; echo $OLD_DIR;rd "$OLD_DIR"; unsetenv OLD_DIR'

Usage:
~/> mcd junkDir
~/junk> -- do commands, unzip files, et cetera --
~/junk> rcd
~/> -- back where you were and the dir is gone --

Microsoft Windows XP - Popd

Popd

Changes the current directory to the directory stored by the pushd command.

Syntax

popd

Parameters

/? : Displays help at the command prompt.

Remarks

Examples

You can use pushd and popd in a batch program to change the current directory from the one in which the batch program was run and then change it back. The following sample batch program shows how to do this:

@echo off
rem This batch file deletes all .txt files in a specified directory
pushd %1
del *.txt
popd
cls
echo All text files deleted in the %1 directory

An Introduction to the Z Shell - Directory Stacks

If you use csh, you may know about directory stacks. The pushd command puts the current directory on the stack, and changes to a new directory; the popd command pops a directory off the stack and changes to it.

phoenix% cd 
phoenix% PROMPT='Z %~> '
Z ~> pushd /tmp
/tmp ~
Z /tmp> pushd /usr/etc
/usr/etc /tmp ~
Z /usr/etc> pushd /usr/bin
/usr/bin /usr/etc /tmp ~
Z /usr/bin> popd
/usr/etc /tmp ~
Z /usr/etc> popd
/tmp ~
Z /tmp> pushd /etc
/etc /tmp ~
Z /etc> popd 
/tmp ~

zsh's directory stack commands work similarly. One difference is the way pushd is handled if no arguments are given. As in csh, this exchanges the top two elements of the directory stack:

Z /tmp> dirs
/tmp ~
Z /tmp> pushd
~ /tmp

unless the stack only has one entry:

Z ~> popd
/tmp
Z /tmp> dirs
/tmp
Z /tmp> pushd
~ /tmp

or unless the PUSHDTOHOME option is set:

Z ~> setopt pushdtohome
Z ~> pushd
~ ~ /tmp

As an alternative to using directory stacks in this manner, we can get something like a directory history by setting a few more options and parameters:

~> DIRSTACKSIZE=8
~> setopt autopushd pushdminus pushdsilent pushdtohome
~> alias dh='dirs -v'
~> cd /tmp
/tmp> cd /usr
/usr> cd bin
/usr/bin> cd ../pub
/usr/pub> dh
0       /usr/pub
1       /usr/bin
2       /usr
3       /tmp
4       ~
/usr/pub> cd -3
/tmp> dh
0       /tmp
1       /usr/pub
2       /usr/bin
3       /usr
4       ~
/tmp> ls =2/df
/usr/bin/df
/tmp> cd -4
~>

Note that =2 expanded to the second directory in the history list, and that cd -3 recalled the third directory in the list.

You may be wondering what all those options do. AUTOPUSHD made cd act like pushd. (alias cd=pushd is not sufficient, for various reasons.) PUSHDMINUS swapped the meaning of cd +1 and cd -1 we want them to mean the opposite of what they mean in csh, because it makes more sense in this scheme, and it's easier to type:

~> dh
0       ~
1       /tmp
2       /usr/pub
3       /usr/bin
4       /usr
~> unsetopt pushdminus
~> cd +1
/tmp> dh
0       /tmp
1       ~
2       /usr/pub
3       /usr/bin
4       /usr
/tmp> cd +2
/usr/pub>

PUSHDSILENT keeps the shell from printing the directory stack each time we do a cd, and PUSHDTOHOME we mentioned earlier:

/usr/pub> unsetopt pushdsilent
/usr/pub> cd /etc
/etc /usr/pub /tmp ~ /usr/bin /usr
/etc> cd
~ /etc /usr/pub /tmp ~ /usr/bin /usr
~> unsetopt pushdtohome
~> cd
/etc ~ /usr/pub /tmp ~ /usr/bin /usr
/etc>

DIRSTACKSIZE keeps the directory stack from getting too large, much like HISTSIZE:

/etc> setopt pushdsilent
/etc> cd /
/> cd /
/> cd /
/> cd /
/> cd /
/> cd /
/> cd /
/> cd /
/> dh
0       /
1       /
2       /
3       /
4       /
5       /
6       /
7       /
Zsh offers a nice way to reference the directory stack quickly in your daily work. The description below is taken directly from the man page:
     A `~' followed by a number is replaced by the  directory  at
     that position in the directory stack.  ~0 is equivalent to
     ~+, and ~1 is the top of the stack.  ~+ followed by  a
     number  is replaced by the directory at that position in the
     directory stack.  ~+0 is equivalent to ~+, and ~+1  is
     the top of the stack.  ~- followed by a number is replaced
     by the directory that many positions from the bottom of  the
     stack.   ~-0  is the bottom of the stack.  The PUSHD_MINUS
     option exchanges the effects of ~+ and ~- where they are
     followed by a number.

dirs in Your Prompt: Better than $cwd 

The C shell gives the absolute pathname of your current directory in $cwd (14.13). Many people use that in their prompts. If you use the pushd and popd (14.6) commands, you may not always remember exactly what's in your directory stack (I don't, at least). Also, do you want to shorten your home directory pathname to just a tilde (~) so it takes less room in the prompt? Here's how: run the dirs command and use its output in your prompt. A simple alias for cd users looks like this:

alias cd 'chdir \!* && set prompt="`dirs`% "'

and the prompts look like:

/work/project % cd
~ % cd bin
~/bin %

Here's what to put in .cshrc to make a multiline prompt (7.5) that shows the directory stack:

uname -n 
expr 
# PUT hostname.domain.name IN $hostname AND hostname IN $HOST:
set hostname=`uname -n`
setenv HOST `expr $hostname : '\([^.]*\).*'`

alias setprompt 'set prompt="\\
${USER}@${HOST} `dirs`\\
\! % "'
alias cd  'chdir \!* && setprompt'
alias pushd  'pushd \!* && setprompt'
alias popd  'popd  \!* && setprompt'
setprompt   # SET THE INITIAL PROMPT

Because bash can run a command each time it sets its prompt, and because it has built-in prompt operators (7.4), the bash version of all the stuff above fits on one line:

$(...) 
PS1='\n\u@\h $(dirs)\n\! \$ '

That makes a blank line before each prompt; if you don't want that, join the first and second lines of the setprompt alias or remove the first \n. Let's push a couple of directories and watch the prompt:

jerry@ora ~
1 % pushd /work/src/perl
/work/src/perl ~

jerry@ora /work/src/perl ~
2 % cd ../cnews

jerry@ora /work/src/cnews ~
3 % pushd ~/bin
~/bin /work/src/cnews ~

jerry@ora ~/bin /work/src/cnews ~
4 %

Warning!

Of course, the prompt looks a little redundant there because each pushd command also shows the dirs output. A few commands later, though, having your directory stack in the prompt will be handy. If your directory stack has a lot of entries, the first line of the prompt can get wider than the screen. In that case, store the dirs output in a shell array (47.5) and edit it with a command like sed or with the built-in csh string editing (9.6).

For example, to show just the tail of each path in the dirs output, use the alias below; the C shell operator :gt globally edits all words, to the tail of each pathname:

alias setprompt 'set dirs=(`dirs`); set prompt="\\
${USER}@${HOST} $dirs:gt\\
\! % "'

Watch the prompt. If you forget what the names in the prompt mean, just type dirs:

History of visited directories in BASH LG #109 By Petar Marinov

Deficiencies of the CD command

Do you realize how many times you type cd per day? Do you realize how many times you retype the same directory names again and again? Ever since I migrated from 4DOS/NT shell on Windows to using Bash on Unix platforms, I've missed its cd history access. In 4DOS/NT the history of the visited directories can be navigated by Ctrl+PgUp/Dn. Every time you go to a new directory by cd, its name automatically goes on top of an easily accessible history list.

In Bash, cd - switches between the last two directories. This is a function in the right direction but many times I wanted to go to the directory before the last, I dreamed of something like cd -2.

A little scripting creates some sanity in the directory navigation of Bash.

Installing the CD history function

To install the modified CD function, copy acd_func.sh to any directory in your $PATH, or even your home directory. At the end of your .bashrc add source acd_func.sh. Restart your bash session and then type cd --.

lotzmana@safe$ cd --
0  ~

Type cd -- to verify if the installation works. Above you may see the result 0 ~. This shows that you have one directory in your history.

lotzmana@safe$ cd work
lotzmana@safe$ cd scripts
lotzmana@safe$ pwd
/home/petarma/work/scripts
lotzmana@safe$ cd --
 0  ~/work/scripts
 1  ~/work
 2  ~
lotzmana@safe$ cd -2
lotzmana@safe$ pwd
/home/petarma

The cd command works as usual. The new feature is the history of the last 10 directories and the cd command expanded to display and access it. cd -- (or simply pressing ctrl+w) shows the history. In front of every directory name you see a number. cd -num with the number you want jumps to the corresponding directory from the history.

How CD with history works

lotzmana@safe$ nl -w2 -s' '  acd_func.sh
 1 # do ". acd_func.sh"
 2 # acd_func 1.0.5, 10-nov-2004
 3 # petar marinov, http:/geocities.com/h2428, this is public domain

 4 cd_func ()
 5 {
 6   local x2 the_new_dir adir index
 7   local -i cnt

 8   if [[ $1 ==  "--" ]]; then
 9     dirs -v
10     return 0
11   fi

12   the_new_dir=$1
13   [[ -z $1 ]] && the_new_dir=$HOME

14   if [[ ${the_new_dir:0:1} == '-' ]]; then
15     #
16     # Extract dir N from dirs
17     index=${the_new_dir:1}
18     [[ -z $index ]] && index=1
19     adir=$(dirs +$index)
20     [[ -z $adir ]] && return 1
21     the_new_dir=$adir
22   fi

23   #
24   # '~' has to be substituted by ${HOME}
25   [[ ${the_new_dir:0:1} == '~' ]] && the_new_dir="${HOME}${the_new_dir:1}"

26   #
27   # Now change to the new dir and add to the top of the stack
28   pushd "${the_new_dir}" > /dev/null
29   [[ $? -ne 0 ]] && return 1
30   the_new_dir=$(pwd)

31   #
32   # Trim down everything beyond 11th entry
33   popd -n +11 2>/dev/null 1>/dev/null

34   #
35   # Remove any other occurence of this dir, skipping the top of the stack
36   for ((cnt=1; cnt <= 10; cnt++)); do
37     x2=$(dirs +${cnt} 2>/dev/null)
38     [[ $? -ne 0 ]] && return 0
39     [[ ${x2:0:1} == '~' ]] && x2="${HOME}${x2:1}"
40     if [[ "${x2}" == "${the_new_dir}" ]]; then
41       popd -n +$cnt 2>/dev/null 1>/dev/null
42       cnt=cnt-1
43     fi
44   done

45   return 0
46 }

47 alias cd=cd_func

48 if [[ $BASH_VERSION > "2.05a" ]]; then
49   # ctrl+w shows the menu
50   bind -x "\"\C-w\":cd_func -- ;"
51 fi

4-7: cd_func() is a function, variables are declared local and are automatically deleted at the end of the function

8-11: if the function is called with a parameter "--" then it dumps the current content of the directory history. It is stored in the same place pushd/popd keep names -- the directory stack. Storage is the same, access is different.

12-13: Argument $1 is transferred into $the_new_dir for some postrocessing. Immediately after that, if there are no parameters we assume that user asked for his home directory.

14-22: If parameter begins with '-' then the user is attempting to access one of the names in the history list. $index gets the number of the directory, then we extract the corresponding name into $adir. For example, dirs +3 dumps directory #3 from the stack.

At this point in $the_new_dir we have either a name specified explicitly as a parameter or a name obtained from the history of previously visited directories.

23-25: If a directory name begins with '~' then this character has to be replaced by the actual home directory name.

26-30: pushd does the actual 'cd'. It also puts the name on top of the directory stack. stdout is redirected to /dev/null in order to completely imitate how 'cd' works. Notice that any output to stderr, for example a message telling that the directory specified by the user doesn't exist will show up, which is again similar to what 'cd' does. The function aborts if pushd fails. We also need the new directory name for further analysis and $the_new_dir carries it down the function.

31-33: Keeping track of more than 10 directories is unproductive. Since we have just pushed one on top of the stack, we trim off any that fall below 11 names deep.

34-44: We loop through all the names in the directory stack. Any name that matches the new current directory is eliminated. Again, we have to translate any name from the list which begins with '~' to its format of fully expanded home directory.

47: We assign cd to be cd_func().

48-51: If the bash version allows for macros to be assigned we make ctrl+w summon the history of visited directories.

This script defines a function. It must be sourced and not executed, so that cd_func() is parsed and stored in the current environment. Try env and you must see it after all environment variables.

Documentation page of the script

Visit the acd_func.sh man page.

 

Recommended Links

Softpanorama hot topic of the month

Softpanorama Recommended

Please visit Heiner Steven SHELLdorado the best shell scripting site on the Internet

Reference

dirs

dirs [+N | -N] [-clpv]
Display the list of currently remembered directories. Directories are added to the list with the pushd command; the popd command removes directories from the list.
+N
Displays the Nth directory (counting from the left of the list printed by dirs when invoked without options), starting with zero.
-N
Displays the Nth directory (counting from the right of the list printed by dirs when invoked without options), starting with zero.
-c
Clears the directory stack by deleting all of the elements.
-l
Produces a longer listing; the default listing format uses a tilde to denote the home directory.
Causes dirs to print the directory stack with one entry per line.
-v
Causes dirs to print the directory stack with one entry per line, prefixing each entry with its index in the stack.

popd

popd [+N | -N] [-n]

Remove the top entry from the directory stack, and cd to the new top directory. When no arguments are given, popd removes the top directory from the stack and performs a cd to the new top directory. The elements are numbered from 0 starting at the first directory listed with dirs i.e., popd is equivalent to popd +0.

+N
Removes the Nth directory (counting from the left of the list printed by dirs), starting with zero.
-N
Removes the Nth directory (counting from the right of the list printed by dirs), starting with zero.
-n
Suppresses the normal change of directory when removing directories from the stack, so that only the stack is manipulated.

pushd

pushd [dir | +N | -N] [-n]

Save the current directory on the top of the directory stack and then cd to dir. With no arguments, pushd exchanges the top two directories.

+N
Brings the Nth directory (counting from the left of the list printed by dirs, starting with zero) to the top of the list by rotating the stack.
-N
Brings the Nth directory (counting from the right of the list printed by dirs, starting with zero) to the top of the list by rotating the stack.
-n
Suppresses the normal change of directory when adding directories to the stack, so that only the stack is manipulated.
dir
Makes the current working directory be the top of the stack, and then executes the equivalent of `cd dir'. cds to dir.

DIRSTACK

An array variable (see section Arrays) containing the current contents of the directory stack. Directories appear in the stack in the order they are displayed by the dirs builtin. Assigning to members of this array variable may be used to modify directories already in the stack, but the pushd and popd builtins must be used to add and remove directories. Assignment to this variable will not change the current directory. If DIRSTACK is unset, it loses its special properties, even if it is subsequently reset.



Etc

FAIR USE NOTICE This site contains copyrighted material the use of which has not always been specifically authorized by the copyright owner. We are making such material available in our efforts to advance understanding of environmental, political, human rights, economic, democracy, scientific, and social justice issues, etc. We believe this constitutes a 'fair use' of any such copyrighted material as provided for in section 107 of the US Copyright Law. In accordance with Title 17 U.S.C. Section 107, the material on this site is distributed without profit exclusivly for research and educational purposes.   If you wish to use copyrighted material from this site for purposes of your own that go beyond 'fair use', you must obtain permission from the copyright owner. 

ABUSE: IPs or network segments from which we detect a stream of probes might be blocked for no less then 90 days. Multiple types of probes increase this period.  

Society

Groupthink : Two Party System as Polyarchy : Corruption of Regulators : Bureaucracies : Understanding Micromanagers and Control Freaks : Toxic Managers :   Harvard Mafia : Diplomatic Communication : Surviving a Bad Performance Review : Insufficient Retirement Funds as Immanent Problem of Neoliberal Regime : PseudoScience : Who Rules America : Neoliberalism  : The Iron Law of Oligarchy : Libertarian Philosophy

Quotes

War and Peace : Skeptical Finance : John Kenneth Galbraith :Talleyrand : Oscar Wilde : Otto Von Bismarck : Keynes : George Carlin : Skeptics : Propaganda  : SE quotes : Language Design and Programming Quotes : Random IT-related quotesSomerset Maugham : Marcus Aurelius : Kurt Vonnegut : Eric Hoffer : Winston Churchill : Napoleon Bonaparte : Ambrose BierceBernard Shaw : Mark Twain Quotes

Bulletin:

Vol 25, No.12 (December, 2013) Rational Fools vs. Efficient Crooks The efficient markets hypothesis : Political Skeptic Bulletin, 2013 : Unemployment Bulletin, 2010 :  Vol 23, No.10 (October, 2011) An observation about corporate security departments : Slightly Skeptical Euromaydan Chronicles, June 2014 : Greenspan legacy bulletin, 2008 : Vol 25, No.10 (October, 2013) Cryptolocker Trojan (Win32/Crilock.A) : Vol 25, No.08 (August, 2013) Cloud providers as intelligence collection hubs : Financial Humor Bulletin, 2010 : Inequality Bulletin, 2009 : Financial Humor Bulletin, 2008 : Copyleft Problems Bulletin, 2004 : Financial Humor Bulletin, 2011 : Energy Bulletin, 2010 : Malware Protection Bulletin, 2010 : Vol 26, No.1 (January, 2013) Object-Oriented Cult : Political Skeptic Bulletin, 2011 : Vol 23, No.11 (November, 2011) Softpanorama classification of sysadmin horror stories : Vol 25, No.05 (May, 2013) Corporate bullshit as a communication method  : Vol 25, No.06 (June, 2013) A Note on the Relationship of Brooks Law and Conway Law

History:

Fifty glorious years (1950-2000): the triumph of the US computer engineering : Donald Knuth : TAoCP and its Influence of Computer Science : Richard Stallman : Linus Torvalds  : Larry Wall  : John K. Ousterhout : CTSS : Multix OS Unix History : Unix shell history : VI editor : History of pipes concept : Solaris : MS DOSProgramming Languages History : PL/1 : Simula 67 : C : History of GCC developmentScripting Languages : Perl history   : OS History : Mail : DNS : SSH : CPU Instruction Sets : SPARC systems 1987-2006 : Norton Commander : Norton Utilities : Norton Ghost : Frontpage history : Malware Defense History : GNU Screen : OSS early history

Classic books:

The Peter Principle : Parkinson Law : 1984 : The Mythical Man-MonthHow to Solve It by George Polya : The Art of Computer Programming : The Elements of Programming Style : The Unix Haterís Handbook : The Jargon file : The True Believer : Programming Pearls : The Good Soldier Svejk : The Power Elite

Most popular humor pages:

Manifest of the Softpanorama IT Slacker Society : Ten Commandments of the IT Slackers Society : Computer Humor Collection : BSD Logo Story : The Cuckoo's Egg : IT Slang : C++ Humor : ARE YOU A BBS ADDICT? : The Perl Purity Test : Object oriented programmers of all nations : Financial Humor : Financial Humor Bulletin, 2008 : Financial Humor Bulletin, 2010 : The Most Comprehensive Collection of Editor-related Humor : Programming Language Humor : Goldman Sachs related humor : Greenspan humor : C Humor : Scripting Humor : Real Programmers Humor : Web Humor : GPL-related Humor : OFM Humor : Politically Incorrect Humor : IDS Humor : "Linux Sucks" Humor : Russian Musical Humor : Best Russian Programmer Humor : Microsoft plans to buy Catholic Church : Richard Stallman Related Humor : Admin Humor : Perl-related Humor : Linus Torvalds Related humor : PseudoScience Related Humor : Networking Humor : Shell Humor : Financial Humor Bulletin, 2011 : Financial Humor Bulletin, 2012 : Financial Humor Bulletin, 2013 : Java Humor : Software Engineering Humor : Sun Solaris Related Humor : Education Humor : IBM Humor : Assembler-related Humor : VIM Humor : Computer Viruses Humor : Bright tomorrow is rescheduled to a day after tomorrow : Classic Computer Humor

The Last but not Least


Copyright © 1996-2016 by Dr. Nikolai Bezroukov. www.softpanorama.org was created as a service to the UN Sustainable Development Networking Programme (SDNP) in the author free time. This document is an industrial compilation designed and created exclusively for educational use and is distributed under the Softpanorama Content License.

The site uses AdSense so you need to be aware of Google privacy policy. You you do not want to be tracked by Google please disable Javascript for this site. This site is perfectly usable without Javascript.

Original materials copyright belong to respective owners. Quotes are made for educational purposes only in compliance with the fair use doctrine.

FAIR USE NOTICE This site contains copyrighted material the use of which has not always been specifically authorized by the copyright owner. We are making such material available to advance understanding of computer science, IT technology, economic, scientific, and social issues. We believe this constitutes a 'fair use' of any such copyrighted material as provided by section 107 of the US Copyright Law according to which such material can be distributed without profit exclusively for research and educational purposes.

This is a Spartan WHYFF (We Help You For Free) site written by people for whom English is not a native language. Grammar and spelling errors should be expected. The site contain some broken links as it develops like a living tree...

You can use PayPal to make a contribution, supporting development of this site and speed up access. In case softpanorama.org is down you can use the at softpanorama.info

Disclaimer:

The statements, views and opinions presented on this web page are those of the author (or referenced source) and are not endorsed by, nor do they necessarily reflect, the opinions of the author present and former employers, SDNP or any other organization the author may be associated with. We do not warrant the correctness of the information provided or its fitness for any purpose.

Last modified: July 30, 2014