rwl@uvacs.CS.VIRGINIA.EDU (Ray Lubinsky) (07/10/88)
I promised to post these a while ago and the recent set of postings about ksh functions reminded me. My apologies; this is a fairly large posting, but I do get tired of people going on about how ksh is not quite able to match some of the C-shell's tricks. Analogs to C-shell's "pushd", "popd", and "dirs" functions are included plus the function "roll" which is easier than "pushd +count" for rolling the directory stack (though that too is implemented). "Cd" is aliased to the function "chdir" which handles the directory stack and prints it out after changing directory. Naturally, you can modify "chdir" so that it also does an ls(1), prints the date, or plays rogue every time you change directories. Enjoy! Feel free to point out bugs &c. -------------------------------- CUT HERE ------------------------------------ # # Directory stack support for ksh. # # Author: Ray Lubinsky, rwl@uvacs.cs.virginia.edu # Site: Computer Science Department, University of Virginia # # This file contains functions and aliases which implement a # directory stack for the Korn shell very similar to that built # into the C-shell. # alias cd='chdir' # THIS IS NOT OPTIONAL alias pop='popd' # optional alias push='pushd' # optional # # pushd -- push directory stack # # Usage: pushd [<directory> | +<position>] # # You may either change directories by pushing a new directory or # by reordering the directory stack. The directory on the top of # the stack (first token in the $DIRSTACK variable) becomes the # current working directory. Giving no arguments is the same as # "pushd +1"; see function roll() defined below. # function pushd { if [ $# -gt 1 ] ; then echo 'pushd: Too many arguments.' return 1 fi integer OK=1 FLIP=0 POS=0 case $1 in '') FLIP=1 ;; +*) POS=${1#+} if [ 0 -eq $POS -o $POS -ne "$POS" ] ; then echo 'pushd: Bad directory.' return 1 fi ;; *) typeset +x NEWDIR=$1 esac set -- ${DIRSTACK:=$PWD} if [ $FLIP -ne 0 ] ; then if [ $# -lt 2 ] ; then echo 'pushd: No other directory.' return 1 else typeset +x SECOND=$1 FIRST=$2 shift 2 set -- $FIRST $SECOND $* fi elif [ $POS -eq 0 ] ; then set -- $NEWDIR $DIRSTACK elif [ $POS -ge $# ] ; then echo 'pushd: Directory stack not that deep.' return 1 else typeset +x STACK='' integer i=0 while [ $i -lt $POS ] do STACK="$STACK $1" shift let i=i+1 done set -- $* $STACK fi 'cd' $1 1>/dev/null OK=$? shift if [ $OK -eq 0 ] ; then DIRSTACK="$PWD $*" dirs else shift DIRSTACK=$* fi return $OK } # # popd -- pop directory stack # # Usage: popd [+<position>] # # Pop a directory off the directory stack. With no arguments this # pops the top (current working) directory and changes directory to # the new top-of-stack directory. With the position argument, the # directory at the given ordinal position from the top of the stack # is removed from $DIRSTACK; this never results in a change of current # working directory. # function popd { if [ $# -gt 1 ] ; then echo 'popd: Too many arguments.' return 1 fi integer OK=0 POS=0 case $1 in '') OK=1 ;; +*) POS=${1#+} if [ 0 -lt $POS -a $POS -eq "$POS" ] ; then OK=1 fi esac if [ $OK -eq 0 ] ; then echo 'popd: Bad directory.' return 1 fi set -- $DIRSTACK if [ $# -le 1 ] ; then echo 'popd: Directory stack empty.' return 1 elif [ $POS -eq 0 ] ; then shift elif [ $POS -ge $# ] ; then echo 'popd: Directory stack not that deep.' return 1 else typeset +x STACK='' integer i=0 while [ $i -ne $POS ] do STACK="$STACK $1" shift let i=i+1 done shift set -- $STACK $* fi 'cd' $1 1>/dev/null OK=$? if [ $OK -eq 0 ] ; then DIRSTACK=$* dirs fi return $OK } # # chdir -- wrapper function for cd which adjusts DIRSTACK # # Usage: chdir [<directory>] # # This function is used as the change-directory function. To have cd # work right, you must alias cd to chdir. Note that instances of cd # in this function are quoted so that you get the real builtin rather # than the alias. # function chdir { typeset +x DIR case $# in 0) DIR=$HOME ;; 1) DIR=$1 ;; 2) DIR=`echo $PWD | /bin/sed "s$1$2"` ;; *) echo 'cd: too many arguments' ; return 1 esac if 'cd' $DIR 1>/dev/null ; then set -- $DIRSTACK DIRSTACK=$PWD if [ $# -gt 1 ] ; then shift DIRSTACK="$DIRSTACK $*" fi dirs else return 1 fi } # # roll -- roll directory stack # # Usage: roll [<count>] # # I use this function when I want to roll the directory stack rather # than using "pushd +<count>" to avoid typing extra characters. # With no arguments, the function is equivalent to "pushd +1". # function roll { typeset +x ROLL case $# in 0) ROLL=1 ;; 1) case $1 in [0-9]*) ROLL=$1 ;; *) echo 'roll: number expected' ; return 1 esac ;; *) echo 'roll: too many arguments' ; return 1 ;; esac pushd +$ROLL } # # dirs -- print directory stack # # Usage: dirs # # Like the C-shell builtin, this prints the directory stack. # function dirs { if [ "$HOME" = '/' ] ; then echo ${DIRSTACK:=$PWD} else echo ${DIRSTACK:=$PWD} | /bin/sed "s$HOME~g" fi } -------------------------------- CUT HERE ------------------------------------ -- | Ray Lubinsky, UUCP: ...!uunet!virginia!uvacs!rwl | | Department of BITNET: rwl8y@virginia | | Computer Science, CSNET: rwl@cs.virginia.edu -OR- | | University of Virginia rwl%uvacs@uvaarpa.virginia.edu |