df@nud.UUCP (03/26/87)
With the recent discussion on Korn Shell aliases for cd, I thought I'd
post my own cd alias. It maintains a directory history in least
recently used (LRU) order. You can print the directory history
and cd to a recent directory via number or pattern matching.
I much prefer it to pushd/popd since the history occurs automatically
through the cd command.
Optionally, all your shells can share the same directory via a history
file, though there is a slight performance hit for this particular feature.
Here is an example of its use.
==============================================================
$ pwd
/usr/df
$ cd /
$ cd /bin
$ cd /usr/bin
$ cd -l # "cd -l" lists directory history
3 /usr/df
2 /
1 /bin
0 /usr/bin
$ cd -3 # "cd -3" cd's to third most recent directory
/usr/df
$ cd -l
3 /
2 /bin
1 /usr/bin
0 /usr/df
$ cd -bin # "cd -foo" cd's to most recent directory name
/usr/bin # containing the string "foo"
$ cd -l
3 /
2 /bin
1 /usr/df
0 /usr/bin
$
==============================================================
From $HOME/.profile:
==============================================================
export CDHISTFILE CDHIST PWD
CDHIST=$HOME
# CDHISTFILE=$HOME/.cdhistory # set this for directory history file.
CDHISTFILE=
ENV=$HOME/.kshrc
==============================================================
From $HOME/.kshrc (Korn shell ENV file):
==============================================================
alias set_prompt="PS1='$ '" # of course, my real prompt is different.
alias cd='. $HOME/.functions; _cd'
alias md='. $HOME/.functions; md'
==============================================================
From $HOME/.functions (Where my function definitions reside):
==============================================================
alias cd=_cd
function _cd
{
typeset -i cdlen i
typeset t
if [ $# -eq 0 ]
then
set -- $HOME
fi
if [ "$CDHISTFILE" -a -r "$CDHISTFILE" ] # if directory history exists
then
typeset CDHIST
i=-1
while read -r t # read directory history file
do
CDHIST[i=i+1]=$t
done <$CDHISTFILE
fi
if [ "${CDHIST[0]}" != "$PWD" -a "$PWD" != "" ]
then
_cdins # insert $PWD into cd history
fi
cdlen=${#CDHIST[*]} # number of elements in history
case "$@" in
-) # cd to new dir
if [ "$OLDPWD" = "" ] && ((cdlen>1))
then
print ${CDHIST[1]}
'cd' ${CDHIST[1]}
else
'cd' $@
fi
;;
-l) # print directory list
typeset -R3 num
((i=cdlen))
while (((i=i-1)>=0))
do
num=$i
print "$num ${CDHIST[i]}"
done
return
;;
-[0-9]|-[0-9][0-9]) # cd to dir in list
if (((i=${1#-})<cdlen))
then
print ${CDHIST[i]}
'cd' ${CDHIST[i]}
else
'cd' $@
fi
;;
-*) # cd to matched dir in list
t=${1#-}
i=1
while ((i<cdlen))
do
case ${CDHIST[i]} in
*$t*)
print ${CDHIST[i]}
'cd' ${CDHIST[i]}
break
;;
esac
((i=i+1))
done
if ((i>=cdlen))
then
'cd' $@
fi
;;
*) # cd to new dir
'cd' $@
;;
esac
_cdins # insert $PWD into cd history
if [ "$CDHISTFILE" ]
then
cdlen=${#CDHIST[*]} # number of elements in history
i=0
while ((i<cdlen))
do
print -r ${CDHIST[i]} # update directory history
((i=i+1))
done >$CDHISTFILE
fi
set_prompt
}
function _cdins # insert $PWD into cd history
{ # meant to be called only by _cd
typeset -i i
((i=0))
while ((i<${#CDHIST[*]})) # see if dir is already in list
do
if [ "${CDHIST[$i]}" = "$PWD" ]
then
break
fi
((i=i+1))
done
if ((i>22)) # limit max size of list
then
i=22
fi
while (((i=i-1)>=0)) # bump old dirs in list
do
CDHIST[i+1]=${CDHIST[i]}
done
CDHIST[0]=$PWD # insert new directory in list
}
==============================================================
Cd is a sizable alias, but actually executes quite quickly.
I hope it is useful to someone else; I've been using it for several months.
-Dale
--
seismo!noao!mcdsun!nud!df 602/438-5739 ihnp4!mot!nud!dfajs@hpfcdt.UUCP (03/31/87)
# Here's yet another way to remember and re-use old directories. This one
# remembers everywhere you've been during a login session, and lets you
# pick from a sorted menu ("mcd") or list a Pareto-style summary ("lcd").
# I've found it only occasionally useful, but fast and painless. If
# nothing else you might find these functions educational.
# This is a shell archive. Remove anything before this line,
# then unpack it by saving it in a file and typing "sh file".
#
# Wrapped by ajs at hpfcdt on Mon Mar 30 16:49:13 1987
#
# This archive contains:
# ksh.cd
#
# Error checking via wc(1) will be performed.
echo x - ksh.cd
cat >ksh.cd <<'@EOF'
# ksh functions to remember directory changes and let you pick (from a menu)
# directories to which to cd.
# Usage:
# Read this file with ". file", or put it in your .profile or .kshrc. Then
# cd as usual. Say "mcd" to get a menu of places you've been, to pick from.
# Say "lcd" to list your cd history, most-visited first.
# Warning: Some things don't work right due to ksh deficiencies:
#
# - The typeset -x below is intended to cause DIRHIST[] to be exported to
# subshells. But ksh only exports the first element of any array (and
# that's clobbered when mycd() is declared). Too bad.
#
# - For some reason, the quotes around "$@" in the select in mcd() cause menu
# item 1 to be munged sometimes, reason unknown. Remove the quotes if this
# is a problem and you never visit a directory with a blank or tab in its
# name.
# INITIALIZE:
#
# Note that during .profile, $PWD is not set yet.
if [ -z "${DIRHIST:-}" ] # not already set.
then
DIRHIST="${PWD:-$HOME}"
fi
typeset -x DIRHIST
typeset -x DIRCOUNT=1 # just for fun, how often before.
# FUNCTION mycd(): DO A CD AND REMEMBER ALL DIRS VISITED:
alias cd=mycd # alias > built-in > function.
mycd()
{
typeset -i dirat=0 # current saved dir index; local var.
typeset -i dirs=${#DIRHIST[*]}
# number of entries in "global" array.
# Do the change:
if 'cd' "${@-$HOME}" # call shell built-in.
then # only if it succeeded.
# See if new directory name (note, full name) is already known:
while [ $dirat -lt $dirs ]
do
if [ "${DIRHIST[$dirat]}" = "$PWD" ]
then
break
fi
(( dirat=dirat + 1 ))
done
# Save new, or tell count for old:
if [ $dirat -ge $dirs ]
then
DIRHIST[$dirat]="$PWD"
DIRCOUNT[$dirat]=1
echo "(first time here)"
else
echo "(previous: ${DIRCOUNT[$dirat]})"
(( DIRCOUNT[$dirat]=${DIRCOUNT[$dirat]} + 1 ))
fi
fi
} # mycd().
# FUNCTION mcd(): DO A CD CHOOSING FROM A MENU:
mcd()
{
set -- "${DIRHIST[@]}" # copy to positional parameters.
set -s # sort them. (remove if not desired)
select dir in "$@" # choose one.
do
if [ "${dir-}" ] # valid response.
then
echo "+ cd $dir"
mycd "$dir" # use function for side-effects.
else
echo "cd: no change"
fi
break
done
} # mcd().
# FUNCTION lcd(): LIST CD HISTORY:
lcd()
{
typeset -i dirat=0 # current saved dir index; local var.
typeset -i dirs=${#DIRHIST[*]} # entries in "global" array.
while [ $dirat -lt $dirs ]
do
echo "${DIRCOUNT[$dirat]}\t${DIRHIST[$dirat]}"
(( dirat=dirat + 1 ))
done | sort +0nr -1
} # lcd().
@EOF
if test "`wc -lwc <ksh.cd`" != ' 114 444 2687'
then
echo ERROR: wc results of ksh.cd are `wc -lwc <ksh.cd` should be 114 444 2687
fi
chmod 444 ksh.cd
exit 0