Kill:结束所有命令的命令
Linux 是一个强大的操作系统。凭借其按需分页内存管理和交换文件机制,它允许您启动任意数量的进程。当然,这个数字受限于整体系统内存容量(物理内存加上交换空间)以及您的 CPU 执行您所请求的所有任务的能力。启动进程很容易,当事情慢到爬行时,停止它们也同样容易。
Linux 的 kill 命令是两个命令之一,当您厌倦等待进程终止时,它将满足您的需求。用我 1992 年的 Linux 程序员手册的话来说,您可以使用它以极大的偏见终止进程。您只需要知道一个名为进程 PID 的数字。请注意,kill 并非总是终止另一个进程。本质上,kill 向指定进程发送一个信号。如果该信号未被进程捕获和处理(并非所有信号都可以被捕获和处理),则进程将被终止。进程使用的所有资源都将被释放,供其他正在运行的进程使用。
什么是进程、PID 和信号?如何发现它们?
回想一下,Linux 是一个多任务操作系统。当 Linux 启动时,它会启动一个名为 init 的程序,该程序又会启动其他程序。其中许多是后台任务,例如 update,它定期将数据刷新到磁盘。另一个例子是 getty,它监视串行端口是否有活动迹象。一个更明显的例子是您用来执行有用工作的 shell。它在前台运行,这意味着它等待您的击键。系统上运行的每个程序的每个副本都称为进程。
正如美国政府颁发社会安全号码(我们在加拿大使用社会保险号码)来唯一标识每个人一样,Linux 为每个进程分配一个唯一的号码作为标识符。这个数字被称为进程 ID 或 PID。
当一个进程启动时,它被赋予下一个可用的 PID,当它终止时,它的 PID 被释放以供最终重用。要确定属于您的任何进程的 PID,请在提示符下输入 ps。ps 命令将为您的每个进程打印一行,其中包含进程的 PID、进程已使用的时间以及启动进程的命令。ps 的输出看起来像
PID TT STAT TIME COMMAND 6651 p0 S 0:01 -ksh<\n> 6661 p1 S 0:00 -ksh 6738 p2 S 0:00 -ksh 6746 p2 S 0:00 wheel 6747 p2 S 0:00 wheel 7002 p0 S 0:01 elm 7193 p1 R 0:00 ps
信号是一种进程通信形式。因为它们可能来自另一个进程、内核或进程本身,所以它们可能更像是程序运行时发生的事件。一个粗略的例子可能是我们大多数人在早年上学时记得的铃声;当铃声响起时,我们的反应是从玩耍的孩子转变为勤奋的学生。
我们将在下面使用的信号是终止信号 SIGTERM、中断信号 SIGINT 和 kill 信号 SIGKILL。这些信号通常是因为另一个进程发送了它们而发生的。您可能已经使用过其中一个;键入 ctrl-c 会将中断信号 SIGINT 发送到您当前的前台进程。其他信号——例如 SIGPIPE,它被发送到写入断开管道的进程——通常来自内核。大约有 30 个信号,所有信号都可以通过数字或名称来引用,但数字在平台之间会发生变化,并且某些信号在某些平台上不可用。信号的完整列表可以在 signal(7) 手册页中找到;输入 man 7 signal 查看它,或输入 kill -1 获取此列表的简短版本。
对于每个信号,都有一个默认操作,几乎所有操作都会终止进程。对于大多数信号,程序可以指定另一个操作——这称为捕获 或 处理 信号——或者可以指定不发生任何操作,这称为忽略 信号。信号 SIGKILL 无法被捕获或忽略;它总是终止进程。
例如,假设您使用 cat 列出大型文本文件,而没有首先确定文件的大小。与其观看数百甚至数千行滚动得太快而无法阅读,不如通过按 Ctrl-c 向 cat 进程发送中断信号。幸运的是,cat 没有被编程为捕获 SIGINT,并且 cat 进程立即终止。
假设我们不小心在后台启动了 cat;Ctrl-c 将无效,因为信号不会到达 cat 进程。因此,我们需要以其他方式向其发送信号。使用命令 kill,您可以向您拥有的任何进程发送任何信号。该命令的语法是
kill -SIGNAL
如果在 kill 命令行上未指定信号,则发送终止信号 SIGTERM(默认)。这通常会终止相关进程。如果它未能做到这一点——即,SIGTERM 被捕获或忽略——您可以发送信号 SIGKILL,这将始终终止进程。
因此,我们可能会执行以下操作来终止失控的 cat 进程命令。首先确定 PID
$ ps PID TT STAT TIME COMMAND 2037 p0 S 0:01 cat
现在,kill 进程 2037,它是 cat 进程
kill 20371如果 cat 已被编写为捕获 SIGTERM,我们将不得不使用无法捕获或忽略的信号。
kill -SIGKILL 20371除了终止错误进程外,kill 还可以用于通知进程某些事物的状态已更改。例如,假设您正在编写一个程序,并且希望它在发生某些外部事件时更改其操作模式。通过在您的程序中编码所谓的“中断处理程序”,您可以让它捕获任意数量对您有意义的信号。特别是,您可以选择 SIGUSR1 或 SIGUSR2,它们是非特定的。通过发送您选择的信号,您可以让您的程序意识到情况的变化,以便它可以进入其备用操作模式。
当您使用 kill 时,所需的信号仅发送给您拥有的进程(即,您调用的进程)。这可以防止意外终止错误的进程。例外情况是超级用户(root)可以使用 kill 向任何进程发送信号。同样,root 拥有的任何进程都可以向任何其他进程发送信号。
系统的有序关闭可以通过这种方式发生。虽然 kill 命令未在关闭时使用,但等效的系统调用 kill(2) 用于终止所有内容。这保证了没有文件处于打开状态,并且所有缓冲区都写入磁盘。有关 kill(2) 的描述,请在提示符下输入 man 2 kill。
一个相关的命令是 killall,它将进程的名称作为参数,而不是进程 ID (PID)。 (某些版本的 kill 也可以接受进程名称。)这是一种终止所有具有相同名称的进程的便捷方法。如果使用路径来标识要发出信号的进程,则仅选择执行该特定文件的进程。此外,您可以要求在 killall kill 特定进程之前咨询您,并且您可以收到信号已实际发送的确认信息。
虽然完整详细信息列在 man 页面中,但此处可能有一个示例很有用。假设您有两个程序,它们不同但名称相同——可能是不同的发布级别。为了不同但名称相同,它们必须存储在不同的目录中。假设它们的名称为 sample_prog,但一个存储在 /usr/a 中,另一个存储在 /usr/b 中。输入 ps 会给出以下输出
PID TTY STAT TIME COMMAND 123 pp0 S 0:03 /usr/a/sample_prog 124 pp1 R 0:02 /usr/b/sample_prog
以下命令执行不同的操作
# To kill both processes killall sample_prog # To kill only process 123 killall /usr/a/sample_prog
