I have a bash script that does some parallel processing in a loop. I don't want the parallel process to spike the CPU, so I use a sleep command. Here's a simplified version.
(while true;do sleep 99999;done)&
So I execute the above line from a bash prompt and get something like:
[1] 12345
Where [1]
is the job number and 12345
is the process ID (pid) of the while loop. I do a kill 12345
and get:
[1]+ Terminated ( while true; do sleep 99999; done )
It looks like the entire script was terminated. However, I do a ps aux|grep sleep
and find the sleep command is still going strong but with its own pid! I can kill the sleep
and everything seems fine. However, if I were to kill the sleep first, the while loop starts a new sleep
pid. This is such a surprise to me since the sleep is not parallel to the while loop. The loop itself is a single path of execution.
So I have two questions:
- Why did the sleep command get its own process ID?
- How do I easily kill the while loop and the sleep?
- Sleep gets its own
PID
because it is a process running and just waiting. Trywhich sleep
to see where it is. - You can use
ps -uf
to see the process tree on your system. From there you can determine what thePPID
(parent PID) of the shell (the one running the loop) of the sleep is.
Have you tried doing kill %1
, where 1
is the number you get after launching the command in background?
I did it right now after launching (while true;do sleep 99999;done)&
and it correctly terminated it.
"ps --ppid" selects all processes with the specified parent pid, eg:
$ (while true;do sleep 99999;done)&
[1] 12345
$ ppid=12345 ; kill -9 $ppid $(ps --ppid $ppid -o pid --no-heading)
You can kill the process group.
To find the process group of your process run:
ps --no-headers -o "%r" -p 15864
Then kill the process group using:
kill -- -[PGID]
You can do it all in one command. Let's try it out:
$ (while true;do sleep 99999;done)&
[1] 16151
$ kill -- -$(ps --no-headers -o "%r" -p 16151)
[1]+ Terminated ( while true; do
sleep 99999;
done )
Because "sleep" is a process, not a build-in function or similar
You could do the following:
(while true;do sleep 99999;done)& whilepid=$! kill -- -$whilepid
The above code kills the process group, because the PID is specified as a negative number (e.g. -123 instead of 123). In addition, it uses the variable $!
, which stores the PID of the most recently executed process.
Note: When you execute any process in background on interactive mode (i.e. using the command line prompt) it creates a new process group, which is what is happening to you. That way, it's relatively easy to "kill 'em all", because you just have to kill the whole process group. However, when the same is done within a script, it doesn't create any new group, because all new processes belong to the script PID, even if they are executed in background (jobs control is disabled by default). To enable jobs control in a script, you just have to put the following at the beginning of the script:
#!/bin/bash
set -m
To kill the while
loop and the sleep
using $!
you can also use a trap
signal handler inside the subshell.
(trap 'kill ${!}; exit' TERM; while true; do sleep 99999 & wait ${!}; done)&
kill -TERM ${!}
来源:https://stackoverflow.com/questions/4452299/sleep-in-a-while-loop-gets-its-own-pid