Kill:结束所有命令的命令

作者:Dean Provins

Linux 是一个强大的操作系统。凭借其按需分页内存管理和交换文件机制,它允许您启动任意数量的进程。当然,这个数字受限于整体系统内存容量(物理内存加上交换空间)以及您的 CPU 执行您所请求的所有任务的能力。启动进程很容易,当事情慢到爬行时,停止它们也同样容易。

Linux 的 kill 命令是两个命令之一,当您厌倦等待进程终止时,它将满足您的需求。用我 1992 年的 Linux 程序员手册的话来说,您可以使用它以极大的偏见终止进程。您只需要知道一个名为进程 PID 的数字。请注意,kill 并非总是终止另一个进程。本质上,kill 向指定进程发送一个信号。如果该信号未被进程捕获和处理(并非所有信号都可以被捕获和处理),则进程将被终止。进程使用的所有资源都将被释放,供其他正在运行的进程使用。

进程和 PID

什么是进程、PID 和信号?如何发现它们?

回想一下,Linux 是一个多任务操作系统。当 Linux 启动时,它会启动一个名为 init 的程序,该程序又会启动其他程序。其中许多是后台任务,例如 update,它定期将数据刷新到磁盘。另一个例子是 getty,它监视串行端口是否有活动迹象。一个更明显的例子是您用来执行有用工作的 shell。它在前台运行,这意味着它等待您的击键。系统上运行的每个程序的每个副本都称为进程

正如美国政府颁发社会安全号码(我们在加拿大使用社会保险号码)来唯一标识每个人一样,Linux 为每个进程分配一个唯一的号码作为标识符。这个数字被称为进程 IDPID

当一个进程启动时,它被赋予下一个可用的 PID,当它终止时,它的 PID 被释放以供最终重用。要确定属于您的任何进程的 PID,请在提示符下输入 psps 命令将为您的每个进程打印一行,其中包含进程的 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 进程立即终止。

使用 kill

假设我们不小心在后台启动了 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
结论

总之,killkillall 命令可以是控制 Linux 系统上进程执行的有用工具。与先前“Take Command”专栏中描述的其他工具结合使用,它们将使您成为非常强大的桌面设备的真正主人。有关它们极少的选项的具体信息,以及有关它们可以调用的信号的描述,请阅读相关的手册页(在提示符下输入 man killman killall)。

Kill: The Command to End All Commands
Dean Provins 是加拿大艾伯塔省卡尔加里的专业地球物理学家和持证业余无线电操作员 (VE6CTA)。自 20 世纪 80 年代中期以来,他一直使用 Unix 系统,自 1993 年 1 月以来一直使用 Linux,当时他在卡尔加里 Unix 用户组通讯中读到一篇关于它的文章。Dean 将 Linux 用作地球物理软件的开发系统,以及用于通讯和其他文章的文本处理系统。他目前正在开发一个 Linux 应用程序,用于查看美国无线电中继联盟月刊 QST 中发表的文章的扫描图像。可以通过 provinsd@cuug.ab.ca 与他联系。
加载 Disqus 评论