home *** CD-ROM | disk | FTP | other *** search
- Newsgroups: comp.unix.shell
- Path: sparky!uunet!wupost!zaphod.mps.ohio-state.edu!rpi!newsserver.pixel.kodak.com!laidbak!tellab5!nucsrl!ddsw1!dattier
- From: dattier@ddsw1.mcs.com (David W. Tamkin)
- Subject: Ron Heiby's ksh pushd and popd
- Message-ID: <1992Jul24.191246.11410@ddsw1.mcs.com>
- Organization: Contributor Account at ddsw1, Chicago, Illinois 60657
- Date: Fri, 24 Jul 1992 19:12:46 GMT
- X-Disclaimer: Material posted in this article is the sole responsibility of
- the poster and does not represent MCSNet or the system owners.
- Lines: 305
-
- The subject of pushd and popd in ksh came up in this newsgroup a few weeks
- back, and I just discovered the following old post from Ron Heiby in my
- files. Naturally, I didn't remember it beforehand nor come across it until
- I'd written my own routines. Oh well. Mr. Heiby's post follows.
-
- [The rest of this article is by Ron Heiby; please fix your attributions
- if you follow up to it. --DWT]
- ___________
-
- If my records are complete, I posted this article in December of
- 1986, while working for AT&T. Then, with modifications in December of
- 1987, while working for Motorola. Since then, Ksh-88 has been
- released and I've seen quite a few articles asking to do lots of stuff
- with the prompt string. So, here it is again, modified for Ksh-88 a
- bit and enhanced in some other minor ways. If you are still using an
- older version of Ksh, UPGRADE! Enjoy!
-
- A while ago [from the perspective of someone writing in December of
- 1986], there were several messages posted to Usenet which showed ways
- to include various information into a Korn Shell PS1 prompt. I
- thought that a number of these were real clever and incorporated them
- into my own environment.
-
- Now that Motorola Microcomputer Division [now the Motorola Computer
- Group] is selling the Korn Shell for our Delta Series of 68020-based
- systems, I thought I'd share this generally.
-
- Relatively little here is my own invention, but I can no longer say
- who had every idea. I did put a lot of work into integrating
- everything together so that it would all work in a coordinated
- fashion. The time stamp stuff is from Korn. The "autoload" stuff
- [originally used] for functions (pshd, popd, etc.) as well as the
- original versions of those functions is from a Usenet article by Avi
- E. Gross in 10/84. [This has since been absorbed in slightly
- different form into standard Ksh-88.] I have made some readability
- and efficiency enhancements to the originals, as well as merging them
- into the rest of the stuff here. I pulled out the large blocks of
- comments in Avi's original to improve the performance in my running
- copy and keep the original intact elsewhere so I can figure out what's
- going on. As to the prompt-resetting code, I know there were at least
- three different people (plus me) who contributed to what is merged
- together here, but I lost the original Usenet articles. Thanks,
- whoever you are.
-
- I've tried to put this is into a form that you can easily install into
- your own environment. I mostly did it to see if I could. Since then,
- it has proved useful enough for me to keep it as my normal
- environment.
-
- One could easily turn up one's nose at all this, if one really likes the "$ "
- prompt, as this is about as far from that as you can get. The normal prompt
- when logged in and in your home directory is: host: hh:mm:ss [~]
- nn>
- After "cd /usr/src/cmd/vi", it is: host: hh:mm:ss [src/cmd/vi]
- nn>
- After "pshd /usr", it is: host: hh:mm:ss 1: [/usr]
- nn>
- After "popd", it is back to: host: hh:mm:ss [src/cmd/vi]
- nn>
- After invoking a sub-shell (ksh): host: hh:mm:ss [src/cmd/vi]
- nn>>
-
- The "host" is the output of the "uname" command. I added the host
- name to the prompt to make it more obvious to whom I was "talking" in
- the face of "cu" and "rlogin" and windowing terminals. The "nn" is
- the ksh history number. hh:mm:ss is the time. As you can see, up to
- the last three directories in your current directory are included. If
- you are in a subdirectory of your home directory, your home directory
- path counts as a single directory and is represented with a tilde (~).
- If you are using Shell Layers (shl), the layer name "foo" or number
- "(n)" is displayed as part of the prompt, too. If the uid of the user
- is 0 (root), then a pound sign (#) is used instead of a greater-than
- (>) to indicate nesting of sub-shells. The prompt was split into two
- lines because the escape sequences to highlight a non-zero return code
- get counted as printable characters and so fewer characters from the
- command you are entering are visible in the line.
-
- Good luck trying to change any of it without breaking something else.
- I am currently running ksh "Version 11/16/88e".
-
- Even if you don't use this, it makes an interesting exercise to figure
- out how everything works. After doing so, you'll have a very good
- understanding of ksh programming.
-
- Ron.
-
- --------- This goes in your .profile --------
- # environment for fancy prompt
- export PSSHL PS1="!$ " FPATH=~/ksh
-
- -------- This goes in your $ENV file ---------
- # All this good stuff needed for interactive shells only.
- # Guard it with appropriate tests for better effeciency of startup.
- # Here's a good example of this:
- # case "$-" in
- # *c*) # Stuff for -c, command line shells goes here.
- # :
- # ;;
- # *) # Stuff for for non -c, (interactive) shells.
- # :
- # ;;
- # esac
- #
- # Set prompt string portion for Shell Layers layer.
- TTY=$(tty)
- if [ "$TTY" != "${TTY#*sxt}" -a "${SHDEPTH:-}" = ">" ]
- then
- export PSSHL=$PS1
- fi
- unset TTY
- #
- # Set System name string for fancy prompt
- UNAME=$(uname)
- #
- # Set standout strings for fancy prompt
- : ${SMSO:=$(tput smso)} ${RMSO:=$(tput rmso)}
- #
- # Set up for time stamping
- typeset -RZ2 _x1 _x2 _x3
- let SECONDS=$(date '+3600*%H+60*%M+%S')
- TIME='"${_d[(_x1=(SECONDS/3600)%24)==(_x2=(SECONDS/60)%60)==(_x3=SECONDS%60)]}$_x1:$_x2:$_x3"'
- #
- # Define the replacement for the "cd" builtin
- function ch {
- if cd ${*:-''}
- then
- resetps1
- else
- return 1
- fi
- }
- alias cd=ch # make it easy to use
-
- function resetps1 {
- typeset _dir=$PWD
- typeset _dirt=${_dir#$HOME} # directory tail
- if [ "${_dirt}" != "${_dir}" ]
- then
- _dir="~${_dirt}"
- fi
- typeset front=${_dir%/*/*/*}
- : ${front:=x}
- case ${pushlevel:-0} in
- 0) PS1="${UNAME}: ${TIME} ${PSSHL:-}${SMSO:-}\${?#0}${RMSO:-}[${_dir#$front/}]
- !$SHDEPTH ";;
- *) PS1="${UNAME}: ${TIME} $pushlevel: ${PSSHL:-}${SMSO:-}\${?#0}${RMSO:-}[${_dir#$front/}]
- !$SHDEPTH ";;
- esac
- }
- # Functions related to push and pop routines
- alias dirs='echo "\t0: $PWD"' \
- popd='echo "You have never pushed any levels.\nYou remain at $PWD."'
- #
- # Check for uid 0 (root)
- id=$(id)
- id=${id#uid=}
- id=${id%%\(*}
- if [ id -eq 0 ]
- then
- export SHDEPTH=${SHDEPTH:-}'#'
- else
- export SHDEPTH=${SHDEPTH:-}'>'
- fi
- # Set special colors
- case $TERM in
- mskermc)
- case $id in
- 0) color=37 ;;
- 501) color=31 ;;
- *) color=35 ;;
- esac
- SMSO="[41;33m" RMSO="[44;${color}m[1m"
- unset color
- ;;
- tm229|tm229g)
- case $id in
- 0) color=33 ;;
- 501) color=37 ;;
- *) color=35 ;;
- esac
- SMSO="[41;33m" RMSO="[40;${color}m[1m"
- unset color
- ;;
- *)
- ;;
- esac
- unset id
- resetps1
-
- -------- This is ~/ksh/pshd, linked to ~/ksh/pshpwd and ~/ksh/poppwd ---------
- unalias popd dirs
- integer pushlevel=0
-
- function pshd
- {
- dirsave[pushlevel]="$PWD" # save the name of the current dir
- promptsave[pushlevel]="$PS1" # save the current prompt
- if [ pushlevel = 0 ]
- then
- pushprompt="$PS1"
- fi
- ch ${1:-$HOME} 2> /dev/null
- case $? in
- 0) # "cd" succeeded.
- let pushlevel=pushlevel+1
- pwd # show the current directory
- : ${2:+`ls -Fx $3 $4 $5 $6 $7 $8 $9 >/dev/tty`}
- resetps1
- ;;
- *) # "cd" failed
- print "Can't change to $1, aborting"
- return 1
- ;;
- esac
- } # END of pshd
-
- function popd
- {
- integer levels=${1:-1}
-
- if (( pushlevel-levels>=0 ))
- then
- let pushlevel=pushlevel-levels
- else
- print "Can't pop that many levels. Your choices were:"
- dirs
- print "You are being returned to your original level"
- let pushlevel=0
- fi
-
- ch ${dirsave[$pushlevel]}
- pwd # show the user where they are.
- : ${2:+`ls -Fx $3 $4 $5 $6 $7 $8 $9 >/dev/tty`}
- PS1="${promptsave[$pushlevel]}"
- }
-
- function dirs
- {
- integer level=$pushlevel
- integer lowest=$level-${1:-$level}
- if [ lowest -lt 0 ]
- then
- lowest=0
- fi
- print " $level: $PWD"
- while [ level -gt lowest ]
- do
- let level=level-1
- print " $level: ${dirsave[$level]}"
- done
- unset level lowest
- }
-
- function pshpwd
- {
- print $PWD "${@:-}" >~/.current-pwd
- }
-
- function poppwd
- {
- print $(<~/.current-pwd)
- }
-
- ---- start of pshd family documentation ----
- # In brief, this routine is called in the form of:
- # . ~/ksh/psh-pop.ksh name arg1 arg2 arg3 ...
- # and has to do the following:
- # - Unalias all five related alias names.
- # - Declare all five function bodies using those names.
- # - Run the function that invoked this file, using the provided
- # arguments.
-
- # The first time one of these aliases is used, it needs to be "loaded". From
- # then on, each one represents a loaded function, and runs smoothly. The
- # advantages are that your .env is about a hundred lines smaller, and these
- # functions are only defined when used.
-
- # The first three routines are used to maintain and examine a directory stack
- # of traversals through the file system. They are:
- # pshd [directory] [ls-indicator] [ls-arg] [ls-arg] [ls-arg]
- # popd [levels] [ls-indicator] [ls-arg] [ls-arg] [ls-arg]
- # dirs [levels]
-
- # These are different than other versions of pshd that have been posted to
- # the net. Both pshd and popd have an optional first argument that tells
- # which directory to go to, or how many levels to backtrack. If a second
- # argument is specified (any string will do) then an "ls -C" is done after
- # the action is completed. Any additional arguments are passed to ls. For
- # example, "pshd /usr/spool/uucp l -l -a -t" will change the directory to
- # /usr/spool/uucp and then do an "ls -C -l -a -t" to show full descriptions
- # of all files in that directory in the orer that they were last changed.
- # The "-C" argument is used to force our version of ls to columnate the
- # output (even if it is going into a pipeline).
-
- # The next two routines are used to share information about the current
- # directory # between two windows on a DMD/BLIT or just to save the value
- # for later. Only one value is currently supported. They are:
- # pshpwd [additional text]
- # poppwd
- # Poppwd is often used in constructs like "cp *.c `poppwd`"
-
- Ron Heiby mcdchg!heiby Moderator: mod.newprod & mod.os.unix
-
- Ron Heiby, heiby@chg.mcd.mot.com Moderator: comp.newprod
- "Wrong is wrong, even when it helps you." Popeye
-