12

Possible Duplicate:
Run a command for a specified time and then abort if time exceeds

I was working on a continuos integration build script when a need for such a command arose. Basically put, I need to launch a command with a set time limit for it to run before it gets killed and all of the proceeding commands should immediately be run once this command launches the time -limited process in the background and not wait for it get to be killed. A sort of asynchronous concurency.

Here's what I imagine:

timelimited --limit=10 'somecommand --someoptions'
someothercommand //This gets launched immediately once 'timelimited' is done creating the background process

3 Answers3

11

If timeout and doalarm are not available (e.g., OS X) you can use expect:

timeout() {

    time=$1

    # start the command in a subshell to avoid problem with pipes
    # (spawn accepts one command)
    command="/bin/sh -c \"$2\""

    expect -c "set echo \"-noecho\"; set timeout $time; spawn -noecho $command; expect timeout { exit 1 } eof { exit 0 }"    

    if [ $? = 1 ] ; then
        echo "Timeout after ${time} seconds"
    fi

}
Matteo
  • 9,796
  • 4
  • 51
  • 66
  • This is exactly what I would have suggested but you beat me to the punch. +1 – JZeolla Dec 12 '12 at 15:44
  • This is great because I do actually use OSX, but at this point the command I'm using doesn't require neither piping nor actually waiting for the command to command to finish (it never will, it's a server). I'll still go with sleeping and killing, but nevertheless this will certainly help me out in the future, thanks. – carlossless Dec 12 '12 at 15:51
  • P.S. I forgot how aggravating it is to be unable to upvote great answers... – carlossless Dec 12 '12 at 15:52
9

BASH FAQ entry #68: "How do I run a command, and have it abort (timeout) after N seconds?"

FIRST check whether the command you're running can 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 the command has no native support for stopping after a specified time, then the best alternatives are some external commands called timeout and doalarm. Some Linux distributions offer the tct version of timeout as a package. There is also a GNU version of timeout, included in recent coreutils releases.

3

Another possibility is to do this manually. However, I would only do this if the options Ignacio suggests in his answer are unavailable:

timeout_f () {
    $1 &
    sleep $2
    kill $! # ends somecommand if still running
}

timeout_f 'somecommand --someoptions' 10 && #need 2 &'s
echo "forked.." # happens immediately
goldilocks
  • 87,661
  • 30
  • 204
  • 262
  • 2
    Actually a similar method was specified in the same FAQ entry, and I'll probably be relying on it since I don't want extra binaries hanging around. Thanks. – carlossless Dec 12 '12 at 15:21
  • 1
    The forked process will always wait for the timeout. There also problems with complex commands: e.g., with pipes and redirection. – Matteo Dec 12 '12 at 15:32
  • I'm not sure if the fork waiting for the full timeout is really significant, but I agree that if 'somecommand' is actually this | that | etc then the kill will not work. – goldilocks Dec 12 '12 at 15:41
  • I never specified the need for piping my output. This will do nicely. – carlossless Dec 12 '12 at 15:57
  • 2
    If the command has already timed out by itself, this method runs the risk of killing something that has been assigned the same PID. – Andrew Stubbs Sep 10 '14 at 15:18