home *** CD-ROM | disk | FTP | other *** search
- From decwrl!sun-barr!cs.utexas.edu!uunet!allbery Thu Aug 3 08:51:55 PDT 1989
- Article 1001 of comp.sources.misc:
- Path: decwrl!sun-barr!cs.utexas.edu!uunet!allbery
- From: allbery@uunet.UU.NET (Brandon S. Allbery - comp.sources.misc)
- Newsgroups: comp.sources.misc
- Subject: v07i109: kashe - change directory by menu
- Message-ID: <61771@uunet.UU.NET>
- Date: 29 Jul 89 00:54:46 GMT
- Sender: allbery@uunet.UU.NET
- Reply-To: jack@cs.glasgow.ac.uk
- Lines: 701
- Approved: allbery@uunet.UU.NET (Brandon S. Allbery - comp.sources.misc)
-
- Posting-number: Volume 7, Issue 109
- Submitted-by: jack@cs.glasgow.ac.uk
- Archive-name: kashe
-
- The following stuff saves me a LOT of typing directory names. Needs the
- Korn shell. I've been using it unchanged for months, but it's only been
- tested on Sun 3 machines. Much easier to use than to describe.
-
- RTFM before trying to use it - it helps to have 'lc', and your environment
- needs to be set up right. The details on using it if ksh isn't your login
- shell are there to help proselytize for ksh among users of other shells.
-
- best wishes - jack
-
- #--------------------------------CUT HERE-------------------------------------
- #! /bin/sh
- #
- # This is a shell archive. Save this into a file, edit it
- # and delete all lines above this comment. Then give this
- # file to sh by executing the command "sh file". The files
- # will be extracted into the current directory owned by
- # you with default permissions.
- #
- # The files contained herein are:
- #
- # -rw-r----- 1 jack 9439 Jul 28 19:10 kashe.1
- # -rw-r----- 1 jack 6819 Jul 28 19:24 .kshenv
- #
- echo 'x - kashe.1'
- if test -f kashe.1; then echo 'shar: not overwriting kashe.1'; else
- sed 's/^X//' << '________This_Is_The_END________' > kashe.1
- X.TH KASHE 1 "7 January 1989" "Jack Campin" "KSH(1) FUNCTIONS"
- X
- X.SH NAME
- X
- Xu, d, c, g, p, csort, cdrop, cwipe, csave, cload, cgrep, chelp \- quicker ways
- Xto change directory
- X
- X.SH SYNOPSIS
- X
- X.B u
- X.LP
- X.B d
- X[
- X.I directory
- X]
- X.LP
- X.B c
- X[
- X.I directory
- X]
- X.LP
- X.B g
- X.I number
- X.LP
- X.B p
- X.I pattern
- X.LP
- X.B csort
- X.LP
- X.B cdrop
- X.LP
- X.B cwipe
- X[
- X.I pattern
- X]
- X.LP
- X.B csave
- X[
- X.I file
- X]
- X.LP
- X.B cload
- X[
- X.I file
- X]
- X.LP
- X.B cgrep
- X.I pattern
- X.LP
- X.B chelp
- X
- X.SH DESCRIPTION
- X
- XThis is a collection of Korn shell (
- X.I ksh (1)
- X) functions I wrote after having to
- Xswitch between different directories a lot. I am a pretty hopeless typist,
- Xand even with
- X.I ksh's
- Xcommand-edit-and-retry features, it was getting boring
- Xentering something like
- X
- X.br
- X cd /bakcuppisa/users/jack/oscar/parse
- X
- Xand then having to change the "kc" to "ck".
- X
- XSo these functions give you a zippy menu interface to
- X.I cd.
- XTheir rationale is that most people most of the time only switch between a
- Xrelatively small "working set" of directories; these functions are intended to
- Xmake this set easily accessible. By far the most frequent commands in Unix are
- X.I cd, pwd,
- Xand
- X.I ls;
- Xthese functions improve the interface to all of these. I use them together
- Xwith a prompt line that displays my current directory, hence the "<pathname>\ $
- X" prompts below. The functions fall into two groups; the first maintains a
- Xcache of "interesting" directories, which you might use like this (assuming
- Xthe 3 directories below are in the cache already):
- X
- X.br
- X /pisa/users/jack $ c
- X.br
- X 1) /usr/spool/news/comp/binaries/mac
- X.br
- X 2) /usr/lib/tex
- X.br
- X 3) /backuppisa/users/jack
- X.br
- X 4) New...
- X.br
- X number? 1
- X.br
- X /usr/spool/news/comp/binaries/mac $
- X
- XThose directories might have got there by the following session, starting from
- Xempty:
- X
- X.br
- X /pisa/users/jack $ c
- X.br
- X directory? /usr/spool/news/comp/binaries/mac
- X.br
- X /usr/spool/news/comp/binaries/mac $ cd /usr/lib
- X.br
- X /usr/lib $ c tex
- X.br
- X /usr/lib/tex $ cd /backuppisa/users/jack
- X.br
- X /backuppisa/users/jack $ c
- X.br
- X 1) /usr/spool/news/comp/binaries/mac
- X.br
- X 2) /usr/lib/tex
- X.br
- X 3) New...
- X.br
- X number? 3
- X.br
- X directory? .
- X.br
- X /backuppisa/users/jack $ cd
- X.br
- X /pisa/users/jack $
- X
- XExtra items can be added at any time. Directories can be specified any way
- Xyou like, including tilde aliases. Directories in the cache are represented
- Xby absolute pathname.
- X.PP
- XThus
- X.B c
- Xhas three modes of operation -
- X.I cd
- Xto a cached directory by menu; add a new one to the cache when prompted and
- X.I cd
- Xto it; or add
- X.I directory
- Xto the cache and
- X.I cd
- Xto it, sidestepping the menu. Only valid directories can be added this way.
- XThus you can use it where you would previously have used
- X.I cd,
- Xto load your cache.
- X.PP
- XThere is also a "goto" for use when you know the menu item number you want
- X(typically, just after you've typed the wrong number to
- X.B c
- Xand still have the menu in front of you):
- X
- X.br
- X /pisa/users/jack $ g 2
- X.br
- X /usr/lib/tex $
- X
- XAnd a "goto by pattern" which scans the cache looking for a match:
- X
- X.br
- X /usr/lib/tex $ p mac
- X.br
- X /usr/spool/news/comp/binaries/mac $
- X
- X.B p
- Xwill give you a menu if more than one directory in the cache matches the
- Xpattern. The pattern syntax is as for
- X.I egrep (1).
- XYou will usually be able to find a very short string that uniquely identifies
- Xyour target. I find this more useful than
- X.B g.
- X.PP
- X.B csort
- Xsorts the cache, eliminating duplicated entries.
- X.B cdrop
- Xdeletes directories from it; enter the numbers of the items to delete when
- Xprompted.
- X.B cwipe
- Xwill either clear it completely, or, if given a pattern argument, will just
- Xremove items matching that pattern.
- X.B csave
- Xsaves the cache to a file.
- X.B cload
- Xreloads it, appending the file to your current cache.
- X.PP
- XA less generally useful function in the same group,
- X.B cgrep,
- Xtakes a string and adds to the
- Xcache all accessible directories below your current directory whose pathnames
- Xhave a last component containing that string. It then gives you a menu
- Xlike
- X.B c.
- XIt's intended for finding your way around pieces of software
- Xthat scatter themselves in undocumented places all over the file system but use
- Xrelated names for all those places. You won't use this often, and it's slow
- X(because of the
- X.I ls -R
- Xembedded in it) but it will save you much frustration with
- X.I find
- Xand the like on the rare occasions when you want
- Xit. The string is an
- X.I egrep
- Xpattern. Since
- X.B cgrep
- Xembeds the string in a larger search pattern, some patterns will not work, in
- Xparticular those containing "^" or "$" as unescaped metacharacters, or "/".
- X.B cgrep
- X"" puts the entire tree below the current directory into the cache.
- X.PP
- XYou can ^C out of a menu selection leaving your directory unchanged. The
- Xcache is kept in a shell variable, so changes to it will not persist when
- Xreturning from a subshell unless you
- X.B csave
- Xbefore exiting and then
- X.B cload
- Xin the outer shell.
- X.PP
- XThe second group is a pair of functions that tries to emulate the way you move
- Xaround the file system on the Mac - a function
- X.B u
- Xto go up and
- X.B d
- Xto go down. (Originally inspired by my infuriatingly frequent typing of "cd.."
- Xfor "cd .."). It's usually a lot more convenient to use
- X.B d
- Xin "unknown territory" than to manually list subdirectories and then do
- X.I cd;
- Xfor one thing,
- X.B d
- Xfilters out non-directories from its display. If the target directory has no
- Xsubdirectories,
- X.B d
- Xacts like
- X.I cd.
- XThere are two alternative forms of
- X.B d
- Xprovided depending on whether the fast file lister
- X.I lc,
- X(written by gamiddleton@watmath.uucp and posted to comp.sources.unix in
- X1987) is available; comment out the one you don't want.
- X.PP
- XFinally,
- X.B chelp
- Xprints out a command synopsis.
- X.PP
- XBy using both groups of functions, you can move to any point in the file
- Xsystem without ever typing a directory name, and get back to it from anywhere
- Xwith four or five keystrokes.
- X
- X.SH ENVIRONMENT
- X
- XTo get all these into your environment, put them into a file called, say,
- X.I .kshenv.
- XThe Korn shell finds this file from the variable
- X.B ENV.
- X(
- X.B chelp
- Xuses
- X.B ENV
- Xto find the text it displays.) The file read or written by
- X.B cload
- Xand
- X.B csave
- Xis specified by the filename parameter if one is given; if not, by
- X.B KSHDIRFILE
- Xif that is set; and as a default, the file
- X.I .kshenvdirs
- Xin the home directory (this is OK if you always use the same domain). These
- Xfunctions use a shell variable
- X.B NL
- Xwhich should always contain a newline. This is simply to make the code easier
- Xto read.
- X.PP
- XHow you set up this environment depends on what
- Xyour login shell is.
- X
- X.PP
- X.B Korn shell:
- Xadd the lines
- X
- X.br
- X ENV=.kshenv \ \ export ENV
- X.br
- X KSHDIRFILE=~/.`domainname`-dirs \ \ export KSHDIRFILE
- X
- Xto your
- X.I .profile.
- XTo get the prompt line, also add
- X
- X.br
- X PS1='${PWD} $' \ \ export PS1
- X.PP
- XTo preload the cache at login time, also add to your
- X.I .profile
- Xthe lines
- X
- X.br
- X .\ \ $ENV
- X.br
- X cload
- X
- X.PP
- X.B C shell:
- Xadd the lines
- X
- X.br
- X setenv ENV .kshenv
- X.br
- X setenv KSHDIRFILE \ \ ~/.`domainname`-dirs
- X
- Xto your
- X.I .login
- Xand add
- X
- X.br
- X PS1='${PWD} $' \ \ export PS1
- X
- Xto your
- X.I .kshenv.
- X
- X.PP
- X.B Bourne shell:
- Xadd the lines
- X
- X.br
- X ENV=.kshenv \ \ export ENV
- X.br
- X KSHDIRFILE=~/.`domainname`-dirs \ \ export KSHDIRFILE
- X
- Xto your
- X.I .profile
- Xand add
- X
- X.br
- X PS1='${PWD} $' \ \ export PS1
- X
- Xto your
- X.I .kshenv.
- X
- X.SH FILE FORMAT
- X
- XA cache file is simply a list of full pathnames of directories terminated by
- Xnewlines.
- X
- X.SH DIAGNOSTICS
- X
- XError messages are printed if these functions are called with the wrong number
- Xof parameters, if files can't be read or written, or if commands used by the
- Xfunctions fail. The exit code returned is 1 when a failure or a signal is
- Xdetected, otherwise 0.
- X
- X.SH BUGS
- X
- XIf you have more directories in the cache than will fit on the screen
- X(this might happen after using
- X.B cgrep
- X) you'll have problems seeing them with
- X.B c
- Xor
- X.B cdrop.
- XThere is no way to avoid this as far as I know. The workaround is to
- X.B csave,
- Xedit the file, and then
- X.B cload
- Xagain.
- X.PP
- XYou will sometimes get insane error messages if you enter random
- Xstrings instead of numbers. This is
- X.I ksh's
- Xfault and nothing can be done about it.
- X.PP
- XThese functions don't handle directory names with embedded newlines. Embedded
- Xspaces are OK, though; embedded tabs are invisible in the menus but otherwise
- Xseem to work (and if you embed tabs in directory names you deserve to have
- Xproblems, anyway).
- X.PP
- XIf anyone has bug reports or ideas for improvement, let me know. I suspect
- Xsymbolic links may not be handled quite right, but haven't found a definite
- Xbug there yet. The same ideas can be used for maintaining caches of strings
- Xin general; it would not be trivial to modify these into a general-purpose
- Xstring cache manager but might be worth doing someday.
- X.PP
- XAn undo facility would be easy enough to add; anyone want it?
- X
- X.SH KLUDGE
- X
- XYou need multiple cache files if you log in from more than one server, given
- Xthe inconsistencies in Glasgow's present NFS naming scheme - the same
- Xdirectory has pathname
- X.I /pisa
- Xfrom a login on vanuata and
- X.I /vanuata.pisa
- Xfrom a login on hawaii. Hence the need for the
- X.B KSHDIRFILE
- Xvariable, to say which is the right cache file for the domain you're logged
- Xin to. If you only ever use one domain you can ignore this.
- X
- X.SH SECTARIAN BRAG
- X
- XYou don't have a prayer of adapting these to the antediluvian C or Bourne
- Xshells while still getting useful speed.
- X
- X.SH AUTHOR
- X
- XJack Campin, Glasgow University Computing Science Department, 17 Lilybank
- XGardens, Glasgow G12 8QQ, Scotland (jack@cs.glasgow.ac.uk)
- ________This_Is_The_END________
- if test `wc -c < kashe.1` -ne 9439; then
- echo 'shar: kashe.1 was damaged during transit (should have been 9439 bytes)'
- fi
- fi ; : end of overwriting check
- echo 'x - .kshenv'
- if test -f .kshenv; then echo 'shar: not overwriting .kshenv'; else
- sed 's/^X//' << '________This_Is_The_END________' > .kshenv
- X# ".kshenv" (or rename to whatever ENV is set to).
- X
- X# An assortment of functions for moving around the file
- X# system with fewer keystrokes, using a menu interface.
- X
- X# Jack Campin, 1988
- X
- X## u - up
- X## d [directory] - down [from "directory"]
- X## c [directory] - cd to a cached (or new) directory by menu,
- X## or add "directory" to the cache and cd to it
- X## g number - cd to a cached directory by number rather than menu
- X## p pattern - cd to a cached directory containing "pattern"
- X## csort - sort directory cache, removing duplicate entries
- X## cdrop - remove entries from cache; enter number(s) when prompted
- X## cwipe [pattern] - empty the cache, or remove the items matching "pattern"
- X## csave [file] - write cache to a file, default $KSHDIRFILE or .kshenvdirs
- X## cload [file] - read cache from a file, default $KSHDIRFILE or .kshenvdirs
- X## cgrep pattern - cd to a menu-given directory below the current directory
- X## whose last component contains "pattern", adding all such
- X## directories to the cache
- X## chelp - print this synopsis
- X
- X# These use a cache of newline-separated directories in a variable KSHENVDIRS.
- X
- Xalias -t awk cat egrep lc ls sed sort tr # speeds things up a bit
- X
- XNL="
- X" export NL # newline, used for IFS; variable used for readability
- X
- Xfunction c {
- X typeset ifs="$IFS" ps3="$PS3"
- X trap 'IFS="$ifs" ; PS3="$ps3" ; return 1' 1 2 3 4 5 6 7 8 14 15
- X typeset j i val=1 ; IFS="$NL"
- X if [ $# != 0 ]
- X then j=$1
- X else if [ "$KSHENVDIRS" != "" ]
- X then PS3="number? "
- X select i in $KSHENVDIRS New...
- X do [ "$i" = "New..." ] && break
- X test -n "$i" && cd $i || continue
- X IFS="$ifs" ; PS3="$ps3" ; return 0
- X done
- X fi
- X read j?"directory? "
- X fi
- X if [ "$j" != "" ] # not interrupted while reading
- X then if eval cd $j # makes tilde substitution work
- X then # avoid introducing a duplicate
- X typeset x="$PWD"
- X for i in $KSHENVDIRS
- X do [ "$x" = "$i" ] && x="" && break
- X done
- X KSHENVDIRS="$KSHENVDIRS$x$NL" export KSHENVDIRS
- X val=0
- X fi
- X fi
- X IFS="$ifs" ; PS3="$ps3" ; return $val
- X}
- X
- Xfunction g {
- X typeset ifs="$IFS"
- X trap 'IFS="$ifs" ; return 1' 1 2 3 4 5 6 7 8 14 15
- X IFS="$NL"
- X if [ $# != 1 ]
- X then print "Usage: g <number>" 1>&2
- X else typeset -i n=0 ; typeset j
- X for j in $KSHENVDIRS
- X do (( n = $n + 1 ))
- X [ $n = $1 ] || continue
- X cd $j && IFS="$ifs" && return 0
- X IFS="$ifs" ; return 1
- X done
- X print "g: no directory number $1" 1>&2
- X fi
- X IFS="$ifs" ; return 1
- X}
- X
- Xfunction p {
- X [ $# != 1 ] && print "Usage: p pattern" 1>&2 && return 1
- X [ "$1" = "" ] && print "p: null argument" 1>&2 && return 1
- X typeset ifs="$IFS" ps3=$PS3
- X trap 'IFS="$ifs" ; PS3="$ps3" ; return 1' 1 2 3 4 5 6 7 8 14 15
- X typeset i val=1 dirs="`print "$KSHENVDIRS" | egrep "$1"`" ; IFS="$NL"
- X if [ "$dirs" = "" ]
- X then print "p: no match found for '""$1""'" 1>&2
- X else set $dirs
- X if [ ${#*} = 1 ]
- X then cd $dirs ; val=0
- X else PS3="number? "
- X select i in $dirs
- X do cd $i && val=0 && break
- X done
- X fi
- X fi
- X IFS="$ifs" ; PS3=$ps3
- X return $val
- X}
- X
- Xfunction csort {
- X typeset ifs="$IFS"
- X trap 'IFS=" " ; return 1' 1 2 3 4 5 6 7 8 14 15
- X IFS="$NL"
- X KSHENVDIRS=`print "$KSHENVDIRS" | sort -u`$NL export KSHENVDIRS
- X IFS="$ifs"
- X}
- X
- Xfunction cdrop {
- X [ "$KSHENVDIRS" = "" ] && print "cdrop: nothing to drop" 1>&2 && return 0
- X typeset ifs="$IFS" ps3="$PS3" i
- X trap 'IFS="$ifs" ; PS3="$ps3" ; return 1' 1 2 3 4 5 6 7 8 14 15
- X PS3="numbers to drop? " ; IFS="$NL"
- X select i in $KSHENVDIRS
- X do typeset -i m=0 ; typeset y="$KSHENVDIRS"
- X for m in `print $REPLY | tr ' \011' '\012'` # sidestep IFS
- X do typeset x="" ; typeset j ; typeset -i n=0
- X for j in $y
- X do (( n = $n + 1 ))
- X if [ $m = $n ]
- X then x="$x@$NL" # tombstone value
- X else x="$x$j$NL"
- X fi
- X done
- X y="$x"
- X done
- X typeset tmp=""
- X for i in $y # edit out the tombstones
- X do [ $i != "@" ] && tmp="$tmp$i$NL"
- X done
- X KSHENVDIRS="$tmp" export KSHENVDIRS
- X IFS="$ifs" ; PS3="$ps3" ; break
- X done
- X}
- X
- Xfunction csave {
- X typeset x
- X case $# in
- X 0) if [ "$KSHDIRFILE" != "" ]
- X then x=$KSHDIRFILE
- X else x=~/.kshenvdirs
- X fi ;;
- X 1) x=$1 ;;
- X *) print "Usage: csave [filename]" 1>&2 ; return 1 ;;
- X esac
- X print "$KSHENVDIRS" > $x
- X}
- X
- Xfunction cload {
- X typeset x
- X case $# in
- X 0) if [ "$KSHDIRFILE" != "" ]
- X then x=$KSHDIRFILE
- X else x=~/.kshenvdirs
- X fi ;;
- X 1) x=$1 ;;
- X *) print "Usage: cload [filename]" 1>&2 ; return 1 ;;
- X esac
- X if test -r $x
- X then typeset i here="$PWD" tmp="$KSHENVDIRS" ifs="$IFS"
- X trap 'IFS="$ifs" ; return 1' 1 2 3 4 5 6 7 8 14 15
- X IFS="$NL"
- X for i in `cat $x`
- X do cd "$i" && tmp="$tmp$i$NL"
- X cd "$here"
- X done
- X KSHENVDIRS="$tmp" export KSHENVDIRS
- X else print "cload: $x unreadable" 1>&2 ; IFS="$ifs" ; return 1
- X fi
- X IFS="$ifs"
- X}
- X
- Xfunction cwipe {
- X case $# in
- X 0) KSHENVDIRS="" export KSHENVDIRS ; return 0 ;;
- X 1) typeset ifs="$IFS" ; IFS="$NL"
- X trap 'IFS="$ifs" ; return 1' 1 2 3 4 5 6 7 8 14 15
- X typeset i j y="$KSHENVDIRS" tmp=""
- X for j in `print "$KSHENVDIRS" | egrep $1`
- X do typeset x=""
- X for i in $y
- X do if [ "$i" = "$j" ]
- X then x="$x@$NL"
- X else x="$x$i$NL"
- X fi
- X done
- X y="$x"
- X done
- X for i in $y # edit out tombstones
- X do [ "$i" = "@" ] || tmp="$tmp$i$NL"
- X done
- X KSHENVDIRS="$tmp" export KSHENVDIRS
- X IFS="$ifs" ;;
- X *) print "Usage: cwipe [pattern]" 1>&2 ; return 1 ;;
- X esac
- X}
- X
- Xfunction cgrep {
- X typeset ifs="$IFS" ps3="$PS3"
- X trap 'IFS="$ifs" ; PS3="$ps3" ; return 1' 1 2 3 4 5 6 7 8 14 15
- X if [ $# != 1 ]
- X then print "Usage: cgrep pattern" 1>&2 ; return 1
- X fi
- X typeset x="`ls -R |
- X sed -n '/:$/s/://p' |
- X egrep '(.*/)*.*'"${1}"'.*([~/])*$'`"
- X typeset i y="" here="$PWD" ; PS3="number? " IFS="$NL"
- X for i in $x
- X do cd $i && y="$y$PWD$NL" && cd $here
- X done
- X KSHENVDIRS="$KSHENVDIRS$y" export KSHENVDIRS
- X select i in $KSHENVDIRS
- X do cd $i && break
- X done
- X IFS="$ifs" ; PS3=$ps3
- X}
- X
- Xfunction u {
- X cd ..
- X}
- X
- Xfunction d {
- X typeset ifs="$IFS" ps3="$PS3" tmp="$PWD" val=1 i
- X trap 'IFS="$ifs" ; PS3="$ps3" ; cd "$tmp" ; return 1' 1 2 3 4 5 6 7 8 14 15
- X case $# in
- X 0) ;;
- X 1) cd "$1" || return 1 ;; # test if target is a directory
- X *) print "Usage: d [directory]" 1>&2 ; return 1 ;;
- X esac
- X PS3="number? " ; IFS="$NL"
- X select i in `lc -d1`
- X# slower alternative if "lc" is not available
- X# the gross pattern is (empirically) faster than the obvious one
- X# select i in `ls -al |
- X# sed -n '/^d.*/{
- X# s/[^ ]*[ ]*//
- X# s/[^ ]*[ ]*//
- X# s/[^ ]*[ ]*//
- X# s/[^ ]*[ ]*//
- X# s/[^ ]*[ ]*//
- X# s/[^ ]*[ ]*//
- X# s/[^ ]*[ ]*//
- X# s/^\.*$//
- X# p
- X# }'`
- X do [ "$i" != "" ] && cd $i && val=0 && break
- X done
- X IFS="$ifs" ; PS3=$ps3 ; return $val
- X}
- X
- Xfunction chelp {
- X sed -n '/^##/s/^##//p' < $ENV
- X}
- ________This_Is_The_END________
- if test `wc -c < .kshenv` -ne 6819; then
- echo 'shar: .kshenv was damaged during transit (should have been 6819 bytes)'
- fi
- fi ; : end of overwriting check
- exit 0
-
-
-