Differences between revisions 1 and 14 (spanning 13 versions)
Revision 1 as of 2007-05-03 00:03:05
Size: 1284
Editor: redondos
Comment:
Revision 14 as of 2010-04-07 20:02:52
Size: 3299
Editor: GreyCat
Comment:
Deletions are marked like this. Additions are marked like this.
Line 1: Line 1:
[[Anchor(faq68)]] <<Anchor(faq68)>>
Line 3: Line 3:
There are two C programs that can do this: [[http://pilcrow.madison.wi.us/|doalarm]], and [[http://www.porcupine.org/forensics/tct.html|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. GNU coreutils also added an implementation of `timeout` in 2008 (version number unknown).
Line 4: Line 8:
There are two C programs that can do this: [http://pilcrow.madison.wi.us/ doalarm], and [http://www.porcupine.org/forensics/tct.html timeout]. (Compiling them is beyond the scope of this document; suffice to say, it'll be trivial on GNU/Linux systems, easy on most BSDs, and painful on anything else....) 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.
Line 6: Line 18:
If you don't have or don't want one of the above two 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. 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.
Line 9: Line 23:
function doalarm () { perl -e 'alarm shift; exec @ARGV' "$@" ; } doalarm() { perl -e 'alarm shift; exec @ARGV' "$@"; }
Line 17: Line 31:
   command & pid=$!; { sleep 10 && kill $pid; } &    command & pid=$!
  
{ sleep 10; kill $pid; } &
Line 20: Line 35:
This will, as you will soon discover, produce quite a mess regardless of whether the timeout condition kicked in or not. Cleaning it up is not something worth my time -- just use {{{doalarm}}} or {{{timeout}}} instead. Really. 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 "[[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.

Just use {{{doalarm}}} or {{{timeout}}} instead. Really.

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

There are two C programs that can do this: 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. GNU coreutils also added an implementation of timeout in 2008 (version number unknown).

In early 2010, a patch was submitted to add a proper "--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.

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" 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 doalarm or timeout instead. Really.

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