且构网

分享程序员开发的那些事...
且构网 - 分享程序员编程开发的那些事

你如何杀死所有的子进程不杀死父母

更新时间:2022-11-03 22:10:05

要扩大埃德治愈的评论:

在父进程,陷阱SIGTERM,如:

陷阱回声收到SIGTERMSIGTERM

然后,当你要终止所有的子进程,在主脚本做

杀-s SIGTERM 0

家长也会收到SIGTERM,但是这并不重要,因为它是被困的信号。

您也可能会发现,设置退出陷阱的子进程,使他们能够清理,当他们收到SIGTERM。

您的可能的发送子进程SIGKILL,但是这是一个有点残酷,孩子进程将不会有机会做任何清理。


修改

下面是一些脚本,说明如何父母脚本可以单独杀害其子,而不是使用EN -s SIGTERM集体杀0

traptest

 #!/斌/庆典#陷阱测试
#写的PM 2Ring 2014年10月23日MYNAME = $(基名$ 0)
孩子= sleeploop
延迟= $ {1:-5}
循环= $ {2:-5}SIG = SIGTERM
#SIG = SIGKILL
#SIG = SIGINT#杀=假signal_children()
{
    杀死= TRUE
    在IPID$ {的PID [@]}
    做
        回声发送$ SIG至$ IPID
        杀-s $ SIG $ IPID
    DONE
}set_INT_trap()
{
    味精=回声-e \\\\ n $ MYNAME收到^ C,送$ SIG儿童\\
    陷阱$味精; signal_childrenSIGINT
}陷阱回声\\拜拜从$ MYNAME \\EXIT的PID =()
因为我在A B C;做
    回声运行$子$ I $延迟......
    ./$child $ I $延迟和放大器;
    PID = $!
#回声-e$儿童$我PID = $ PID \\ n
    的PID + =($ PID)
DONE
#回声的所有孩子的PID:$ {PID的[@]}回声$ MYNAME PID = $$
回声; PS;回声set_INT_trap $ SIG
陷阱回声$ MYNAME收到SIGTERM; signal_childrenSIGTERM回声$ MYNAME睡觉......
睡18安培;
等待$!
回声$ MYNAME醒[[$打死=真]!]放大器;&安培; {回声$ MYNAME发送$ SIG signal_children; }回声$ MYNAME完成

sleeploop

 #!/斌/庆典#为traptest孩子脚本
#写的PM 2Ring 2014年10月23日MYNAME =$(基名$ 0)$ 1
延迟= $ 16
循环= $ {3} -5set_trap()
{
    SIG = $ 1
    陷阱回声-e'\\ n $ MYNAME收$ SIG信号';退出0$ SIG
}陷阱回声\\拜拜从$ MYNAME \\EXIT
set_trap SIGTERM
#set_trap SIGINT#选择睡眠模式
如果假
然后
    回声利用前景睡眠$ MYNAME
    睡觉()
    {
        睡眠延迟$
    }
其他
    回声使用后台睡眠$ MYNAME
    睡觉()
    {
        休眠$延迟&放大器;
        等待$!
    }
科幻#TIME打盹:)
为((i = 0; I<循环;我++));

    回声$ I:$ MYNAME睡$延时
    睡觉
DONE回声$ MYNAME正常终止

这甚至可以,如果你想管 traptest 的输出,例如尝试

{./traptest;回声>和2退出code $ ?; } |猫-n

I have a script which runs a background process at the beginning, then towards the end needs to stop that background process and its children, THEN do some other tasks etc then return an error code if necessary. How do I do this? I have seen several examples of how to kill the whole tree including the parent process (eg kill 0) but I want the main script to continue running and return the right error code. E.g.:

./some_process_with_child_processes &
./do_stuff
kill $! # doesnt kill child processes!
./do_other_stuff
exit 5

To expand on Ed Heal's comment:

In the parent process, trap SIGTERM, eg

trap "echo received sigterm" SIGTERM

Then, when you want to terminate all the child processes, in the main script do

kill -s SIGTERM 0

The parent will also receive SIGTERM, but that doesn't matter, since it's trapped that signal.

You may also find it useful to set a trap for EXIT in the child processes so they can clean up when they receive SIGTERM.

You could send the child processes SIGKILL, but that's a bit brutal, and the child processes won't have a chance to do any clean up.


edit

Here are some scripts that illustrate how a parent script can kill its children individually, rather than en masse using kill -s SIGTERM 0.

traptest

#!/bin/bash

# trap test
# Written by PM 2Ring 2014.10.23

myname=$(basename "$0")
child=sleeploop
delay=${1:-5}
loops=${2:-5}

sig=SIGTERM 
# sig=SIGKILL 
# sig=SIGINT 

# killed=False

signal_children()
{
    killed=True
    for ipid in "${pids[@]}"
    do 
        echo "Sending $sig to $ipid"
        kill -s $sig $ipid
    done
}

set_INT_trap()
{
    msg="echo -e \"\n$myname received ^C, sending $sig to children\""
    trap "$msg; signal_children" SIGINT
}

trap "echo \"bye from $myname\"" EXIT

pids=()
for i in A B C;do 
    echo "running $child $i $delay ..."
    ./$child $i $delay  &
    pid=$!
#     echo -e "$child$i PID = $pid\n"
    pids+=($pid)
done
# echo "all child PIDs: ${pids[@]}"

echo "$myname PID = $$"
echo; ps; echo

set_INT_trap $sig
trap "echo $myname Received SIGTERM; signal_children" SIGTERM

echo "$myname sleeping..."
sleep 18 &
wait $!
echo "$myname awake"

[[ $killed != True ]] && { echo "$myname sending $sig"; signal_children; }

echo "$myname finished"

sleeploop

#!/bin/bash

# child script for traptest
# Written by PM 2Ring 2014.10.23

myname="$(basename "$0")$1"
delay=$2
loops=${3:-5}

set_trap()
{
    sig=$1
    trap "echo -e '\n$myname received $sig signal';exit 0" $sig
}

trap "echo \"bye from $myname\"" EXIT
set_trap SIGTERM
# set_trap SIGINT

#Select sleep mode
if false
then
    echo "$myname using foreground sleep"
    Sleep()
    {
        sleep $delay
    }
else
    echo "$myname using background sleep"
    Sleep()
    {
        sleep "$delay" &
        wait $!
    }
fi

#Time to snooze :)
for ((i=0; i<loops; i++));
do
    echo "$i: $myname sleeping for $delay"
    Sleep
done

echo "$myname terminated normally"

This even works if you want to pipe the output of traptest, eg try

{ ./traptest; echo >&2 exitcode $?; } | cat -n