allbery@ncoast.UUCP (09/24/87)
Hello ( is there a better greeting that does not sound so boring? ) -
Having been working for a long time under csh and being
accustomed to the commands pushd and popd, I was saddened to find that
these commands were not avaiable under my version of Microport Unix
System V (version 2.2). I had just come across ksh routines to do this
and thought, hey, what a wonderful way to spend a few hours instead of
doing something that I should be doing (like real work 8-). The result
is my first csh program (all other shell programs where written using
the bourne shell). It is used with a few (four) alias-es and manages a
directory stack. Hope you find it useful.
If you decide to give this a try, wait until using it before
reading the next sentence. You shouldn't be reading this unless you've
tried it already - okay - experienced it? - well ... it may not be
incredibly fast, but the object was to learn a bit of the c shell.
Rickers
..!drexel!rickers
==========c=u=t====h=e=r=e=====================c=u=t====h=e=r=e=========
#!/bin/csh
#
# (-8 tab stops should be at every four for easy readibility 8-)
#
# dirstack -- c shell script to manipulate a directory stack
# written by rickers, august 29, 1987
#
# Permission is granted to do what you wish with this code. Happily
# placed in the public domain. No copyrights - no nutin'.
#
# Description of routines:
# init -- initializes the environment so that the routines can work.
# dirs -- prints out directory stack.
# pushd -- push the current directory and change to that specified
# popd -- pop a directory and change to it
#
# These routines pattern themselves after the same functions of the
# C shell, with a few exceptions. Idea to write this script taken from
# ksh script originally written by David C. Stewart, and modified to
# work under MKS tookkit ksh by Keith Ericson, both of Tektronix Inc.
#
# To use, some aliases are needed. These follow.
# set dirstack=/usr/local/lib/dirstack
# alias initds "set argv=(init \!*); source $dirstack; set argv"
# alias dirs "set argv=(dirs \!*); source $dirstack; set argv"
# alias pushd "set argv=(pushd \!*); source $dirstack; set argv"
# alias popd "set argv=(popd \!*); source $dirstack; set argv"
# unset dirstack
#
# This file should be placed in a known directory. The dirstack variable
# is just to make the alias look a bit neater.
#
# You may be pondering with the question "why did he do it this way?" when
# i figure it out, i will let you know (maybe). it just seemed the thing to
# do. note these need routines need to be executed using source. it is
# faster (it does not invoke another shell) and it makes the variable
# available to the shell.
#
# Oh, btw, the other reason this was written, was to make up for a lacking
# csh under Microport Unix System V 2.2.
#
#
# Depending on argv[1], goto a certain spot in the script and execute
#
goto $argv[1]
init:
# the current directory stack depth
set ddepth=1
# dstack is the directory stack, set to a max depth of 20
set dstack=(`pwd` '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '')
goto finish
#
# dirs is equivalent (almost) to the csh command `dirs'. It prints out
# the stack, current directory first, followed by top of stack, and the
# rest of the stack. it fmt-s the output so it looks nice and does not
# get fold-ed at 80 chars. It is a bit slow - oh well, so are the rest
# of the routines.
#
dirs:
set i=$ddepth
if ( $i == 1 ) set dstack[1]=`pwd`
cp /dev/null /tmp/$$
while ($i > 0)
echo $dstack[$i] >> /tmp/$$
@ i = $i - 1
end
sed "s,$home,\~,g" /tmp/$$ | fmt ; rm /tmp/$$
goto finish
#
# pushd is stretching from the csh definition of pushd. given one arg,
# it pushes the current directory on the stack, and changes to the
# specified directory. now comes the kludge. to specify a buried
# directory, use the syntax: pushd + n. note the space between the
# plus sign and the number. It is there to make life easier and faster.
# you wouldn't want it any other way now, would you? also, the way it
# works is different from the way my pushd works (under 4.2BSD). It
# exchanges the current directory and the specified directory, making
# the specified directory current. note that the number is offset to
# the current directory on the dirs print-out ( + 1 is top of stack ).
# also note that the current directory is not on the top of the stack.
# pushd given with no arguments is the exact same as pushd + 1, and
# exchanges the current directory with the top to the stack.
#
pushd:
switch ($#argv)
case 1:
if ( $ddepth < 2 ) then
echo pushd: No other directory.
goto finish
else
@ i = $ddepth - 1
set temp=$dstack[$i]
set dstack[$i]=$dstack[$ddepth]
set dstack[$ddepth]=$temp
cd $dstack[$ddepth]
endif
breaksw
case 2:
if ( $ddepth == 1 ) set dstack[1]=`pwd`
@ ddepth++
cd $argv[2]
set dstack[$ddepth]=`pwd`
breaksw
case 3:
@ i = $argv[3]
@ i = $ddepth - $i
set temp=$dstack[$i]
set dstack[$i]=$dstack[$ddepth]
set dstack[$ddepth]=$temp
cd $dstack[$ddepth]
breaksw
default:
echo usage: pushd \| pushd name \| pushd +n
goto finish
endsw
goto dirs
#
# popd is stretching from the csh definition of popd. given no args,
# it pops one directory from the stack and makes it current, assuming
# that one exists. again a kludge (same one). to specify a buried
# directory, use the syntax: popd + n. note the space between the
# plus sign and the number. same old argument as above. but, ha, this
# one actually works like the csh popd. oh well, there goes the large
# deviation. what this action does is removes the specifed directory
# from the directory stack. again, note that the number is offset to
# the current directory on the dirs print-out ( + 1 is top of stack ).
# also note that the current directory is not on the top of the stack,
# although it is the first printed in the dirs output.
#
popd:
if ( $ddepth == 1 ) then
echo popd: Directory stack empty.
goto finish
else switch ($#argv)
case 1:
breaksw
case 2:
echo usage: popd \[ + n \]
goto finish
breaksw
case 3:
if ( ($argv[3] < 1) || ($argv[3] >= $ddepth) ) then
echo popd: Illegal value.
goto finish
endif
@ i = $ddepth - $argv[3]
while ( $i < $ddepth )
@ temp = $i + 1
set dstack[$i]=$dstack[$temp]
@ i = $i + 1
end
breaksw
endsw
endif
@ ddepth--
cd $dstack[$ddepth]
goto dirs
#
# finishup is the generic get outta here routine.
#
finish:
unset i
unset tempallbery@ncoast.UUCP (09/29/87)
In article <4563@ncoast.UUCP> rickers@RUTGERS.EDU@drexel.UUCP (Rick Wargo) writes: > Having been working for a long time under csh and being >accustomed to the commands pushd and popd, I was saddened to find that >these commands were not avaiable under my version of Microport Unix >System V (version 2.2). Sure they are! But you need to set them up yourself as shell functions. I use something like the following (actually mine is much more elaborate, supporting "myx" layer banners etc., and exploits our sh's "builtin" command to allow redefining "cd" as a function): DIRSTACK=... # for pushd, popd, swapd PREVDIR="$HOME" # for backd if [ -z "$HOST" ] then HOST=`uname` export HOST fi backd(){ ch "$PREVDIR"; echo `pwd`; } # Following should be "cd", but you need "builtin" for that. ch(){ PREVDIR="$CWD" if [ $# -lt 1 ] then cd else cd "$1" fi CWD=`pwd` export CWD # exported so interactive subshells can ch $CWD to outwit symbolic links if [ "$CWD" = "$HOME" ] then PS1="$HOST" else PS1="$HOST":`echo "$CWD" | sed -e "s!^$HOME!~!"` fi PS1="$PS1"'$ ' } dirs(){ if [ "$DIRSTACK" != "" ] then echo "$CWD $DIRSTACK" fi } popd(){ set $DIRSTACK if [ $# -ge 2 ] then DIRSTACK="$*" ch $1 set $DIRSTACK # ch clobbered $* shift DIRSTACK="$*" fi set -- } pushd(){ DIRSTACK=$CWD" $DIRSTACK" if [ $# -lt 1 ] then set $HOME fi if ch $1 then echo $DIRSTACK else popd fi set -- } swapd(){ DIRSTACK=$CWD" $DIRSTACK" set $DIRSTACK if [ $# -ge 3 ] then DIRSTACK="$*" ch $2 set $DIRSTACK # ch clobbered $* DIRSTACK="$1" shift 2 DIRSTACK=$DIRSTACK" $*" echo $DIRSTACK else shift DIRSTACK="$*" echo 'swapd: No previous directory' >&2 set -- return 1 fi set -- } readonly backd ch dirs popd pushd swapd if [ "$CWD" ] then ch "$CWD" # outwit symbolic links else ch "`pwd`" fi