Categories
bash linux unix

How to kill a child process after a given timeout in Bash?

193

I have a bash script that launches a child process that crashes (actually, hangs) from time to time and with no apparent reason (closed source, so there isn’t much I can do about it). As a result, I would like to be able to launch this process for a given amount of time, and kill it if it did not return successfully after a given amount of time.

Is there a simple and robust way to achieve that using bash?

P.S.: tell me if this question is better suited to serverfault or superuser.

2

295

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

If you don’t mind downloading something, use timeout (sudo apt-get install timeout) and use it like: (most Systems have it already installed otherwise use sudo apt-get install coreutils)

timeout 10 ping www.goooooogle.com

If you don’t want to download something, do what timeout does internally:

( cmdpid=$BASHPID; (sleep 10; kill $cmdpid) & exec ping www.goooooogle.com )

In case that you want to do a timeout for longer bash code, use the second option as such:

( cmdpid=$BASHPID; 
    (sleep 10; kill $cmdpid) \
   & while ! ping -w 1 www.goooooogle.com 
     do 
         echo crap; 
     done )

7

  • 11

    Re Ignacio’s reply in case anyone else wonders what I did: the cmdpid=$BASHPID will not take the pid of the calling shell but the (first) subshell that is started by (). The (sleep… thing calls a second subshell within the first subshell to wait 10 secs in the background and kill the first subshell which, after having launched the killer subshell process, proceeds to execute its workload…

    – jamadagni

    Jun 8, 2014 at 1:12


  • 19

    timeout is part of GNU coreutils, so should already be installed in all GNU systems.

    – Sameer

    Feb 13, 2015 at 22:34

  • 1

    @Sameer: Only as of version 8.

    Feb 13, 2015 at 22:37

  • 3

    I am not 100% sure of that, but as far as I know (and I know what my manpage told me) timeout is now part of the coreutils.

    – benaryorg

    May 15, 2015 at 21:04

  • 6

    This command doesn’t ‘finish early’. It will always kill the process at the timeout – but won’t handle the situation where it didn’t timeout.

    – hawkeye

    Sep 15, 2016 at 7:52

34

# Spawn a child process:
(dosmth) & pid=$!
# in the background, sleep for 10 secs then kill that process
(sleep 10 && kill -9 $pid) &

or to get the exit codes as well:

# Spawn a child process:
(dosmth) & pid=$!
# in the background, sleep for 10 secs then kill that process
(sleep 10 && kill -9 $pid) & waiter=$!
# wait on our worker process and return the exitcode
exitcode=$(wait $pid && echo $?)
# kill the waiter subshell, if it still runs
kill -9 $waiter 2>/dev/null
# 0 if we killed the waiter, cause that means the process finished before the waiter
finished_gracefully=$?

4

  • 9

    You shouldn’t use kill -9 before you try signals that a process can process first.

    Mar 2, 2011 at 2:31

  • True, I was going for a fast fix however and just assumed that he wants the process dead instantly because he said it crashes

    – Dan

    Mar 2, 2011 at 15:27

  • 10

    That’s actually a very bad solution. What if dosmth terminates in 2 seconds, another process takes the old pid, and you kill the new one ?

    Jan 3, 2017 at 10:26

  • 2

    PID recycling works by reaching the limit and wrapping around. It is very unlikely for another process to reuse the PID within the remaining 8 seconds, unless if the system is going haywire completely.

    – kittydoor

    Nov 15, 2019 at 14:30

13

sleep 999&
t=$!
sleep 10
kill $t

1

  • It incurs excessive waiting. What if a real command (sleep 999 here) often finishes faster than the imposed sleep (sleep 10)? What if I wish to give it a chance up to 1 minute, 5 minutes? What if I have a bunch of such cases in my script 🙂

    – it3xl

    Mar 9, 2019 at 8:28