杀死子管道进程的父进程

杀死子管道进程的父进程

我有一个小脚本来演示我想做的事情

#!/bin/bash
> z
tail -f z | grep 'd' &
echo $!

给出$!grep 进程的 PID。我希望能够在终止 grep 进程的同时终止 tail 进程。这样做kill "pid of grep"不会杀死尾部进程。也没有killall grep。我可以使用killall tail,但我认为这会很危险。

答案1

将命令用括号括起来:

( tail -f z | grep 'd' ) &
kill -- -$!

这将杀死整个子进程。

这里,通过指定要杀死的负PID,我们杀死了整个进程组。看man 1 kill

负PID值可用于选择整个过程组;请参阅 ps 命令输出中的 PGID 列。

或者man 2 kill

如果pid小于-1,则将sig发送到进程组中ID为-pid的每个进程。

然而,kill -PID只会起作用如果启用作业控制in bash(交互式 shell 的默认设置)。否则,您的子进程将没有专用的进程组,并且终止命令将失败并显示kill: (-PID) - No such process

要解决此问题,请激活bash( set -m) 中的作业控制,或使用pkill -P $!

答案2

我尝试过这个,但它对我不起作用

( tail -f z | grep 'd' ) &
kill -- -$!

我只是使用命名管道而不是无名管道

rm -f tailfifo; mkfifo tailfifo
tail -n 0 -f mylog.log >tailfifo &
TAIL_PID=$!
grep --line-buffered someword <tailfifo >outputfile &
GREP_PID=$!
# .. ..
kill $TAIL_PID
kill $GREP_PID

答案3

希恩的回答 不适用于非交互式 sh (dash) 。使用()不会创建进程组,因此sh -c '(sleep 6m | sleep 8m) & kill -- -$!'不起作用。

但是,您仍然可以使用ps --no-headers --format pgid:1 $! 查找整个管道的 pgid 并将其杀死。

sleep 6m | sleep 8m &
pgid=`ps -ho $!`
kill -- -$pgid

而且,()在管道中使用会导致shell无法创建进程组。

pgid() {
    ps --no-headers --format pgid:1 $1
}

while true
do nc $ip $port
done | str2str -out tcpsvr://:5566 &
echo `pgid $!` == $$
wait

相关内容