How to Set Time Out from Bash Script

Is it possible to set time out from bash script?

This Bash-only approach encapsulates all the timeout code inside your script by running a function as a background job to enforce the timeout:

#!/bin/bash

Timeout=1800 # 30 minutes

function timeout_monitor() {
sleep "$Timeout"
kill "$1"
}

# start the timeout monitor in
# background and pass the PID:
timeout_monitor "$$" &
Timeout_monitor_pid=$!

# <your script here>

# kill timeout monitor when terminating:
kill "$Timeout_monitor_pid"

Note that the function will be executed in a separate process. Therefore the PID of the monitored process ($$) must be passed. I left out the usual parameter checking for the sake of brevity.

Execute a shell function with timeout

timeout is a command - so it is executing in a subprocess of your bash shell. Therefore it has no access to your functions defined in your current shell.

The command timeout is given is executed as a subprocess of timeout - a grand-child process of your shell.

You might be confused because echo is both a shell built-in and a separate command.

What you can do is put your function in it's own script file, chmod it to be executable, then execute it with timeout.

Alternatively fork, executing your function in a sub-shell - and in the original process, monitor the progress, killing the subprocess if it takes too long.

Timeout a command in bash without unnecessary delay

I think this is precisely what you are asking for:

http://www.bashcookbook.com/bashinfo/source/bash-4.0/examples/scripts/timeout3

#!/bin/bash
#
# The Bash shell script executes a command with a time-out.
# Upon time-out expiration SIGTERM (15) is sent to the process. If the signal
# is blocked, then the subsequent SIGKILL (9) terminates it.
#
# Based on the Bash documentation example.

# Hello Chet,
# please find attached a "little easier" :-) to comprehend
# time-out example. If you find it suitable, feel free to include
# anywhere: the very same logic as in the original examples/scripts, a
# little more transparent implementation to my taste.
#
# Dmitry V Golovashkin <Dmitry.Golovashkin@sas.com>

scriptName="${0##*/}"

declare -i DEFAULT_TIMEOUT=9
declare -i DEFAULT_INTERVAL=1
declare -i DEFAULT_DELAY=1

# Timeout.
declare -i timeout=DEFAULT_TIMEOUT
# Interval between checks if the process is still alive.
declare -i interval=DEFAULT_INTERVAL
# Delay between posting the SIGTERM signal and destroying the process by SIGKILL.
declare -i delay=DEFAULT_DELAY

function printUsage() {
cat <<EOF

Synopsis
$scriptName [-t timeout] [-i interval] [-d delay] command
Execute a command with a time-out.
Upon time-out expiration SIGTERM (15) is sent to the process. If SIGTERM
signal is blocked, then the subsequent SIGKILL (9) terminates it.

-t timeout
Number of seconds to wait for command completion.
Default value: $DEFAULT_TIMEOUT seconds.

-i interval
Interval between checks if the process is still alive.
Positive integer, default value: $DEFAULT_INTERVAL seconds.

-d delay
Delay between posting the SIGTERM signal and destroying the
process by SIGKILL. Default value: $DEFAULT_DELAY seconds.

As of today, Bash does not support floating point arithmetic (sleep does),
therefore all delay/time values must be integers.
EOF
}

# Options.
while getopts ":t:i:d:" option; do
case "$option" in
t) timeout=$OPTARG ;;
i) interval=$OPTARG ;;
d) delay=$OPTARG ;;
*) printUsage; exit 1 ;;
esac
done
shift $((OPTIND - 1))

# $# should be at least 1 (the command to execute), however it may be strictly
# greater than 1 if the command itself has options.
if (($# == 0 || interval <= 0)); then
printUsage
exit 1
fi

# kill -0 pid Exit code indicates if a signal may be sent to $pid process.
(
((t = timeout))

while ((t > 0)); do
sleep $interval
kill -0 $$ || exit 0
((t -= interval))
done

# Be nice, post SIGTERM first.
# The 'exit 0' below will be executed if any preceeding command fails.
kill -s SIGTERM $$ && kill -0 $$ || exit 0
sleep $delay
kill -s SIGKILL $$
) 2> /dev/null &

exec "$@"

Bash timeout command doesn't work within a script

I found the solution: systemctl seemed to be waiting for 'input' for authentication when ran from a script. It didn't really need this, so it immediately succeeded when not ran from a script. I solved the problem by adding --no-ask-password:

/usr/bin/timeout 180 /bin/systemctl --no-ask-password stop aem-service || echo "test"

bash - close script by error or by timeout

First, I won't use set -e.

You'll explicitly wait on the job you want; the exit status of wait will be the exit status of the job itself.

echo "finish_time = $1"

./execute_something.sh & pid=$!
sleep "$1" & sleep_pid=$!

wait -n # Waits for either the sleep or the script to finish
rv=$?

if kill -0 $pid; then
# Script still running, kill it
# and exit
kill -s ALRM $pid
wait $pid # exit status will indicte it was killed by SIGALRM
exit
else
# Script exited before sleep
kill $sleep_pid
exit $rv
fi

There is a slight race condition here; it goes as follows:

  1. wait -n returns after sleep exits, indicating the script will exit on its own
  2. The script exits before we can check if it is still running
  3. As a result, we assume it actually exited before sleep.

But that just means we'll create a script that ran slightly over the threshold as finishing on time. That's probably not a distinction you care about.

Ideally, wait would set some shell parameter that indicates which process caused it to return.

Set timeout for shell script, to make it exit(0) when time is over

I resolved this problem finally, I added the code below in each testX.sh.

trap 'exit 0' SIGTERM SIGHUP

It is to make test1.sh exit normally after it receives killall signal.

Thanks to all the help!



Related Topics



Leave a reply



Submit