# 2020-10-05 #「Linux」- 如何结束进程?

    科技2022-08-22  112

    问题描述

    起初是为了 systemd 的 service 单元文件中的 ExecStop 指令才整理的这篇文章,后来看 systemd 的文档说执行 stop 时,执行完 ExecStop 指令后,未结束的进程会由 systemd 来结束。

    本来没有什么可写的,直接使用 kill(1) 命令来结束进程就可以了。但是,由几个有意思的问题: 1)如何结束一个进程的全部子进程? 2)如何结束一个进程及其子进程? 3)我想结束某个组或某个用户的进程该怎么做?

    通常结束一个进程的时候,它的子进程不一定会退出,子进程可能会变成“孤儿进程”:

     

    孤儿进程:一个父进程退出,而它的一个或多个子进程还在运行,那么那些子进程将成为孤儿进程。孤儿进程将被init进程(进程号为1)所收养,并由init进程对它们完成状态收集工作。

     

    所以有的时候,我们就需要结束某个进程以及它的子进程。

    我们先从基础的开始吧。

    根据进程号,结束进程

    在 Linux 中,想要结束一个进程可以直接使用kill(1)命令并指定进程ID(PID)就可以了。比如,我们想要结束PID为3219的进程,只需要执行如下命令:

    kill -9 3219 kill -KILL 3219

    上面的两个命令是100%完全等价的,只是形式不一样而已,具体参考 kill(1) 手册。唯一需要注意:在 Shell 中,内建的kill命令,参考「注意事项」部分。

    根据父进程号,结束子进程

    如果想要结束进程所有的子进程的ID,可以使用pkill(1)命令。比如,我们想要结束PID为3219的进程的子进程,只需要执行如下命令:

    pkill -KILL -P 3219

    该命令可以结束某个进程的全部子进程。

    结束进程及其全部子进程

    方法一、使用进程组

    可以使用kill(1)命令或者pkill(1)命令,配合“进程组”的ID来结束进程。比如进程组的ID为4536如下:

    kill -KILL -4536 pkill -KILL -g 4536

    注意,这里的“4536”是“进程组”的ID,不是进程ID,不是父进程ID,也不是进程所属组的ID,有一个名词叫做“进程组”(Process Group)。可以用下面的命令来体会组ID(gid)、进程组ID(pgid)及其他ID之间的差异,注意观察各个字段的输出:

    ps -o pid,ppid,pgid,gid,sess,cmd -U root

    上面的ID分别是进程ID、父进程ID、进程组的ID、进程的组ID、会话、命令。

    方法二、使用一点 Shell 命令

    但是下面的这条命令应该是一劳永逸了:

    kill -KILL $(ps -o pid= --pid 6234 --ppid 6234)

    上述命令结束进程ID为6234的全部进程以及它的子进程。

    根据GID结束进程

    如果要结束属于某个组的进程,可以使用pkill(1)命令。如下,结束GID为34的全部进程:

    pkill -KILL -G 34 pkill -KILL -G mail

    结束GID为34的组的全部进程。代表,GID的数值34也可以使组名来代替,如上的两个命令是等价的,因为GID为34的组名为“mail”。

    根据终端来结束进程

    可以使用pkill(1)命令,根据/dev/下的终端来结束进程:

    pkill -9 -t 'pts/4'

    结束终端为“pts/4”的进程,不需要“/dev/“前缀。但这也仅仅是适用于关联终端的进程。有些后台进程没有与终端关联。

    根据进程名来结束进程

    可以使用 pkill 命令,配合进程名来结束进程。如下示例,结束进程名为“xterm”的进程:

    pkill -KILL -x "xterm"

    根据会话来结束进程

    依旧是使用 pkill 命令来结束进程。如下示例,结束会话号为 1256 的全部进程:

    pkill -KILL -s 1256

    结束僵尸进程(Kill Zombie Processes)

    Alternative way to kill a zombie process - Unix & Linux Stack Exchange

    kill -CHLD <PPID>

    注意事项

    内建于 Shell 的 kill 命令

    在 Shell 中(比如 BASH),它可能内建 kill 命令。可以使用 type -a kill 命令进行查看:

    # type -a kill kill is a shell builtin kill is /bin/kill

    如果输出的第一行为”kill is a shell builtin“,这就表示你所执行的kill命令Shell内建的kill命令,而不是util-linux包中的kill(1)命令。而Shell内建kill命令的用法需要查看你所使用的Shell的文档,这里不再展开说明。如果你要使用util-linux软件包中的kill(1)命令,可以使用“绝对路径”(/bin/kill ...)或者“env”(env kill ...)来执行。还有一点要注意procp-ng软件包也提供了kill命令,所以到底使用的哪个包里的kill命令呢?这个需要你自己去判断了,但是看手册肯定不会错的。这些kill命令的用法大同小异,因此也没有什么可以担心的。

    关于-KILL(-9)信号

    如果您关心数据完整性,请不要使用-KILL(-9)信号,会直接杀死进程。所有理智的进程都应该会处理-TERM(-15)信号,通知进程结束自身。

    参考文献

     

    K4NZ / 如何结束进程?孤儿进程与僵尸进程(已经不是第一次参考这篇文章了)Ways to kill parent and child processes in one commandDisabling column names in ps output

     

    Processed: 0.019, SQL: 9