I want to run a shell script that got a loop in it and it can go for ever which I do not want to happen. So I need to introduce a timeout for the whole script.
How can I introduce a timeout for the whole shell script under SuSE?
I want to run a shell script that got a loop in it and it can go for ever which I do not want to happen. So I need to introduce a timeout for the whole script.
How can I introduce a timeout for the whole shell script under SuSE?
If GNU timeout
is not available you can use expect
(Mac OS X, BSD, ... do not usually have GNU tools and utilities by default).
################################################################################
# Executes command with a timeout
# Params:
# $1 timeout in seconds
# $2 command
# Returns 1 if timed out 0 otherwise
timeout() {
time=$1
# start the command in a subshell to avoid problem with pipes
# (spawn accepts one command)
command="/bin/sh -c \"$2\""
expect -c "set echo \"-noecho\"; set timeout $time; spawn -noecho $command; expect timeout { exit 1 } eof { exit 0 }"
if [ $? = 1 ] ; then
echo "Timeout after ${time} seconds"
fi
}
Edit Example:
timeout 10 "ls ${HOME}"
timeout
itself is 124 in the case of a timeout, otherwise it's the command's return status (this is mentioned in Tim Kennedy's answer).
– Daniel Hanrahan
Aug 11 '13 at 02:25
Thank you for the clarification.
The easiest way to accomplish what you're after is to run your script with the loop within a wrapper like the timeout
command from the GNU Coreutils package.
root@coraid-sp:~# timeout --help
Usage: timeout [OPTION] DURATION COMMAND [ARG]...
or: timeout [OPTION]
Start COMMAND, and kill it if still running after DURATION.
Mandatory arguments to long options are mandatory for short options too.
-k, --kill-after=DURATION
also send a KILL signal if COMMAND is still running
this long after the initial signal was sent.
-s, --signal=SIGNAL
specify the signal to be sent on timeout.
SIGNAL may be a name like 'HUP' or a number.
See `kill -l` for a list of signals
--help display this help and exit
--version output version information and exit
DURATION is an integer with an optional suffix:
`s' for seconds(the default), `m' for minutes, `h' for hours or `d' for days.
If the command times out, then exit with status 124. Otherwise, exit
with the status of COMMAND. If no signal is specified, send the TERM
signal upon timeout. The TERM signal kills any process that does not
block or catch that signal. For other processes, it may be necessary to
use the KILL (9) signal, since this signal cannot be caught.
Report timeout bugs to bug-coreutils@gnu.org
GNU coreutils home page: <http://www.gnu.org/software/coreutils/>
General help using GNU software: <http://www.gnu.org/gethelp/>
For complete documentation, run: info coreutils 'timeout invocation'
In the end, it will be much easier than writing your own timeout function, which shells tend to not have builtin.
gtimeout
on my setup (OSX).
– Joshua Goldberg
Nov 08 '17 at 17:10
Launch a watchdog process from within your script to kill off its parent if it runs too long. Example:
# watchdog process
mainpid=$$
(sleep 5; kill $mainpid) &
watchdogpid=$!
# rest of script
while :
do
...stuff...
done
kill $watchdogpid
This script will be terminated by the watchdog after five seconds.
#!/bin/sh
# Execute a command with a timeout
if [ "$#" -lt "2" ]; then
echo "Usage: `basename $0` timeout_in_seconds command" >&2
echo "Example: `basename $0` 2 sleep 3 || echo timeout" >&2
exit 1
fi
cleanup()
{
trap - ALRM #reset handler to default
kill -ALRM $a 2>/dev/null #stop timer subshell if running
kill $! 2>/dev/null && #kill last job
exit 124 #exit with 124 if it was running
}
watchit()
{
trap "cleanup" ALRM
sleep $1& wait
kill -ALRM $$
}
watchit $1& a=$! #start the timeout
shift #first param was timeout for sleep
trap "cleanup" ALRM INT #cleanup after timeout
"$@"& wait $!; RET=$? #start the job wait for it and save its return value
kill -ALRM $a #send ALRM signal to watchit
wait $a #wait for watchit to finish cleanup
exit $RET #return the value
There's also cratimeout
by Martin Cracauer.
# cf. http://www.cons.org/cracauer/software.html
# usage: cratimeout timeout_in_msec cmd args
cratimeout 5000 sleep 600
cratimeout 5000 tail -f /dev/null
cratimeout 5000 sh -c 'while sleep 1; do date; done'
timeout
orexpect
) – Gilles 'SO- stop being evil' Jul 18 '12 at 23:37