In this tutorial we will discuss the timeout command. This utility allows you to exit a command after it runs for x number of seconds. Timeout is part of the GNU Core Utilities that are available on almost any Linux system. It is a fairly simple utility that doesn't have a ton of options. In the following sections we will outline the basic usage, some of it's options and of course show some examples.
Basic timeout Command Usage
Using the timeout utility is quite simple. You call timeout, specify the number of seconds you want, then enter the command you want to run. Here is the basic syntax.
timeout 10 command
Let's say we wanted to run top on a system to check the running processes. Normally top would run indefinitely until sent the SIGINT signal by pressing CTRL+C on the keyboard. Using the timeout command we can tell timeout to exit after 10 seconds.
That's it, simple and to the point. Now let's explore some of the options for timeout.
Send Specific Signal with Timeout
There are may different signals you can send to a command. Outlining all of them is outside the scope of this tutorial. Instead we will focus on how to send a specific signal.
By Default the timeout command sends a SIGTERM or termination signal. We can specify which signal to send by using the -s (--signal) option followed by the desired signal. For example, let's say we wanted to send the SIGINT signal to the top command after 10 seconds. We can specify the signal by name or number, like so:
timeout -s SIGINT 10 top
timeout -s 2 10 top
You can get a list of signals by calling the following command:
Using Verbose Output to Print Signal
In the last section we discussed using specific signals with timeout. If you want to know which signal was used you can supply the -v (--verbose) option. This will print the signal used by timeout to stderr (standard error).
Here is an example of timeout run without specifying a signal. As mentioned in the previous section, SIGTERM will be used by default. We will use the tail command as an example for readability.
$ timeout -v 5 tail -F /etc/redhat-release Fedora release 30 (Thirty) timeout: sending signal TERM to command ‘tail’
As you can see, timeout printed the signal it sent to the tail command. Let's try another example, but this time we will send the SIGINT signal.
[[email protected] ~]$ timeout -v -s SIGINT 5 tail -F /etc/redhat-release Fedora release 30 (Thirty) timeout: sending signal INT to command ‘tail’
Preserving Exit Status (Exit Code)
Timeout will exit with status code 124 if the command reaches the time limit and is timed out. If the command completes before the specified time limit, it will return the exit status of the command. You can preserve the exit status of the command by using the --preserve-status option. This will instruct the timeout utility to use the exit status of the command, even if it times out. Let's look at some examples to better demonstrate how this works.
Here we will run the tail command and interrupt it with the CTRL+C keyboard combination (SIGINT). This will generate an exit code of 130, which means command terminated by CTRL+C.
$ tail -F /etc/redhat-release Fedora release 30 (Thirty) ^C $ echo $? 130
Now we know that if we send SIGINT to tail it generates a 130 exit code. Let's tell timeout to send SIGINT after 5 seconds and check the exit code.
$ timeout -s SIGINT 5 tail -F /etc/redhat-release Fedora release 30 (Thirty) $ echo $? 124
The exit code is 124, this is because we are getting the exit code of timeout, NOT the command. Remember, if the timeout reaches it's time limit it will always return the 124 exit code. If we want the exit code of the command, we must use the --preserve-status option. Let's run the same command again, this time with the preserve status option.
$ timeout --preserve-status -s SIGINT 5 tail -F /etc/redhat-release Fedora release 30 (Thirty) $ echo $? 130
Timeout now sends the exit code of the command, even though the time limit was reached.
Killing Unruly (Stuck) Processes
There are times when a process continues to run even after sending a termination signal. If you have used a Linux system long enough, you probably have seen this before. You run a command, then hit CTRL+C to terminate the command and nothing happens. It is frustrating and usually makes the user instantly start mashing CTRL+C repeatedly. If the process still doesn't respond most people head for the nuclear kill -9 (SIGKILL) option. The timeout command has a option for such a case.
Using the -k (--kill-after) option allows you to send a SIGKILL to the process after a set time limit. Let's run an experiment to see how it works.
For this example I wrote a small script that uses the trap command to ignore the SIGTERM signal. This will allow us to demonstrate how the "kill after" option works. Here is our script:
#!/bin/bash trap 'echo "RECEIVED SIGTERM, IGNORING"; SECS=1' TERM SECS=1 while true; do echo "Running for $SECS seconds…" let "SECS=SECS+1" sleep 1 done
The script will continue to print "Running for x seconds..." to the screen indefinitely if left alone. Let's run it with the timeout command with a 5 second time limit and use the -k option to kill it after 10 seconds.
timeout -k 10 5 "./test.sh"
Our experiment worked perfectly. The script ran for 5 seconds, then timeout sent the SIGTERM to terminate it. The script caught the SIGTERM and ignored it, restarted it's counter and kept going. The kill after option was set to 10 seconds, which sent the SIGKILL to the script when that time limit was reached, ultimately killing the process.
There you have the timeout command. Not only did we learn the basic usage of the timeout command, but we also learned a little about signals. Another interesting tidbit is the fact that you can use trap to ignore signals, something that did not occur to me until I needed to do it.
Below is a summary of links and resources we mentioned in the article for your convenience.
Resources and Links
This site uses Akismet to reduce spam. Learn how your comment data is processed.