我有一个小脚本来演示我想做的事情
#!/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