#!/bin/sh # Topish version 1.00. Copyright 1999-2001. All rights reserved. # # This program provides an alternative to the widely available top program # but is written in standard Bourne Shell script and does not require # special permissions to run or for installation. # # Note that this version will run on Solaris only. # # Usage: # # topish [-s time] [-o field] [-u user] [-m match] # # Options: # # -s time specify the time between updates in seconds. Default is 5 # seconds. # -o field sort by the specified field (one of cpu, pid, res, size, th, # time). Default is to sort by CPU. # -u user restrict output to just processes belonging to the specified # user. Use + to indicate all users (default). # -m match restrict output to just those lines that match the given regular # expression. # # As far as possible this program has been designed to look and run like top # although there are slight differences in layout and behaviour. Like top # the screen will update automatically. Window resizing is accomodated and # options may be changed when the program is running by pressing the # appropriate command letter. The commands are: # # ^L redraw screen # h or ? help # k kill processes; send a signal to a list of processes # m restrict display to lines matching a regular expression # o specify sort order (cpu, pid, res, size, th, time) # q quit # s change number of seconds between updates # # The display may be sorted in the following ways: # # cpu Highest CPU usage first. # pid Lowest PID first # res Highest resident size first (paged in) # size Highest total size first (total image size) # th Highest number of threads first # time Longest run time first. # # Notable differences from top 3.5beta9: # # * topish displays system up time instead of last pid. # * topish does not distinguish jobs on CPU from jobs running, nor does it # display the total number of processes on the system. # * topish uses a 3 line header and 1 line footer as opposed to top's 6 # line header. # * topish runs lots of processes each updated, top only ever has one # process (this probably implies that topish's CPU load is higher). # * topish does not display processes' instantaneous priority (like top # it displays the niceness). This is to free up horizontal space. # * topish displays command line arguments, top merely displays the command. # * topish displays only the amounts of swap and RAM free, not the total # amounts available or in-use. # * topish can sort by number threads and pid, top can't. # * top can renice processes, topish can't. # * top can run for a limited number of displays, topish can't. # * top can ignore idle and/or system processes, topish can't. # * top can have the number of processes it displays limited, topish # always fills the display. # * top can run with 0 seconds between updates, topish has a minimum of # one second. # # Note that top has advanced somewhat since version 3.5beta9, that's just # the version I had handy for comparison. # # Known Bugs: # # It doesn't cope very will with being suspended and may leave the terminal # driver in a funny state. # # Some code is too Solaris specific. # # Porting: # # It's probably not impossible to port this program to other variants of # Unix. It's already intelligent enough to work out which version of # stty and echo it's using. In principle it could auto-adapt to other # features of the system. # # Version history: # # 0.01 sms Created. Posted on Usenet. # 0.02 sms Added sort options pid and th. Added match option. Posted on Usenet. # 1.00 sms Added documentation, placed on web site www.finesse.demon.co.uk. # # Authors: # # sms: Steven Singer, steven@finesse.demon.co.uk. # # Copying restrictions: # # This program may be copied freely provided the author(s) are clearly # identified. This means that if you make a change then at the very least you # should add a line to the version history with your initials stating what # changes you made, and a line to the Authors section giving your full name and # e-mail address. # # Warranty: # # This program is provided "AS IS" with no guarantee of suitability for any # purpose. No warranty is given. TTY=`tty` || { echo 'topish can only be run when connected to a terminal.' 1>&2 exit 1 } if stty > /dev/null 2>&1 ; then STTY=stty else STTY=sysv_stty fi if test `echo "foo\c" | wc -c` -ne 3 ; then ECHONONL=echon else ECHONONL=echoc fi TERMINAL=`stty -g` ERROR= PAGESIZE=`pagesize` echon() { echo -n "$@" } echoc() { echo "$@\c" } sysv_stty() { stty $@ 2>&1 > $TTY } resetandexit() { $STTY $TERMINAL exit 0 } getsize() { eval `$STTY -a | egrep '(rows|columns)' | \ sed 's/\([^=]*\) = \([0-9]*\);*/\1=\2;/g'` procs=`expr $rows - 4` } displayusage() { echo 'Usage: topish [-s time] [-o field] [-u user] [-m match]' } setuperror() { case "$ERROR" in "") ;; *) echo "$ERROR" displayusage exit 1 ;; esac } settime() { case "$1" in "") ;; *) NEWTIME=`expr \( $1 - 1 \) \* 10 \* \( $1 \> 0 \) 2>&1` && \ TIME=$NEWTIME || ERROR=`echo $NEWTIME | cut -d' ' -f2-` ;; esac } setfield() { FIELD=`echo $1 | tr 'A-Z' 'a-z'` case $FIELD in size) SORTSEQ='+3nr +4nr' ;; res) SORTSEQ='+4nr +3nr' ;; cpu) SORTSEQ='+7nr +8nr' ;; time) SORTSEQ='+8nr +7nr' ;; pid) SORTSEQ='+1n' ;; th) SORTSEQ='+2nr +1n' ;; *) ERROR="Unknown sort field \"$FIELD\"" ;; esac } setuser() { case "$1" in "") ;; +) USEROPT="-e" ;; *) USEROPT="-u $1" ;; esac } setmatch() { case "$1" in "") MATCHEXP=. ;; *) MATCHEXP=`echo "$1" | sed 's,/,\\\\/,g'` ;; esac } setfield cpu setmatch '' setuser '+' settime 5 while test $# -gt 0 do case $1 in -s) settime $2 setuperror || exit 1 shift 2 ;; -o) setfield $2 setuperror || exit 1 shift 2 ;; -u) setuser $2 setuperror || exit 1 shift 2 ;; -m) setmatch "$2" setuperror || exit 1 shift 2 ;; *) echo "Unknown option $1" displayusage exit 1 ;; esac done trap getsize WINCH trap resetandexit INT QUIT TERM getsize while : do DISPLAY=`clear; uptime; \ vmstat 1 2 | awk 'NR == 4 \ {if ($4 > 9999) s = int($4/1024) "M"; else s = $4 "k"; \ if ($5 > 9999) f = int($5/1024) "M"; else f = $5 "k"; \ printf "r:%3d, b:%3d, w:%3d, free:%6s swap,%6s real, " \ "CPU:%3d%% us,%3d%% sy,%3d%% id\n", $1, $2, $3, s, f, $20, $21, $22}' echo 'USERNAME PID TH SIZE RES NI STATE %CPU TIME COMMAND' /usr/bin/ps $USEROPT -o user= -o pid= -o nlwp= -o vsz= -o rss= -o \ nice= -o s= -o pcpu= -o time= -o args= | \ awk '{\ if ($6 == "Z") { \ for(i=NF; i>=6; i--) \ $(i+1) = $i; \ $6 = "--"; \ } \ if (split($9,d,"-") == 1) {\ days = 0; t = d[1]; \ } else {\ days = d[1]; t = d[2]; \ } \ if (split(t,time,":") == 2) \ secs = time[2] + time[1]*60; \ else \ secs = time[3] + time[2]*60 + time[1]*3600; \ secs += days*86400; \ printf "%s %s %s %s %s %s %s %s %d", $1,$2,$3,$4,$5,$6,$7,$8,secs; \ for(i=10; i<=NF; i++) \ printf " %s", $i; \ printf "\n"; \ }' | sort $SORTSEQ | awk 'BEGIN { \ state["O"] = "cpu"; state["S"] = "sleep"; state["R"] = "run"; \ state["Z"] = "zomb"; state["T"] = "stop"} '"l < $procs "'{ \ if ($4 > 9999) rs = int($4/1024) "M"; else rs = $4 "k"; \ if ($5 > 9999) vs = int($5/1024) "M"; else vs = $5 "k"; \ if ($9 <= 59999) \ ti = sprintf("%3d:%02d", int($9/60), $9 % 60); \ else {\ ti = $9 / 3600; \ if (ti <= 999.9) \ ti = sprintf("%5.1fH", ti); \ else \ ti = sprintf("%5.1fD", ti/24); \ } \ st = state[$7]; \ if (length($1) > 8) us = substr($1, 1, 8); else us = $1; \ line = sprintf "%-8s %5d%3d%6s%6s %2s %-5s%5s %5s", us, $2, $3, rs, \ vs, $6, st, $8, ti; for(i=10; i<=NF; i++) line = line " " $i; \ '"if (line ~ /$MATCHEXP/) {print substr(line, 1, $columns); l++}}"` echo "$DISPLAY" $ECHONONL "$ERROR" ERROR= $STTY -echo -icanon min 0 time $TIME COMMAND=`(trap TSTP; dd bs=1 count=1 2>/dev/null)` $STTY echo icanon case "$COMMAND" in q) exit 0 ;; o) $ECHONONL 'Enter name of field to sort by: ' read FIELD setfield $FIELD ;; s) $ECHONONL 'Enter number of seconds between updates: ' read SECS settime "$SECS" ;; u) $ECHONONL 'Enter the user to display for (+ for all): ' read USER setuser $USER ;; k) $ECHONONL 'Kill: ' read KILL case "$KILL" in *-l*) ERROR="Option -l not recognised." ;; "") ;; *) ERROR=`kill $KILL 2>&1` ;; esac ;; m) $ECHONONL 'Enter the regular expression to match: ' MATCH=`head -1` setmatch "$MATCH" ;; h|\?) clear cat << EOF Topish version 1.00, Copyright 1999-2001, Steven Singer A cheap replacement for top requiring no special permissions. These single-character commands are available: ^L - redraw screen h or ? - show this text k - kill processes; send a signal to a list of processes m - restrict display to lines matching a regular expression o - specify sort order (size, res, cpu, time, pid, th) q - quit s - change number of seconds between updates Press return or enter to continue EOF read FIELD ;; ""| ) ;; *) ERROR="Command not understood." ;; esac done