Subject: Re: ksh, PS1 and $?
To: Denis Lagno <dlagno@rambler.ru>
From: Greg A. Woods <woods@weird.com>
List: netbsd-users
Date: 04/28/2005 03:26:17
[ On Thursday, April 28, 2005 at 00:44:23 (+0000), Frederick Bruckman wrote: ]
> Subject: Re: ksh, PS1 and $?
>
> This is all very silly, but how about this...?
> 
>   export PS1='$(_status=$?; echo [$(id -nu)@$(hostname -s) \($(tty | sed s/\\/dev\\///)\) $(date "+%H:%M:%S") $(pwd) $_status$; exit $_status) '

Most of that is static data that doesn't change (hostname, tty, etc.),
so accessing it with command expansions in every prompt echo is more
than just very silly.....  :-)

And the pwd is available as $PWD

Expanding the date can be done with arithmetic and arrays:

####################

# initialize SECONDS to the number of seconds since the last
# local wall-clock midnight hour
#
alias set_secs_to_midnight='SECONDS="$(date '"'"'+3600*%H+60*%M+%S'"'"')"'
set_secs_to_midnight

# We wouldn't normally have to reset $SECONDS since our calculations
# for hours and minutes only need to find the remainder values for the
# seconds/unit since any epoch.  However wall-clock time will shift
# when daylight savings time transitions happen.  Resetting $SECONDS
# once per hour is probably overkill but will do the job -- it only
# really needs to be done once a day at most in order to catch any
# number of daylight savings time transitions.
#
# The first one in the loop should only sleep to the top of the hour,
# but calculating that would really be overkill!
#
# The extra sub-shell is to prevent the main shell from tracking the
# kill job...
#
#trap 'SECONDS="$(date '+3600*%H+60*%M+%S')"; ( { sleep 3600; kill -14 $$; } & )' 14
#
# start the cycle
#
#kill -14 $$
#
# instead of that just remember to run set_secs_to_midnight after every
# transition!

# expressions to calculate hours, minutes, and seconds since midnight
# given the number of $SECONDS (we ignore the number of days that may
# have passed since that midnight hour)
#
_hh="(SECONDS/3600)%24"
_mm="(SECONDS/60)%60"
_ss="(SECONDS)%60"

# We'll be wanting zero-filled 2-digit expansion for our hours and
# minutes variables
#
typeset -Z2 _h _m

# a magic expression that evaluates the above expressions to set the two
# variables we've configured specially above, and then expands those two
# variables in a standard "HH:MM" 24-hr format to show the current time.
#
_time='${_x[(_m=_mm)==(_h=_hh)]}$_h:$_m'

PS1="$_time $PS1"

####################

The above results in something like the following:

	01:49 [1969] $ echo $PS1
	${_x[(_m=_mm)==(_h=_hh)]}$_h:$_m [!] $
	02:10 [1970] $   

(note I didn't invent this trick -- but I don't remember where I learned
it from either!  :-)

On any windowing system I put the other stuff in the window title where
it doesn't interfere with command-line editing, and I have a trap that
prints any non-zero status codes:

	03:21 [1982] $ trap
	trap -- '. $HOME/.kshlogout ; exit $?' EXIT
	trap -- 'trap 1 2 3 15; setban' HUP
	trap -- 'trap 1 2 3 15; setban' INT
	trap -- 'trap 1 2 3 15; setban' QUIT
	trap -- 'trap 1 2 3 15; setban' TERM
	trap -- '
	        rc=$?;
	        if ((ERRNO > 0)); then
	                EMSG="; errno: $ERRNO"
	        else
	                EMSG=""
	        fi;
	        print "${0#-}: exit code: $rc$EMSG"
	' ERR

Learn all about these and many other magic tricks from the files in here:

	ftp://ftp.weird.com/pub/local/dotfiles.tar.gz


-- 
						Greg A. Woods

H:+1 416 218-0098  W:+1 416 489-5852 x122  VE3TCP  RoboHack <woods@robohack.ca>
Planix, Inc. <woods@planix.com>          Secrets of the Weird <woods@weird.com>