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 temp
allbery@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