I’ve been playing around with trying to make a timeout using just bash builtins, motivated by the fact that my Mac doesn’t have the timeout command.
I haven’t quite been able to do it using _only_ builtins, but if you allow the sleep command (which has been standardised since the first version of POSIX, so it should be available pretty much anywhere that makes any sort of attempt to be POSIX compliant), then this seems ok:
# TIMEOUT SYSTEM
#
# Defines a timeout function:
#
# Usage: timeout <num_seconds> <command>
#
# which runs <command> after <num_seconds> have elapsed, if the script
# has not exited by then.
_alarm() {
local timeout=$1
# Spawn a subshell that sleeps for $timeout seconds
# and then sends us SIGALRM
(
sleep "$timeout"
kill -ALRM $$
) &
# If this shell exits before the timeout has fired,
# clean up by killing the subshell
subshell_pid=$!
trap _cleanup EXIT
}
_cleanup() {
if [ -n "$subshell_pid" ]
then
kill "$subshell_pid"
fi
}
timeout() {
local timeout=$1
local command=$2
trap "$command" ALRM
_alarm "$timeout"
}
# MAIN PROGRAM
times_up() {
echo 'TIME OUT!'
subshell_pid=
exit 1
}
timeout 10 times_up
for i in {1..20}
do
sleep 1
echo $i
done
With that (minus the gen_die() line unless you copy that helper function too), you can do:
doSomething() {
for i in {1..20}
do
sleep 1
echo $i
done
}
if ! call_func_timeout doSomething 10; then
echo 'TIME OUT!'
exit 1
fi
Similarly to you, I only used shell builtins, plus the sleep command. The genkernel code is run by busybox ash, so the script had to be POSIX conformant. Note that both your script and my example script reimplementing your script with my code from 12 years ago, use {1..20}, which I believe is a bashism and is not POSIX conformant, but that is fine for your use case.
My innovation over the stack overflow post was to have the exit status return true when the timeout did not trigger and false when the time out did trigger, so that error handling could be done inline in the main script (even if that error handling is just printing a message and exiting). I felt that made code using this easy to read.
That's ok, but %1 will refer to the wrong job if there's already a background job running. You could use %% instead, but that will refer to the wrong job if <command> terminates before the timeout.
I haven’t quite been able to do it using _only_ builtins, but if you allow the sleep command (which has been standardised since the first version of POSIX, so it should be available pretty much anywhere that makes any sort of attempt to be POSIX compliant), then this seems ok: