我想杀死整个进程树。使用通用脚本语言实现这一目标的最佳方法是什么?我在寻找一个简单的解决办法。
当前回答
brad的答案也是我推荐的,除了如果你使用——ppid选项ps,你可以完全放弃awk。
for child in $(ps -o pid -ax --ppid $PPID) do ....... done
其他回答
我进一步开发了志刚、木uri和固颈的溶液:
#!/bin/bash
if test $# -lt 1 ; then
echo >&2 "usage: kiltree pid (sig)"
exit 1 ;
fi ;
_pid=$1
_sig=${2:-TERM}
# echo >&2 "killtree($_pid) mypid = $$"
# ps axwwf | grep -6 "^[ ]*$_pid " >&2 ;
function _killtree () {
local _children
local _child
local _success
if test $1 -eq $2 ; then # this is killtree - don't commit suicide!
echo >&2 "killtree can´t kill it´s own branch - some processes will survive." ;
return 1 ;
fi ;
# this avoids that children are spawned or disappear.
kill -SIGSTOP $2 ;
_children=$(ps -o pid --no-headers --ppid $2) ;
_success=0
for _child in ${_children}; do
_killtree $1 ${_child} $3 ;
_success=$(($_success+$?)) ;
done ;
if test $_success -eq 0 ; then
kill -$3 $2
fi ;
# when a stopped process is killed, it will linger in the system until it is continued
kill -SIGCONT $2
test $_success -eq 0 ;
return $?
}
_killtree $$ $_pid $_sig
这个版本将避免杀死它的祖先进程——在以前的解决方案中,这会导致大量的子进程。
在确定子列表之前适当地停止进程,这样就不会创建或消失新的子列表。
停止的作业被杀死后,必须继续执行,才能从系统中消失。
如果你知道传递父进程的pid,下面这个shell脚本应该可以工作:
for child in $(ps -o pid,ppid -ax | \
awk "{ if ( \$2 == $pid ) { print \$1 }}")
do
echo "Killing child process $child because ppid = $pid"
kill $child
done
pkill -TERM -P 27888
这将杀死父进程ID为27888的所有进程。
或者更有力:
CPIDS=$(pgrep -P 27888); (sleep 33 && kill -KILL $CPIDS &); kill -TERM $CPIDS
它将kill安排在33秒后,并礼貌地要求进程终止。
请参阅终止所有子代的答案。
老问题,我知道,但所有的回答似乎都叫ps,我不喜欢。
这个基于awc的解决方案不需要递归,只调用ps一次。
awk 'BEGIN {
p=1390
while ("ps -o ppid,pid"|getline) a[$1]=a[$1]" "$2
o=1
while (o==1) {
o=0
split(p, q, " ")
for (i in q) if (a[q[i]]!="") {
p=p""a[q[i]]
o=1
a[q[i]]=""
}
}
system("kill -TERM "p)
}'
或单行:
awk 'BEGIN {p=1390;while ("ps -o ppid,pid"|getline) a[$1]=a[$1]" "$2;o=1;while (o==1) {o=0;split(p, q, " ");for (i in q) {if (a[q[i]]!="") {p=p""a[q[i]];o=1;a[q[i]]=""}}}system("kill -TERM "p)}'
基本思想是,我们建立一个父:子条目的数组(a),然后循环数组为匹配的父元素查找子元素,并将它们添加到我们的父元素列表(p)中。
如果您不想终止顶级进程,则执行
sub(/[0-9]*/, "", p)
就在system()行将它从kill集中移除之前。
请记住,这里存在一个竞争条件,但这对所有的解都是正确的(据我所知)。它做了我所需要的,因为我需要它的脚本不会创建大量短暂的子进程。
对于读者来说,一个练习是将其设置为2次循环:在第一次传递之后,将SIGSTOP发送给p列表中的所有进程,然后再次循环运行ps,在第二次传递之后发送SIGTERM,然后是SIGCONT。如果你不关心美好的结局,那么第二遍可能只是SIGKILL,我想。
在shell脚本中杀死子进程:
很多时候我们需要杀死因为某些原因被挂起或阻塞的子进程。如。FTP连接问题。
有两种方法,
1)为每个子进程创建独立的新父进程,该父进程将在超时时监视并终止子进程。
创建test.sh,如下所示:
#!/bin/bash
declare -a CMDs=("AAA" "BBB" "CCC" "DDD")
for CMD in ${CMDs[*]}; do
(sleep 10 & PID=$!; echo "Started $CMD => $PID"; sleep 5; echo "Killing $CMD => $PID"; kill $PID; echo "$CMD Completed.") &
done
exit;
使用以下命令查看其他终端中名称为“test”的进程。
watch -n1 'ps x -o "%p %r %c" | grep "test" '
上面的脚本将创建4个新的子进程和它们的父进程。每个子进程将运行10秒。但是一旦达到5秒的超时,它们各自的父进程将终止这些子进程。 所以孩子将无法完成执行(10秒)。 围绕这些时间(切换10和5)来玩游戏,看看另一种行为。在这种情况下,child将在达到10秒超时之前在5秒内完成执行。
2)让当前父进程监视并在超时时终止子进程。这不会创建单独的父节点来监视每个子节点。此外,您还可以在同一个父进程中正确地管理所有子进程。
创建test.sh,如下所示:
#!/bin/bash
declare -A CPIDs;
declare -a CMDs=("AAA" "BBB" "CCC" "DDD")
CMD_TIME=15;
for CMD in ${CMDs[*]}; do
(echo "Started..$CMD"; sleep $CMD_TIME; echo "$CMD Done";) &
CPIDs[$!]="$RN";
sleep 1;
done
GPID=$(ps -o pgid= $$);
CNT_TIME_OUT=10;
CNT=0;
while (true); do
declare -A TMP_CPIDs;
for PID in "${!CPIDs[@]}"; do
echo "Checking "${CPIDs[$PID]}"=>"$PID;
if ps -p $PID > /dev/null ; then
echo "-->"${CPIDs[$PID]}"=>"$PID" is running..";
TMP_CPIDs[$PID]=${CPIDs[$PID]};
else
echo "-->"${CPIDs[$PID]}"=>"$PID" is completed.";
fi
done
if [ ${#TMP_CPIDs[@]} == 0 ]; then
echo "All commands completed.";
break;
else
unset CPIDs;
declare -A CPIDs;
for PID in "${!TMP_CPIDs[@]}"; do
CPIDs[$PID]=${TMP_CPIDs[$PID]};
done
unset TMP_CPIDs;
if [ $CNT -gt $CNT_TIME_OUT ]; then
echo ${CPIDs[@]}"PIDs not reponding. Timeout reached $CNT sec. killing all childern with GPID $GPID..";
kill -- -$GPID;
fi
fi
CNT=$((CNT+1));
echo "waiting since $b secs..";
sleep 1;
done
exit;
使用以下命令查看其他终端中名称为“test”的进程。
watch -n1 'ps x -o "%p %r %c" | grep "test" '
Above script will create 4 new child processes. We are storing pids of all child process and looping over them to check if they are finished their execution or still running. Child process will execution till CMD_TIME time. But if CNT_TIME_OUT timeout reach , All children will get killed by parent process. You can switch timing and play around with script to see behavior. One drawback of this approach is , it is using group id for killing all child tree. But parent process itself belong to same group so it will also get killed.
如果不希望终止父进程,可能需要为父进程分配其他组id。
更多细节可以在这里找到,
在shell脚本中杀死子进程
推荐文章
- 在Bash中检查变量是否存在于列表中
- 查看PS命令的全部输出
- 确保一次只运行一个shell脚本实例的快速方法
- Linux命令将域名转换为IP
- 如何从命令行在windows中找到mysql数据目录
- 如何在Makefile中设置子进程的环境变量
- 如何让“wc -l”打印没有文件名的行数?
- 有效地测试Linux上的端口是否打开?
- 如何从另一个文件A中删除文件B中出现的行?
- 对以制表符分隔的文件进行排序
- Shell脚本删除超过n天的目录
- 使用sudo时未找到命令
- 当有命令行参数时,如何使用GDB分析程序的核心转储文件?
- 如何检查shell脚本中是否存在命令?
- 如何使用查找命令从列表中查找所有具有扩展名的文件?