#!/bin/sh - PATH=$PATH:/sbin:/usr/sbin:/etc:/usr/etc; export PATH umask 000 snapshot=/var/tmp/snaps test -d /var/tmp || snapshot=/tmp/snaps killpid=killpid # snaps - snapshot ps, convenience front-end for the ps, kill & renice commands # Steve Kinzler, kinzler@cs.indiana.edu, Sep 90/Jul 94/Mar 06 # http://www.cs.indiana.edu/~kinzler/home.html#unix action=snaps; user=; force=; priority= snaps=; page=; perl=; gopt=; popt=; bad= while : do case $# in 0) break;; *) case "$1" in -u) user=t case "$action" in snaps) action=list;; esac;; -l) action=list;; -c) action=count;; -k) action=kill;; -[A-Z][A-Z]*) action="kill $1";; -r) shift; action="renice -n $1"; priority="$1";; -f) force=t;; -s) snaps=t;; -P) page=P;; -E) page=E;; -g) perl=;; -p) perl=t;; -i) gopt="$1"; popt=i;; --) shift; break;; -h) bad=t; break;; -*) bad=t; echo "$0: unknown option ($1)" 1>&2;; *) break;; esac shift;; esac done case "$bad" in ?*) cat << EOF 1>&2 usage: $0 [ -u ] [ -l | -c | [ -k ] [ -SIGNAL ] | -r priority ] [ -f ] [ -s ] [ -P | -E ] [ -g | -p ] [ -i ] [ regexp ... ] Without arguments, just snapshots the system ps to the snapshot file, $snapshot. -u restricts consideration to user's current processes -l lists processes (default with -u or regexps) -c lists an ordered count of process names -k kills processes -SIGNAL use the given signal when killing processes (implies -k) -r renices processes with the given priority -f force kills or renices without confirmation -s snapshots system ps even if the snapshot file already exists -P runs the user's \$PAGER or 'more' to view any listing -E runs the user's \$VISUAL, \$EDITOR or 'vi' to edit any listing -g use grep regular expressions (default) -p use perl regular expressions -i use case-insensitive matching with the regexps Consideration is restricted to processes with ps lines matching the given regexps if any are specified, otherwise all processes are considered. For system process consideration, the snapshot file is used if it already exists, otherwise it is automatically created first. For user process consideration, ps is always run anew. If kill or renice input is from a tty and no -f option is given, confirmation is required before the kills or renices. If the special signal -DIE is given, the command '$killpid' is used to kill the processes. EOF exit 1;; esac case $# in 0) ;; *) case $action in snaps) action=list;; esac;; esac tmp=/tmp/snaps$$ tmpA=/tmp/snapsA$$ tmpB=/tmp/snapsB$$ trap 'rm -f $tmp $tmpA $tmpB; exit' 0 1 2 13 15 # We have to try SysV ps first since some systems, eg aix3 and hpux, # will silently do something, but not what we want, with BSD ps arguments. # This gets the desired behavior with procps-2.0, eg. PS_PERSONALITY=bsd; export PS_PERSONALITY case "$action" in snaps) bsd= if ps -ef > $tmpA 2> /dev/null then case "`grep ' \\\\_ ' $tmpA`" in ?*) bsd=t;; *) test `wc -l < $tmpA` -le 1 && bsd=t;; esac else bsd=t fi case "$bsd" in ?*) ps aguwwx > $tmpA 2> /dev/null || ps auwwx > $tmpA;; esac trap '' 1 2 13 15 cat $tmpA > "$snapshot" exit;; esac case "$user" in ?*) bsd= if ps -f > $tmpA 2> /dev/null then case "`grep ' \\\\_ ' $tmpA`" in ?*) bsd=t;; *) test `wc -l < $tmpA` -le 1 && bsd=t;; esac else bsd=t fi case "$bsd" in ?*) ps guwwx > $tmpA 2> /dev/null || ps uwwx > $tmpA;; esac snapshot=$tmpA;; *) case "$snaps" in ?*) $0;; *) test -s "$snapshot" || $0;; esac;; esac case $# in 0) sed 1d < "$snapshot" > $tmpB || exit 2;; *) case "$perl" in ?*) for regexp do perl -ne "m$regexpo$popt && ! m$0o && $. > 1 && print" < "$snapshot" || exit 2 done > $tmpB || exit 2;; *) for regexp do sed 1d < "$snapshot" | grep $gopt "$regexp" done | grep -v "$0" > $tmpB || exit 2;; esac;; esac case "$page" in [EeVv]*) page=${VISUAL-${EDITOR-vi}};; ?*) page=${PAGER-more};; *) page=cat;; esac case "$action" in list) sed 1q < "$snapshot" > $tmp && cat < $tmpB >> $tmp && $page $tmp;; count) dots=`sed 's/CMD$//; s/COMD$//; s/COMMAND$//; s/././g; 1q' "$snapshot"` case "$dots" in '') echo "$0: cannot determine COMMAND column of ps output" 1>&2 exit 3;; esac sed "s/^$dots// s/.*(\(.*\)).*/\1/ s/^[ ]*// s/[ ].*// s/^-// s,.*/,," < $tmpB | sort | uniq -c | sort -nr > $tmp || exit 2 $page $tmp;; kill*|renice*) case "$action" in kill*-DIE) action="$killpid";; renice*) case "`renice 2>&1`" in *renice?priority*) action="renice $priority";; esac esac xopt= if test -z "$force" -a -t 0 then hdr=`sed 1q < "$snapshot"` || exit 2 echo "$hdr" > $tmp || exit 2 cat < $tmpB >> $tmp || exit 2 $page $tmp hdr=`echo "$hdr" | sed 's/[^a-zA-Z0-9_ ]/\\\\&/g'` grep -v "^$hdr$" $tmp > $tmpB || exit 2 echo "$action all these? [n] " | tr -d '\012' read answer case "$answer" in [yY]*) xopt=-p;; *) exit;; esac fi set x `sed 1q "$snapshot" | sed -n 's/^PID .*//p; s/ PID .*//p' | wc` shift case "$1" in 1) ;; *) echo "$0: cannot determine PID column of ps output" 1>&2 exit 3;; esac awk "{ print \$($2 + 1) }" < $tmpB | xargs $xopt $action;; esac