问题
I am having a really hard time understanding the behaviour of zenity --progress --auto-kill
. It appears to not kill its parent process' subprocesses but to detach them somehow.
Consider the following shell script long-live-the-subshell.sh
:
#!/bin/sh
(
echo sleeping...>&2;
sleep 5;
echo woke up >&2
) | zenity --progress --auto-close --auto-kill
To reproduce the mentioned behaviour:
- execute the script
sh long-live-the-subshell.sh
- click Cancel on the progress bar
- wait another 5 seconds
- see that
woke up
is output to the terminal
Example output:
> sh long-live-the-subshell.sh
sleeping...
Hangup
> woke up
The Hangup
happens when you click Cancel. You then get your prompt back. However, after the sleep 5
finishes, woke up
is output to the terminal.
ps jf
immediately after running the script:
PPID PID PGID SID TTY TPGID STAT UID TIME COMMAND
20806 20825 20825 20825 pts/7 2391 Ss 1000 0:01 -zsh
20825 2391 2391 20825 pts/7 2391 S+ 1000 0:00 \_ sh test.sh
2391 2392 2391 20825 pts/7 2391 S+ 1000 0:00 \_ sh test.sh
2392 2394 2391 20825 pts/7 2391 S+ 1000 0:00 | \_ sleep 5
2391 2393 2391 20825 pts/7 2391 Sl+ 1000 0:00 \_ zenity --progress --auto-close --auto-kill
ps jf
immediately after clicking Cancel:
PPID PID PGID SID TTY TPGID STAT UID TIME COMMAND
1179 2392 2391 20825 pts/7 20825 S 1000 0:00 sh test.sh
2392 2394 2391 20825 pts/7 20825 S 1000 0:00 \_ sleep 5
Apparently, zenity
kills its PPID (2391
in this case) but somehow both of the other children of 2391
(2392
and its only child sleep
command 2394
) stay alive. Why? Shouldn't a kill -1 2391
(which is obviously what zenity does) kill also the children of 2391
?
回答1:
I have just found a nice way that works for me, and I think should work for most cases, using bash.
The idea is that you run Zenity in a container with a trap: when zenity --auto-kill
sends a SIGHUP to the parent process, the parent process sends a SIGHUP to all processes in the same process group before dying. So the key is calling Zenity like this:
{
trap 'pkill -g 0' HUP
zenity --progress --auto-kill
}
In the code below I show how I used this with a named pipe feeding Zenity, which makes things easier if you want the running process to produce data on standard output.
#! /bin/bash
...
zenityfifo=/tmp/zenityfifo$$
trap "rm --force $zenityfifo" EXIT
if [ -x /usr/bin/zenity -a "$DISPLAY" ]; then
rm --force $zenityfifo
mkfifo $zenityfifo
## The while loop is needed to keep the pipe blocking on read
while read p < $zenityfifo; do echo $p; done | {
trap 'pkill -g 0' HUP
zenity --progress --title="resync" --auto-close --auto-kill
} &
fi
while ...; do
...
echo ... > $zenityfifo
done
来源:https://stackoverflow.com/questions/44607387/zenity-auto-kill-killing-a-subshell-does-not-kill-its-child-processes