6

If I use a combination to kill a child process in batch and wait for it's termination, I use

kill $PID
wait $PID

If the process exists immediately, the wait will fail, since the pid is not running anymore.

Is there a way to combine both statements to a single one to aviod the error?

Edit: The process I have to kill uses a tempfile; thus it has to be closed (and not just signaled to close) to start it again. Checking the return value of kill does not help, since this indicates whether the signal was delivered successfully.

Jahid
  • 21,542
  • 10
  • 90
  • 108
urzeit
  • 2,863
  • 20
  • 36
  • 3
    What is the purpose of your `wait`? What do you really want to do? – Jean-Baptiste Yunès Jun 10 '15 at 08:14
  • You know that `kill` already returns a code that you can check to see if it was successful, right? ;-) If you want to kill the process no matter what, you can try `kill -9 $PID`. – Peque Jun 10 '15 at 08:21
  • 1
    If you want to execute commands sequentially it is a good idea to check out [$$ ; || etc.](http://www.gnu.org/software/bash/manual/bashref.html#Lists) Otherwise, maybe a while loop can help you out. `while [ $(kill ${PID}) ]; do "nothing" ;done` – Sigve Karolius Jun 10 '15 at 08:26
  • 2
    @SigveKarolius Wrong. `kill $PID` returns immediately regardless of whether the job is actually killed or not. Just write a simply script that traps and ignores `SIGINT`, and see how `kill` works (it will return `0`, although the job is not killed). – 4ae1e1 Jun 10 '15 at 08:41
  • @Jean-BaptisteYunès: See edit. – urzeit Jun 10 '15 at 08:45
  • Then I'm afraid you need to find something else... Why not use some polling to *wait* until some event (as the creation of a file named `closeDone` make by the process)? Or make the process sleep for a while before exiting? Make the script sleep for a while after killing? Note that the latests are almost *tricky*. Do you have control over the source code of the process? – Jean-Baptiste Yunès Jun 10 '15 at 09:01
  • 2
    Regarding what you want to do: why don't you use a unique tempfile each time? (Check out `mktemp`.) – 4ae1e1 Jun 10 '15 at 09:02
  • 1
    Also, a not-so-safe way is to simply check whether the PID still exists. – 4ae1e1 Jun 10 '15 at 09:03
  • Sorry about my ignorance of how kill works. Let me try some more ignorance: maybe you can use `ps` to check the status of the process after using `kill`? – Sigve Karolius Jun 10 '15 at 09:15
  • You can use `while kill $PID 2>/dev/null; do sleep 0.01; done`. After PID exits, kill will fail & loop will break. There is a possibility of race condition though - another process may start in that 0.01 second, which can possibly have same PID... – anishsane Jun 10 '15 at 09:54
  • @4ae1e1: Because the binary I have to kill can not be changed. – urzeit Jun 10 '15 at 12:25
  • @SigveKarolius: I don't want to do this, because the pid might be used again in the meantime by another process. Then, it'd be better to use wait, since this guarantees that the process is at least a child process. – urzeit Jun 10 '15 at 12:27

3 Answers3

8

It's not a one-liner, but would you be willing to consider spawning off the kill with a short sleep, then waiting in the main thread? Something like:

(sleep 1; kill $PID) &
wait $PID

This addresses your concern of the PID being reused after the kill. Even if you reduce the sleep to something much smaller, it introduces idle time, but it should at least ensure that you wait on the correct process.

bto
  • 1,619
  • 15
  • 23
2

Effectively, there is not an atomic kill and wait since they are two separate system calls. Some wrapper must be written to execute both functions.

If you do not care about the status,

kill $PID 2> /dev/null
wait $PID 2> /dev/null

If you do care about the status, but do not want an error message, do something like

if ! kill $PID 2> /dev/null; then
    # Error logic here
fi

The fancy way for both is a function

killAndWait() {
    kill $1 2> /dev/null && wait $1 2> /dev/null
}

Then, do

killAndWait $PID
RTLinuxSW
  • 822
  • 5
  • 9
  • They may be two separate syscalls, but at the syscall level, `wait()` is a valid and expected thing to do on a process that you've just killed. I can't speak to what `kill` and `wait`'s semantics are in Bash, though. – Maxpm May 12 '21 at 04:44
0
kill $PID
wait $PID

If the process exists immediately, the wait will fail, since the pid is not running anymore.

As long as $PID really points to a child process of the shell, I don't think wait will fail. I don't see an error with your code.

Experiment:

bash-3.2$ while : ; do ls > /dev/null ; done &
[1] 44908
bash-3.2$ kill 44908
[1]+  Terminated: [...]
bash-3.2$ wait 44908
bash-3.2$ echo $?
143

143 is the return code for SIGTERM, so the kill worked as expected, and Bash could wait for the dead process.

Maxpm
  • 24,113
  • 33
  • 111
  • 170