Loading
killp
Neighboring pages...
Signal (typically, terminate) specific processes according to their command line text. Many features - 'killp -?' tells you all the options, and see the documentation comments at the top of the script.
Latest update: 2015-10-09
#!/bin/bash
# Send signals to selected processes according to their command line text.
# Killp:
# - reports each running process whose command contains an egrep-style
# match for the text on the killp command line
# - solicits confirmation from the user for sending a signal to each target
# - on each confirmation, reports whether the signal was succesfully
# delivered (the user, eg, might not be privileged to signal that process)
# - proceeds to the next qualifying process
# Many of these behaviors can be adjusted using command-line arguments.
# The user can designate the signal to be sent just as they would with
# the shell 'kill' command. 'TERM' is accordingly the default signal.
# Additionally, the user can restrict the candidate process to just
# those running under the users uid, with the '-m' option.
# killp can be run non-interactively. It only lists the qualified
# candidates, delivering no signals, when the '-n' option is
# specified. It delivers the designated signal to all qualified
# candidates if the '-y' option is specified. (The '-n' option takes
# precedence.)
# A '--' command line option indicates that all following arguments
# are to be taken as the match pattern. This is useful if the initial
# character of the match pattern is a '-'.
# Each prompt includes the sequence number of the candidate process,
# the total number of processes, the pid of the candidate, the command
# text as ps sees it, the pending signal, the set of valid responses,
# and then the default response, which will be sent on null input from
# the user. The initial default response is no ('n').
# The prompting provides a number of options. The valid responses are:
#
# y - yes
# n - no
# Y - yes, and set default response to 'y'
# N - no, and set default response to 'n'
# g - 'go' - don't ask, just show rest of candidates and do default action
# q - 'quit' - no more killing, exit immediately
# ? - show this message
#
# The 'g' response allows the user to indicate that all the remaining
# candidates should be treated with the default response, which can
# first be reset to 'y' or 'n' using the 'Y' or 'N' responses.
# *Note for systems running SunOS 4.1.3*
# ------------------------------------
# There's a Sun patch for ps which makes it work reliably with the
# combination of the 'xja' options. Without it, ps will sporadically
# (but often) segmentatation faults, particularly when your processes
# are reaching higher pids. The script accomodates this bug to some
# degree, but is less discriminating about the candidate processes it
# offers for kills. You're better off installing Sun patch 100981-02,
# which consists of a repaired ps executable.
PATH=/bin:/usr/bin:/usr/ucb
# Get the name of the script, in $scriptNm:
plainIFS="$IFS"; IFS="/$IFS"
for scriptNm in $0; do : ; done;
IFS=" "
IFS="$plainIFS"
# The default signal:
sig="-TERM"
case "$(uname -s)" in
Linux ) os=Linux
awk=awk;;
Darwin ) os=MacOSX
awk=awk;;
* ) case "$(uname -o)" in
Cygwin ) os=Linux
awk=awk;;
* ) os="$(uname -r)"
awk=nawk;;
esac;;
esac
UsageMsg () {
echo \
"${scriptNm} [ -SIGNAL ] [ -m ] [ -n | -y ] [ -help | '-?' ] [ -- ] string ...
For each process invoked containing egrep(1) match for 'string', ask
user whether to bombard it with <SIGNAL> (default TERM).
'-SIGNAL' names signal (default: \"-TERM\", 15) to send.
'-m' - attend only to user's (\"My\") processes.
'-n' - No signalling (or prompting) - just show number, pid,
and text of matching commands.
'-p' - show only Process ids, with no signally or prompting.
'-y' - Yes - send signal to matching procs, !no questions asked!
'-help' and '-?' -show this message and exit.
'--' - take all subsequent arguments as part of the command text.
During interaction, use '?' to get help on response choices."
}
# Parse the command line:
while [ "x$*" != "x" ]; do
case "$1" in
-m ) meOnly=t; shift;;
-n ) alwaysNo=$1; shift;;
-p ) pidOnly=t; shift;;
-y ) alwaysYes=$1; shift;;
-- ) shift; target="$*"; shift $#;; # Consume the rest
-help | -\? ) UsageMsg; exit 0;;
-[0-9] | -[1-9][0-9] | -[A-z]* ) sig=$1; shift;;
* ) target="$*"; shift $#;; # Consume the rest
esac
done
if [ x"$target" = "x" ]; then
echo "${scriptNm}: nonsense - no command text specified. Usage:" 1>&2
UsageMsg
exit 1
fi
EchoSansNL () {
case $os in
5* ) echo "$@"'\c';;
* ) echo -n "$@";;
esac
}
PsArgsLinux () {
# Suitable ps args for Linux (at least, as of 1.1.59).
psArgs="xjww"
cmdCol=57
pidFld=2
pgidFld=3
psOthersOpt=a
}
PsArgsMacOSX () {
# Suitable ps args for Linux (at least, as of 1.1.59).
PsArgsLinux
pgidFld=""
}
PsArgsOS4 () {
# Suitable ps args for SunOS4.
PsArgsLinux
cmdCol=54
psArgs=-$psArgs
}
PsArgsOS5 () {
# Suitable ps args for SunOS5 (solaris 2)
psArgs=-fja
cmdCol=60
pidFld=2
pgidFld=4
psOthersOpt=e
}
AltPsArgsOS4 () {
# Alternate ps args for SunOS4, for use when (SunOS 4.1.3) ps
# 'xja' bug is screwing us up.
psArgs=-xlw
cmdCol=73
pidFld=3
pgidFld=""
psOthersOpt=a
}
PsArgs () {
vrsn="$1"
if [ -z "$vrsn" ]; then vrsn="$os"; fi
case $vrsn in
4* ) PsArgsOS4;;
5* ) PsArgsOS5;;
Linux ) PsArgsLinux;;
MacOSX ) PsArgsMacOSX;;
alt4 ) AltPsArgsOS4;;
* ) echo "Unimplemented OS '$1' - using linux configuration."
PsArgsLinux;;
esac
}
GetCandidates () {
# Set var 'candidates' to the pid and command for all process
# whose commands contain an 'nawk' (egrep) match for given string.
# The process running this script and its offspring are excluded.
target="$*"
thisPid=$$
PsArgs
if [ "x$meOnly" = "x" ]; then psArgs=${psArgs}${psOthersOpt}; fi
psLines="`ps $psArgs`"
status=$?
if [ $status != 0 ]; then
echo "Somethings wrong with ps ($vrsn, ps $psArgs) - bailout."
exit 1
fi
if [ -n "$pgidFld" ]; then
useIdFld="$pgidFld"
else
useIdFld="$pidFld"
fi
# Filter out this process and offspring from the list:
candidates=`IFS="";
echo $psLines | \
$awk 'NR != 1 \
{ if (($matchIdFld != thisPid) &&
(substr($0,cmdCol) ~ target))
# All procs containing target string but, either,
# - not in the process group of this process, if
# we have it,
# - or not having the pid, if we dont:
{ got += 1
targets[got]=$pidFld " " substr($0,cmdCol)
}
}
END { print got
for (i=1; i<=got; i++) print targets[i] } ' \
thisPid=$thisPid target="$target" cmdCol=$cmdCol \
matchIdFld="$useIdFld" pidFld=$pidFld \
leadFldNm="$leadFldNm" -`
return $status
}
Ask () {
# Line split so $totalNum can be at bol, to discard leading spaces:
EchoSansNL "$onNum/"
EchoSansNL $totalNum, $pid" $command " # Indicate target text.
if [ x"$alwaysNo" != "x" ]; then
# We're in no-action mode, just go on to the next one:
echo ""
return 1
else
# Set up for a kill:
EchoSansNL " [$sig, y/n/g/q/?: $defResp] "
if [ x"$alwaysYes" != "x" ]; then
echo "[y]"
return 0
elif [ x"$alwaysDef" != "x" ]; then
if [ "$defResp" = "y" ]; then
echo "[y]"
return 0
else
echo "[n]"
return 1
fi
else
read response <&4 # Get the response
fi
# Return code from GetAction will be returned.
GetAction $response
return $?
fi
}
GetAction () {
case $1 in
y ) return 0;;
Y ) defResp="y"; return 0;;
n ) action=n; return 1;;
N ) defResp="n"; return 1;;
g ) alwaysDef=t; if [ "$defResp" = y ]; then return 0; else return 1; fi;;
q ) exit 0;;
? ) echo "
y - yes
n - no
g - 'go' - don't ask, just show rest of candidates, doing default action
Y - yes, and set default response to 'y'
N - no, and set default response to 'n'
q - 'quit' - no more signalling or reporting - exit immediately
? - show this message
"
# Resolicit the response:
Ask;;
* ) case "$defResp" in
y ) echo "y"; return 0;;
* ) echo "n"; return 1;;
esac;;
esac
}
# Dup stdin to file descr 4, so we can still read from stdin while
# taking input (in the while loop) from a pipe:
exec 4<&0
# ... and dup stderr to file descr 5 for showing errors to user
exec 5<&2
GetCandidates $target
status=$?
if [ $status != 0 ]; then
echo "${scriptNm}: ps $psArgs returned error status $status - the kernel seems to be awry." 2>&1
fi
if [ x"$candidates" = "x" ]; then
if [ x"$meOnly" != "x" ]; then
qual="no $USER"
else
qual="no"
fi
echo "${scriptNm}: $qual commands matching '$target' found" 1>&2
exit 1
fi
onNum=1
defResp=n
echo "$candidates" | \
while read pid command; do
# The first item is the count:
if [ x"$totalNum" = "x" ]; then
totalNum=$pid
# The rest are the entries:
else
if [ -n "$pidOnly" ]; then
echo $pid
elif Ask; then
kill $sig $pid
if [ $? = 0 ]; then
echo ... hit
else
echo ... missed
fi
fi
onNum="`expr $onNum + 1`" # Increment the target count.
fi
done
exit $?