1 |
#!/bin/bash
|
2 |
#
|
3 |
# The Bash shell script executes a command with a time-out.
|
4 |
# Upon time-out expiration SIGTERM (15) is sent to the process. If the signal
|
5 |
# is blocked, then the subsequent SIGKILL (9) terminates it.
|
6 |
#
|
7 |
# Based on the Bash documentation example.
|
8 |
|
9 |
# Hello Chet,
|
10 |
# please find attached a "little easier" :-) to comprehend
|
11 |
# time-out example. If you find it suitable, feel free to include
|
12 |
# anywhere: the very same logic as in the original examples/scripts, a
|
13 |
# little more transparent implementation to my taste.
|
14 |
#
|
15 |
# Dmitry V Golovashkin <Dmitry.Golovashkin@sas.com>
|
16 |
|
17 |
scriptName="${0##*/}"
|
18 |
|
19 |
declare -i DEFAULT_TIMEOUT=300
|
20 |
declare -i DEFAULT_INTERVAL=1
|
21 |
declare -i DEFAULT_DELAY=1
|
22 |
|
23 |
# Timeout.
|
24 |
declare -i timeout=DEFAULT_TIMEOUT
|
25 |
# Interval between checks if the process is still alive.
|
26 |
declare -i interval=DEFAULT_INTERVAL
|
27 |
# Delay between posting the SIGTERM signal and destroying the process by SIGKILL.
|
28 |
declare -i delay=DEFAULT_DELAY
|
29 |
|
30 |
function printUsage() {
|
31 |
cat <<EOF
|
32 |
|
33 |
Synopsis
|
34 |
$scriptName [-t timeout] [-i interval] [-d delay] command
|
35 |
Execute a command with a time-out.
|
36 |
Upon time-out expiration SIGTERM (15) is sent to the process. If SIGTERM
|
37 |
signal is blocked, then the subsequent SIGKILL (9) terminates it.
|
38 |
|
39 |
-t timeout
|
40 |
Number of seconds to wait for command completion.
|
41 |
Default value: $DEFAULT_TIMEOUT seconds.
|
42 |
|
43 |
-i interval
|
44 |
Interval between checks if the process is still alive.
|
45 |
Positive integer, default value: $DEFAULT_INTERVAL seconds.
|
46 |
|
47 |
-d delay
|
48 |
Delay between posting the SIGTERM signal and destroying the
|
49 |
process by SIGKILL. Default value: $DEFAULT_DELAY seconds.
|
50 |
|
51 |
As of today, Bash does not support floating point arithmetic (sleep does),
|
52 |
therefore all delay/time values must be integers.
|
53 |
EOF
|
54 |
}
|
55 |
|
56 |
# Options.
|
57 |
|
58 |
# $# should be at least 1 (the command to execute), however it may be strictly
|
59 |
# greater than 1 if the command itself has options.
|
60 |
if (($# == 0 || interval <= 0)); then
|
61 |
printUsage
|
62 |
exit 1
|
63 |
fi
|
64 |
export HAVEKILLED=0
|
65 |
# kill -0 pid Exit code indicates if a signal may be sent to $pid process.
|
66 |
(
|
67 |
((t = timeout))
|
68 |
|
69 |
while ((t > 0)); do
|
70 |
sleep $interval
|
71 |
kill -0 $$ || exit 0
|
72 |
((t -= interval))
|
73 |
done
|
74 |
|
75 |
# Be nice, post SIGTERM first.
|
76 |
# The 'exit 0' below will be executed if any preceeding command fails.
|
77 |
echo -e "\E[31;47m Sorry have to kill the process as it took longer than $timeout seconds (checked after $interval)\E[0m \n "
|
78 |
kill -s SIGTERM $$ && kill -0 $$ || exit 0
|
79 |
export HAVEKILLED=1
|
80 |
sleep $delay
|
81 |
kill -s SIGKILL $$
|
82 |
) 2> /dev/null &
|
83 |
|
84 |
eval $@
|