「Linux」- 如何结束进程?

更新日期:2020年03月06日

起初是为了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命令,参考「注意事项」部分。

局限性
没有什么局限性,就结束单个进程能有什么局限性。

结束子进程:根据PPID

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

# pkill -KILL -P 3219

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

局限性
没有什么局限性,就结束单个进程能有什么局限性。

结束进程及其全部子进程

#1 使用进程组

可以使用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、会话、命令。

#2 使用一点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命令,配合进程名来结束进程:

# pkill -KILL -x "xterm"

结束进程名为“xterm”的进程。

根据会话来结束进程

依旧是使用pkill命令来结束进程:

# pkill -KILL -s 1256

上述命令将会话ID为1256的进程结束调。

注意事项

到处都是的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)信号,通知进程结束自身。

参考文献


ToC

结束进程:根据进程号

结束子进程:根据PPID

结束进程及其全部子进程

#1 使用进程组

#2 使用一点Shell命令

根据GID结束进程

根据终端来结束进程

根据进程名来结束进程

根据会话来结束进程

注意事项

到处都是的kill命令

关于-KILL(-9)信号

参考文献