|
Softpanorama
(slightly skeptical)
Open Source Software Educational Society |
May the
source be with you,
but remember the KISS principle ;-)
|
Improving the usefulness of pushd / popd / dirs troika in
Unix filesystem navigation
Remember, there's a limited number of
keystrokes in a lifetime - use them wisely.
Unix has a huge number of directories and no good way to navigate them. Famous
cd command is too simplistic to help when you
have over 10K directories in the directory tree. the right way was
actually invented in DOS with the advent of NCD and Orthodox managers but Unix
is lagging behind and there although both orthodox manager and NCD clones re
available they are not widely used.
But usually for a particular user on a particular server there is patterns of usage of this directory tree.
First of all some directories are used more often, some never at all.
Another common pattern
is shuttling between two or three directories, repeatedly editing, compiling, running,
archiving or deleting some files. This particular pattern of usage was noticed very
early and pushd/popd/dirs troika is not very
effective Bill Joy
attempt to simplify and speed up filesystem navigation in C shell. The idea was
brilliant but unfortunately nobody tried to improve the first bad implementation
and eventually it became standardized (lemmings rules). But the fact that underling implementation if
primitive does not mean that idea cannot be reused -- one definitely can adapt
the initial (and brilliant) Bill Joe idea to modern capabilities of
bash or ksh93 shells. You should also look at
NCD clones
pushd is essentially an elegant
generalization of cd invented by
Bill Joe and first implemented in C-shell: in addition to
moving to a particular directory it stores the current directory in a directory
stack (with optional suppression of duplicates).
Right now duplicate directories can be suppressed
only in tcsh (with option set dunique.) It looks like in bash
the implementation of pushd/popd is very weak and not only dies not support this
option but contain some bugs that corrupt directory stack in cetain
circamstances.
And without the supression of duplicates the functionality of push/pop is much less usable (if at
all)... Pushd can also be used with -n argument
to populate stack with the set of directories. Bash also provides an
environment variable called PROMPT_COMMAND.
The contents of this variable are executed as a regular Bash command just before
Bash displays a prompt. This command can be used to maintain visited
directories list.
Later on,
popd can be used to restore to move to any
of the directories in the stack. The weakness of implementation is that it
always removes the directory from the stack.
Paradoxically the ksh idiom cd - that permit toggling between
two directories proved to be more useful for me then complex machinery of push/popd/dirs
(Entering cd - return you to the last directory we used; entering it
a second time "toggles" us back again). The key idea is to
generalize it permitting to do cd -- or cd --- . The simplest way to
implement cd -- and
cd --- commands is by defining aliases
cd-- and
cd--- respectively (note that there
should be no space in alias names, but that's not bad -- saves you one keystroke
:-).
The simplest way is to define set of aliases:
alias cd='pushd '
alias rr='pushd'
alias cd-='popd'
alias cd--='popd -2'
alias cd---='popd -3'
alias d='dirs -v'
alias b='pushd +1'
The first step is to redefine cd as pushd so that you do not need to
type additional letters and change your navigation habits:
alias cd='pushd '
If you do like to see the list of directories in the stack you can also
use
pushd()
{
builtin pushd "$@" > /dev/null
}
The simplest way is to define aliases:
alias cd-='popd'
alias cd--='popd -2'
alias cd---=popd -3'
While I never managed to use productively the original functionality of pushd/popd/dirs
troika I found that you can benefit from cd -- and cd ---
functionality.
the third way to use pushd/popd is to to use it as a proxy
to the directories favorite list. To do this we need better
understand the capabilities of each of the commands in pushd/popd/dirs
troika
dirs
-
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.
-p
- 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]
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.
dirs command is very useful if we try to use pushd/popd as a favorites list. If nothing else it provides you with the history of visited directories:
small but useful improvement over pitiful standard bash mode ;-). To
put directory into the stack you can use the ability to use pushd
simply store directories using option -n. Initial population
of the list of favorites can be done from the .profile via
history command (all cd commands can be pushed into stack. see below).
After populating the DIRSTACK you can use shortcuts to directories via cd ~1, cd ~2, ...
notation. For example if :
dirs -v
0 ~
1 /var/log
2 /usr/local
Then
cd ~1
is equal to cd /var/log
and
cd ~2
is equal to cd /usr/local
Notes
- In bash we cannot directly execute pushd command in the pipe as bash
contain the bug -- the last stage of the pipe does not belongs to the
current environment as in ksh.
- We can also prepend a set of valuable directories.
Dr. Nikolai Bezroukov
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.
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-some-previous-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
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.
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.
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
}
-
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.
Trackbacks
Trackback Address:
http://www.petefreitag.com/tb/66/A132A1E502B1F3B7C329191D6E9FBE4C
cd - works. I don't think you need cd ~-.
You can suppress the output redirecting the output to /dev/null
e.g. pushd <dir-name> >> /dev/null popd >> /dev/null
You can use small script from http://fvue.nl/cdots which
defines 1-7 dots commands:
$/usr/local/share> ... sh[Tab]
$/usr/share>
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'\'' -print \!: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 --
|
Popd
Changes the current directory to
the directory stored by the pushd command.
Syntax
popd
Parameters
/? : Displays help at the
command prompt.
Remarks
|
•
|
Every time you use the
pushd command, a single directory is stored for your use. However,
you can store multiple directories by using the pushd command
multiple times.
The directories are stored sequentially in a virtual stack. If you use
the pushd command once, the directory in which you use the command
is placed at the bottom of the stack. If you use the command again,
the second directory is placed on top of the first one. The process
repeats every time you use the pushd command.
You can use the popd command to change the current directory
to the directory most recently stored by the pushd command. If
you use the popd command, the directory on the top of the stack
is removed from the stack as the current directory is changed to that
directory. If you use the popd command again, the next directory
on the stack is removed.
|
|
•
|
When command extensions
are enabled, the popd command removes any drive-letter assignations
created by pushd.
|
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
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.
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:
|
|
# 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:
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
--.
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 post-processing. 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.
|
Please visit Heiner Steven
SHELLdorado the
best shell scripting site on the Internet
|
dirs
-
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.
-p
- 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
-
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.
Copyright © 1996-2007 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.
Submit
comments This document is an industrial compilation designed and created
exclusively for educational use and is placed under the copyright of the
Open Content License(OPL).
Original materials copyright belong to respective owners. Quotes are made
for educational purposes only in compliance with the fair use doctrine.
Standard disclaimer: The statements, views and opinions presented on
this web page are those of the author 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:
April 02, 2008
Comments