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

前端 未结 8 1721
青春惊慌失措
青春惊慌失措 2020-11-22 15:24

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

8条回答
  •  隐瞒了意图╮
    2020-11-22 15:56

    Here's the third answer I've submitted here. This one handles signal interrupts and cleans up background processes when SIGINT is received. It uses the $BASHPID and exec trick used in the top answer to get the PID of a process (in this case $$ in a sh invocation). It uses a FIFO to communicate with a subshell that is responsible for killing and cleanup. (This is like the pipe in my second answer, but having a named pipe means that the signal handler can write into it too.)

    run_with_timeout ()
    {
      t=$1 ; shift
    
      trap cleanup 2
    
      F=$$.fifo ; rm -f $F ; mkfifo $F
    
      # first, run main process in background
      "$@" & pid=$!
    
      # sleeper process to time out
      ( sh -c "echo \$\$ >$F ; exec sleep $t" ; echo timeout >$F ) &
      read sleeper <$F
    
      # control shell. read from fifo.
      # final input is "finished".  after that
      # we clean up.  we can get a timeout or a
      # signal first.
      ( exec 0<$F
        while : ; do
          read input
          case $input in
            finished)
              test $sleeper != 0 && kill $sleeper
              rm -f $F
              exit 0
              ;;
            timeout)
              test $pid != 0 && kill $pid
              sleeper=0
              ;;
            signal)
              test $pid != 0 && kill $pid
              ;;
          esac
        done
      ) &
    
      # wait for process to end
      wait $pid
      status=$?
      echo finished >$F
      return $status
    }
    
    cleanup ()
    {
      echo signal >$$.fifo
    }
    

    I've tried to avoid race conditions as far as I can. However, one source of error I couldn't remove is when the process ends near the same time as the timeout. For example, run_with_timeout 2 sleep 2 or run_with_timeout 0 sleep 0. For me, the latter gives an error:

    timeout.sh: line 250: kill: (23248) - No such process
    

    as it is trying to kill a process that has already exited by itself.

提交回复
热议问题