我想杀死整个进程树。使用通用脚本语言实现这一目标的最佳方法是什么?我在寻找一个简单的解决办法。
当前回答
使用psutil使用python非常容易做到这一点。只要用pip安装psutil,你就有了一整套进程操作工具:
def killChildren(pid):
parent = psutil.Process(pid)
for child in parent.get_children(True):
if child.is_running():
child.terminate()
其他回答
谢谢你们的智慧。我的脚本在退出时留下了一些子进程,而否定提示使事情变得更容易。我写这个函数是为了在其他脚本中使用:
# kill my group's subprocesses: killGroup
# kill also myself: killGroup -x
# kill another group's subprocesses: killGroup N
# kill that group all: killGroup -x N
# N: PID of the main process (= process group ID).
function killGroup () {
local prid mainpid
case $1 in
-x) [ -n "$2" ] && kill -9 -$2 || kill -9 -$$ ;;
"") mainpid=$$ ;;
*) mainpid=$1 ;;
esac
prid=$(ps ax -o pid,pgid | grep $mainpid)
prid=${prid//$mainpid/}
kill -9 $prid 2>/dev/null
return
}
欢呼。
为了补充Norman Ramsey的答案,如果您想创建一个流程组,可能值得看看setsid。 http://pubs.opengroup.org/onlinepubs/009695399/functions/setsid.html
The setsid() function shall create a new session, if the calling process is not a process group leader. Upon return the calling process shall be the session leader of this new session, shall be the process group leader of a new process group, and shall have no controlling terminal. The process group ID of the calling process shall be set equal to the process ID of the calling process. The calling process shall be the only process in the new process group and the only process in the new session.
我的意思是你可以从头开始创建一个组。我在php中使用这个功能是为了能够在启动整个进程树后杀死它。
这可能是个坏主意。我对你们的评论很感兴趣。
现在是一些聪明的shell编程。
这种解决方案是有代价的,但至少它是基于日常迭代和递归的。通过仔细注意排版命令并在适当的地方将它们转换为声明或本地,可以将其转换为bash。
讨论
当终止一个进程时,必须面对这样的现实:它可能是许多子进程的父进程,而每个子进程又可能是更多子进程的父进程,等等等等。
怎么办呢?
如果有一个函数来测试进程是否有子进程,以及另一个函数来返回父进程的子pid就好了。
这样,游戏就简单多了,因为你可以创建一个循环来遍历pid列表,在杀死它之前检查每个pid是否有子代。如果没有子进程,则直接终止该进程。如果有子函数,递归地调用驱动函数,并将获得父函数子函数pid的函数的结果传递给它。
基本案例操作(流程没有子过程)。
#!/bin/ksh
function killProcess ()
{
typeset -r PID=$1
if [[ ! isProcess $PID ]]
then
echo -e "Process $PID cannot be terminated because it does not exist.\n" 1>&2
return 1
elif [[ kill -s TERM $PID ]] && [[ ! isProcess $PID ]]
then
echo -e "Process $PID was terminated.\n" 1>&2
return 0
elif kill -s KILL $PID
echo -e "Process $PID killed with SIGKILL (9) signal. No time to clean up potential files.\n" 1>&2
return 0
elif isZombie $PID
then
echo -e "Process $PID in the zombie status.\n" 1>&2
return 2
else
echo -e "Process $PID is alive. SIGTERM and SIGKILL had no effect. It is not a zombie.\n" 1>&2
fi
return 3
}
function attemptToKillPid ()
{
typeset -r PID=$1
if killProcess $PID
then
return 0
fi
ppid=$(getParentPid $pid)
echo -e "Process $pid of parent $ppid was not able to be killed.\n" 1>&2
return 1
}
一般案例操作(流程有子)。
function killPidFamily ()
{
typeset -r PROCESSES=$*
typeset -ir NUM_PROCESSES_TO_KILL=$(countLines $PROCESSES)
typeset -i numKilledProcesses=0
typeset ppid
for pid in $PROCESSES
do
pid=$(trim $pid)
if ! hasChildPids $pid
then
attemptToKillPid $pid && (( numKilledProcesses++ ))
else
killPidFamily $(getChildPids $pid) && attemptToKillPid $pid && (( numKilledProcesses++ ))
fi
done
(( numKilledProcesses == NUM_PROCESSES_TO_KILL ))
return $?
}
支持函数库。
#!/bin/ksh
function trim ()
{
echo -n "$1" | tr -d [:space:]
}
function countLines ()
{
typeset -r $LIST=$*
trim $(echo $LIST | wc -l | awk {'print $1'})
}
function getProcesses ()
{
# NOTE: -o pgid below would be $4 in awk.
ps -e -o comm,pid,ppid,pgid,user,ruid,euid,group,rgid,egid,etime,etimes,stat --no-headers
}
function getProcess ()
{
typeset -r PID=$1
ps -p $PID -o comm,pid,ppid,pgid,user,ruid,euid,group,rgid,egid,etime,etimes,stat --no-headers
}
function isProcess ()
{
typeset -r PID=$1
ps -p $PID -o pid --no-headers 1>&2
return $?
}
function getProcessStatus ()
{
typeset -r PID=$1
trim $(ps -p $PID -o stat --no-headers)
}
function isZombie ()
{
typeset -r PID=$1
typeset processStatus
processStatus=$(getProcessStatus $PID)
[[ "$processStatus" == "Z" ]]
return $?
}
function hasChildPids ()
{
typeset -r PPID=$1
echo $(getProcesses) | awk '{print $3}' | sort -n | uniq | grep "^${PPID}$"
return $?
}
function getChildPids ()
{
typeset -r PPID=$1
echo $(getProcesses) | awk '{print $2, $3}' | sort -k 2 | awk "\$2 == $PPID {print \$1}" | sort -n
}
function getParentPid ()
{
typeset -r PID=$1
trim $(echo $(getProcess $PID) | awk '{print $3}')
}
通过这种方式,您可以确定流程树正在从分支被销毁,并向上移动到根。这有助于避免潜在的僵尸和其他不受欢迎的情况。
现在,您已经看到了执行此操作的最昂贵的方法(一次杀死一个进程),研究如何更改此解决方案以使用PGID(进程组ID)。getProcesses()函数已经打印了PGID(在awk中为4美元),所以学习如何使用它,或者不要使用它。
我知道这很老了,但这是我找到的更好的解决方案:
killtree() {
for p in $(pstree -p $1 | grep -o "([[:digit:]]*)" |grep -o "[[:digit:]]*" | tac);do
echo Terminating: $p
kill $p
done
}
我使用了这里描述的方法的一个稍微修改的版本: https://stackoverflow.com/a/5311362/563175
它看起来是这样的:
kill `pstree -p 24901 | sed 's/(/\n(/g' | grep '(' | sed 's/(\(.*\)).*/\1/' | tr "\n" " "`
其中24901是父PID。
它看起来很丑,但它的工作很完美。
推荐文章
- 在Bash中检查变量是否存在于列表中
- 查看PS命令的全部输出
- 确保一次只运行一个shell脚本实例的快速方法
- Linux命令将域名转换为IP
- 如何从命令行在windows中找到mysql数据目录
- 如何在Makefile中设置子进程的环境变量
- 如何让“wc -l”打印没有文件名的行数?
- 有效地测试Linux上的端口是否打开?
- 如何从另一个文件A中删除文件B中出现的行?
- 对以制表符分隔的文件进行排序
- Shell脚本删除超过n天的目录
- 使用sudo时未找到命令
- 当有命令行参数时,如何使用GDB分析程序的核心转储文件?
- 如何检查shell脚本中是否存在命令?
- 如何使用查找命令从列表中查找所有具有扩展名的文件?