Differences between revisions 15 and 16
Revision 15 as of 2010-05-27 06:30:53
Size: 3710
Editor: Lhunath
Comment: A bit of advice on where to look first.
Revision 16 as of 2010-07-21 22:44:44
Size: 4177
Editor: WillDye
Comment: The standard "timeout" is now easier to acquire (at least for some people)
Deletions are marked like this. Additions are marked like this.
Line 4: Line 4:
'''FIRST''' check whether the command you're running can't be told to timeout directly. The methods described here are "hacky" workarounds to force a command to terminate after a certain time has elapsed. Configuring your command properly is ''always'' preferable to this.  So do not proceed until you've checked and double-checked your command's man page and documentation for such a method. '''FIRST''' check whether the command you're running can't be told to timeout directly. The methods described here are "hacky" workarounds to force a command to terminate after a certain time has elapsed. Configuring your command properly is ''always'' preferable to the alternatives below.
Line 6: Line 6:
That said, there are two C programs that can do this: [[http://pilcrow.madison.wi.us/|doalarm]], and [[http://www.porcupine.org/forensics/tct.html|timeout]]. If you're running a recent version of Ubuntu or a similar Linux distribution,
you may already have (or be able to easily install) a standard program named "timeout".
Here's an excerpt from a terminal session in Ubuntu 10.04:
{{{
$ timeout
The program 'timeout' is currently not installed. You can install it by typing:
sudo apt-get install timeout
$ sudo apt-get install timeout
 [Installation messages omitted]
$ man timeout
 [Instructions of using 'timeout' should appear]
$ timeout -15 2 top
 [Runs 'top' for two seconds, then terminates the process]
$ two_hours=$((60*60*2)) # Number of seconds in two hours
$ timeout -15 $two_hours really_long_running_program
}}}
Beware: by default, 'timeout' issues a SIGKILL (kill -9),
which is roughly the same as pulling out the power cord,
(leaving no chance for the program to clean up files and such).
See [[ProcessManagement]] for more information on SIGKILL.
You'll probably want to use a kinder, gentler signal such as -15.
If you want to send the program a gentle signal,
then resort to SIGKILL if the first signal doesn't work,
you can create a series of wrapper commands.

If the above methods don't work in your case,
here are two C programs that you can download and compile:
[[http://pilcrow.madison.wi.us/|doalarm]],
and [[http://www.porcupine.org/forensics/tct.html|timeout]].
Line 9: Line 37:
and at least possible (though potentially painful) on anything else. GNU coreutils also added an implementation of `timeout` in 2008 (version number unknown).

In early 2010, a
[[http://git.savannah.gnu.org/gitweb/?p=coreutils.git;a=commit;h=c403c31e8806b732e1164ef4a206b0eab71bca95|patch]]
was submitted to add a proper
[[http://old.nabble.com/What-signal-should-timeout-send-when-it-gets-a-SIGTERM--ts27814544.html|"--kill-after" option]]
to the "timeout" command in GNU coreutils.
If you have the GNU coreutils version of timeout
(as opposed to the downloaded & compiled "timeout" program mentioned above),
and if your version is new enough to support the "--kill-after" option,
then the coreutils approach is almost certainly your best bet.
and at least possible (though potentially painful) on anything else.
Line 52: Line 70:
The shell-script "[[http://www.shelldorado.com/scripts/cmds/timeout|timeout]]" uses the second approach above. It has the advantage of working immediately (no need for compiling a program), but has problems e.g. with programs reading standard input. The shell-script "[[http://www.shelldorado.com/scripts/cmds/timeout|timeout]]"
(not to be confused with the command 'timeout')
uses the second approach above.
It has the advantage of working immediately (no need for compiling a program),
but has problems e.g. with programs reading standard input.
Line 54: Line 75:
Just use {{{doalarm}}} or {{{timeout}}} instead. Really. Just use {{{timeout}}} or {{{doalarm}}} instead. Really.

How do I run a command, and have it abort (timeout) after N seconds?

FIRST check whether the command you're running can't be told to timeout directly. The methods described here are "hacky" workarounds to force a command to terminate after a certain time has elapsed. Configuring your command properly is always preferable to the alternatives below.

If you're running a recent version of Ubuntu or a similar Linux distribution, you may already have (or be able to easily install) a standard program named "timeout". Here's an excerpt from a terminal session in Ubuntu 10.04:

$ timeout
The program 'timeout' is currently not installed.  You can install it by typing:
sudo apt-get install timeout
$ sudo apt-get install timeout
 [Installation messages omitted]
$ man timeout
 [Instructions of using 'timeout' should appear]
$ timeout -15 2 top
 [Runs 'top' for two seconds, then terminates the process]
$ two_hours=$((60*60*2)) # Number of seconds in two hours
$ timeout -15 $two_hours really_long_running_program

Beware: by default, 'timeout' issues a SIGKILL (kill -9), which is roughly the same as pulling out the power cord, (leaving no chance for the program to clean up files and such). See ProcessManagement for more information on SIGKILL. You'll probably want to use a kinder, gentler signal such as -15. If you want to send the program a gentle signal, then resort to SIGKILL if the first signal doesn't work, you can create a series of wrapper commands.

If the above methods don't work in your case, here are two C programs that you can download and compile: doalarm, and timeout. Compiling them is beyond the scope of this document, but it should be trivial on GNU/Linux systems, easy on most BSDs, and at least possible (though potentially painful) on anything else.

The primary difference between doalarm and timeout is that doalarm "execs" the program after setting up the alarm, which makes it wonderful in a WrapperScript; while timeout launches the program as a child and then hangs around (both processes exist simultaneously), which gives it the opportunity to send more than one signal if necessary.

If you don't have or don't want one of the above programs, you can use a perl one-liner to set an ALRM and then exec the program you want to run under a time limit. In any case, you must understand what your program does with SIGALRM; programs with periodic updates usually use ALRM for that purpose and update rather than dying when they receive that signal.

doalarm() { perl -e 'alarm shift; exec @ARGV' "$@"; }

doalarm ${NUMBER_OF_SECONDS_BEFORE_ALRMING} program arg arg ...

If you can't or won't install one of these programs (which really should have been included with the basic core Unix utilities 30 years ago!), then the best you can do is an ugly hack like:

   command & pid=$!
   { sleep 10; kill $pid; } &

This will, as you will soon discover, produce quite a mess regardless of whether the timeout condition kicked in or not, if it's run in an interactive shell. Cleaning it up is not something worth my time. Also, it can't be used with any command that requires a foreground terminal, like top.

It is possible to do something similar, but to keep command in the foreground:

   bash -c '(sleep 10; kill $$) & exec command'

kill $$ would kill the shell, except that exec causes the command to take over the shell's PID. It is necessary to use bash -c so that the calling shell isn't replaced; in bash 4, it is possible to use a subshell instead:

   ( cmdpid=$BASHPID; (sleep 10; kill $cmdpid) & exec command )

The shell-script "timeout" (not to be confused with the command 'timeout') uses the second approach above. It has the advantage of working immediately (no need for compiling a program), but has problems e.g. with programs reading standard input.

Just use timeout or doalarm instead. Really.

BashFAQ/068 (last edited 2019-07-25 13:38:08 by GreyCat)