The timeout Command in Bash
This article is an easy guide to setting up a timeout for specific programs using the timeout
command by GNU’s coreutils
package in Bash.
the timeout
Command in Bash
In many situations, such as fetching data from a server or running a function or program with random inputs, the program or function may run for a very long time or indefinitely.
In such cases, stopping the program and preventing it from wasting more time and resources is essential.
This is where a timeout functionality comes in. The user defines a time limit, and then the program is allowed to run until successful completion, and if it takes too long until the user-defined time limit, it is then killed.
Timeout functionality is usually built-in for most programming languages. However, for Bash, it is not built-in and is part of an external package called coreutils
.
This package is developed and maintained by GNU and contains implementations of many basic utilities.
The coreutils
package can be installed simply by running the command sudo apt-get install -y coreutils
in LINUX systems.
You must first have Homebrew installed to get the coreutils
on macOS systems. To get Homebrew run the command below in the command terminal.
/bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"
After the complete installation of Homebrew, run the command below.
brew install coreutils
coreutils
commands on macOS, all the commands will have a g
prefixed before the name (e.g., gdir
or gtimeout
).If you have the coreutils
package installed, you can simply use the timeout
function, for example:
timeout 10 ping google.com
The above command outputs:
The ping
utility in Bash is built-in and continues to run until manually interrupted. By default, ping
sends a package every 1 second.
As seen above, the timeout
command kills ping
after 10 seconds as the number right after the timeout
command is the time limit.
Therefore, the command timeout 10 cmd1
means that cmd1
will run until the successful completion or 10 seconds, whichever is earlier. The unit of time for the timeout
command is in seconds.
To use a time value measured in minutes, hours, or days, add an m
, an h
, or a d
, respectively.
For example, to set a timeout of 2 minutes:
timeout 2m programToRun
It should be noted that the exit status for a timeout is 124
when the process times out. In the following example, we will use this to check whether or not the process has timed out.
timeout 1 ping 8.8.8.8 -w3
EXIT_STATUS=$?
if [ $EXIT_STATUS -eq 124 ]
then
echo 'Process timed out!'
else
echo 'Process did not timeout.'
fi
exit $EXIT_STATUS
In the above-illustrated example, if the process does not complete in 1 second, the process will time out. The -w3
extension indicates that the address will be pinged thrice.
Hence, this process will always time out, giving the following output.
PING 8.8.8.8 (8.8.8.8) 56(84) bytes of data.
64 bytes from 8.8.8.8: icmp_seq=1 ttl=57 time=40.4 ms
Process timed out!
It is important to note that any internal timeout will also result in the same exit status (124
). Hence, this output indicates that either the process timed out using our specified timeout or some internal timeout made it terminate.
Use timeout
With SIGKILL
Signal in Bash
Typically, the timeout
function sends a SIGTERM
signal to stop the execution of a program when the time limit is reached. The problem is that some programs may ignore the SIGTERM
signal and keep running.
This is where the SIGKILL
signal comes in; it immediately stops executing a process and all its child processes and cannot be blocked or ignored. To use a timeout with SIGKILL
, we must add the -s
flag.
For example:
timeout -s SIGKILL 10 programToRun
When not running timeout
directly from the shell, as in running it from a script, it is important to add --foreground
to the timeout
command.
Many alternatives to the timeout
command can be used, all primarily based on the same logic of using some kill signal with sleep
and then running the required command or program, which will be stopped as soon as sleep
ends.
Example:
(sleep 2 && killall prog) & ./prog
The above code will kill all processes of prog
after 2 seconds if the prog
has not completed its execution. Such solutions can work but are not as safe and reliable as the timeout
command, so it is always better to use timeout
instead.