计算机资源是有限的。为了有效管理进程,我们可以使用 timeout
命令来限制其运行时间。本文将深入探讨如何运用此命令来控制程序的执行时长。
超时命令的优势
timeout
命令允许您为程序设定一个最长运行时间。那么,为什么要这样做呢?
首先,当您明确知道程序需要运行多久时,超时命令非常有用。例如,对于日志记录或数据捕获程序,您可以设置一个超时,以防止日志文件无限增长,占用硬盘空间。
其次,即使您不确定程序需要运行多久,但您不希望它无限期地运行,超时命令也很有价值。有时候,我们可能会启动一个程序,最小化终端窗口,然后就忘记了它。
一些程序,包括简单的工具,可能会产生影响网络性能的网络流量。或者,它们可能会消耗目标设备的资源,导致性能下降。(ping
命令就是一个例子。)长时间运行这些类型的程序是不明智的。
timeout
命令是 GNU核心实用程序 的一部分,这意味着像 Linux 和 macOS 这样的类 Unix 操作系统都内置了此功能。无需额外安装,您可以直接使用。
超时命令的基本用法
下面是一个简单的例子。 默认情况下,ping
命令会一直运行,直到您按下 Ctrl+C 手动停止它。 如果您不中断它,它就会继续发送网络请求。
ping 192.168.4.28
通过使用 timeout
命令,我们可以确保 ping
不会无限期地运行,从而避免占用网络带宽或对目标设备造成负担。
下面的命令使用 timeout
来限制 ping
的运行时间。 我们允许 ping
运行 15 秒:
timeout 15 ping 192.168.4.28
15 秒后,timeout
将终止 ping
会话,并返回到命令行提示符。
使用不同的时间单位
请注意,我们不必在数字 15 后面添加 “s”。 timeout
默认以秒为单位。 您可以添加 “s”,但没有实际区别。
要使用分钟、小时或天作为时间单位,请添加 “m”、”h” 或 “d”。例如,要让 ping
运行 3 分钟,请使用以下命令:
timeout 3m ping 192.168.4.28
ping
将运行三分钟,然后 timeout
会介入并停止 ping
会话。
使用超时限制数据捕获
一些数据捕获文件可能会迅速膨胀。为了防止此类文件变得过大,请限制允许捕获程序运行的时间。
在这个例子中,我们使用 tcpdump
,一个网络流量捕获工具。 在一些 Linux 发行版中,如 Ubuntu 和 Fedora,tcpdump
已经预装好了。 如果您的系统中没有安装,您可能需要使用以下命令进行安装(例如,在 Manjaro 和 Arch Linux 中):
sudo pacman -Syu tcpdump
我们可以使用默认选项运行 tcpdump
10 秒,并将其输出重定向到名为 capture.txt
的文件:
timeout 10 sudo tcpdump > capture.txt
(tcpdump
本身具有将捕获的网络流量保存到文件的选项。这只是一个简单的演示,因为我们主要关注 timeout
命令。)
tcpdump
开始捕获网络流量,我们等待 10 秒。 10 秒过去后,tcpdump
仍在运行,capture.txt
的大小仍在增长。 需要手动使用 Ctrl+C 来停止 tcpdump
。
使用 ls
命令检查 capture.txt
的大小,发现它在几秒钟内增长到了 209K。 文件增长速度惊人!
ls -lh capture.txt
怎么回事?为什么 timeout
没有停止 tcpdump
?
这与信号有关。
理解信号
当 timeout
想要停止程序时,它会发送一个SIGTERM 信号。这是一种礼貌地请求程序终止的方式。 然而,有些程序可能会选择忽略 SIGTERM
信号。 当这种情况发生时,我们需要让 timeout
更强硬一些。
我们可以请求 timeout
发送 SIGKILL
信号来代替。
SIGKILL
信号无法被“捕获、阻止或忽略” – 它总是能强制程序终止。 与 SIGTERM
的礼貌请求不同,SIGKILL
是一种更直接的强制手段。
我们可以使用 -s
(signal) 选项来告诉 timeout
发送 SIGKILL
信号:
timeout -s SIGKILL 10 sudo tcpdump > capture.txt
这一次,只要 10 秒过去,tcpdump
就会停止。
先尝试礼貌方式
我们可以请求 timeout
先尝试使用 SIGTERM
停止程序,只有在 SIGTERM
不起作用时才发送 SIGKILL
。
为此,我们使用 -k
(kill after) 选项。 -k
选项需要一个时间值作为参数。
在下面的命令中,我们要求 timeout
让 dmesg
运行 30 秒,然后使用 SIGTERM
信号终止它。 如果 40 秒后 dmesg
仍在运行,则表示 SIGTERM
被忽略,timeout
将发送 SIGKILL
来完成任务。
dmesg
是一个实用程序,可以 监视内核环形缓冲区消息 并将其显示在终端窗口中。
timeout -k 40 30 dmseg -w
dmesg
运行 30 秒,并在收到 SIGTERM
信号时停止。
我们知道阻止 dmesg
的不是 SIGKILL
,因为 SIGKILL
总会在终端窗口中留下一个词的讣告:“Killed”。 在这种情况下,并没有发生这种情况。
获取程序的退出代码
表现良好的程序在终止时会向 shell 返回一个值,称为退出代码。这通常用于告诉 shell(或启动程序的任何进程)该程序在运行时是否遇到问题。
timeout
也有自己的退出代码,但我们可能并不关心。 我们可能对 timeout
控制的程序的退出代码更感兴趣。
下面的命令让 ping
运行 5 秒钟。它正在 ping
一台名为 Nostromo
的计算机,这台计算机位于用于研究本文的测试网络上。
timeout 5 ping Nostromo.local
该命令运行 5 秒钟,然后 timeout
将其终止。 我们可以使用以下命令检查退出代码:
echo $?
退出代码是 124。这是 timeout
用于指示程序使用 SIGTERM
终止的值。 如果 SIGKILL
终止了程序,则退出代码为 137。
如果我们使用 Ctrl+C 中断程序,timeout
的退出代码为零。
timeout 5 ping Nostromo.local
echo $?
如果程序在 timeout
终止之前自行结束,那么 timeout
可以将程序的退出代码传递回 shell。
为此,程序必须自行停止(即,它不会被超时终止),并且我们必须使用 --preserve-status
选项。
如果我们使用值为 5 的 -c
(count) 选项,ping
将只发送 5 个请求。如果我们给 timeout
一分钟的持续时间,ping
肯定会自行终止。 然后,我们可以使用 echo
检查退出值。
timeout --preserve-status 1m ping -c 5 Nostromo.local
echo $?
ping
完成其 5 个 ping
请求并终止。 退出代码为零。
为了验证退出代码是否来自 ping
,我们可以强制 ping
生成不同的退出代码。如果我们尝试向不存在的 IP 地址发送 ping
请求,ping
将失败并返回错误退出代码。 然后,我们可以使用 echo
来检查退出代码是否非零。
timeout --preserve-status 1m ping -c 5 NotHere.local
echo $?
ping
命令显然无法到达不存在的设备,因此它会报告错误并关闭。 退出代码是 2。这是 ping
用于一般错误的退出代码。
总结
timeout
命令为正在运行的程序提供了一种界限。如果存在日志文件可能超出硬盘驱动器容量的风险,或者担心忘记正在运行的网络工具,请使用 timeout
命令来限制其运行时间,让您的计算机自行管理。