Linux 中 timeout、watch 和 at 的指南:管理命令执行时间

大家好!我是大聪明-PLUS

您是否经常在终端中运行某些程序,结果却永远卡住了?或者相反:您需要每秒查看某些内容的变化,但却固执地按下了向上箭头和 Enter 键?又或者,您想在 5 分钟内安排一项任务,但 cron 实在太麻烦了?

对于所有这些场景,Linux 有三个经过验证的实用程序:timeoutwatchat,我们可以使用脚本和黑客手段来解决,但是......我们使用 Unix 方法并非毫无意义,因为 Unix 方法中的一切都已经发明了很长时间。

今天我们将研究如何使用 timeout、watch 和 at 来管理 Linux 中的命令执行时间。

timeout

timeout --- 是 GNU coreutils 软件包的一部分。其目的是运行命令并监控其时间。如果命令超出限制,则会发出信号终止。

默认信号是SIGTERM,重要的是要理解该过程是否有机会正确完成其工作

复制代码
`timeout 5s ./my_script.sh`

这意味着:如果my_script.sh5 秒内没有完成,他就会得到SIGTERM。如果超过 5 秒仍未完成,他就会被杀死。但前提是你明确要求这样做。

我如何确定命令终止的原因?
返回代码 这是什么意思?
124 该队因暂停而被淘汰。
125 错误timeout(例如没有命令)
126 该命令不可执行
127 未找到命令
休息 这是命令本身的退出代码。
复制代码
`timeout 3s `sleep` `5`
`echo` `$?`

`

假设你有一个守护进程或服务器,而不仅仅是一个脚本,并且你无法强行关闭它。你想先礼貌地敲门(SIGTERM),如果你不开门,你就想破门而入(SIGKILL)。

复制代码
`timeout `--signal=`SIGTERM `--kill-after=`2s 10s ./long_running_job`

10秒后,发送SIGTERM信号。如果进程没有响应,则在2秒后收到SIGKILL信号。

这个链条绝对必不可少。终止进程只是成功的一半。你还需要给它机会关闭文件、取消套接字订阅等等。

有时,如果命令自行终止,您可能希望timeout避免干扰其退出代码。那么:

复制代码
`timeout `--preserve-status` 5s ./backup_script.sh`

如果没有此标志,即使脚本以 0 退出,timeout它也可能根据信号返回 124 或 137。

具有超时的安全卷曲:

复制代码
if` ! timeout 3s `curl` `-s` https://example.com > /dev/null; `then`
  `echo` `"Request failed or timed out"`
`fi

如果有的话,为什么还要这么做curl --max-time?因为timeout

  • 通用(不依赖于实用程序)。

  • 可以与任何程序一起工作,而不仅仅是网络程序。

  • 允许您不仅检测较长的加载时间,还可以检测任何类型的冻结(例如,如果curl服务器卡在 DNS 上)。

进程树

如果一个命令timeout启动一个进程,并且该进程产生其他进程,那么:

  • 默认情况下, timeout****它只会终止第一个进程。

  • 所有孩子都会继续活着,除非他们自杀。

例子:

复制代码
`timeout 3s `bash` `-c` `"sleep 5 & wait"

sleep即使终止后仍会继续存在bash,因为它是一个独立的进程。要正确终止所有进程,请执行以下操作:

选项 1:setsid

复制代码
`timeout `--foreground` 3s setsid `bash` `-c` `"sleep 5"=

setsid在新的会话组中启动一个进程。timeout然后它可以通过信号终止整个会话组。

选项 2:脚本内部陷阱

如果你控制了脚本代码,你就可以设置一个陷阱:

复制代码
#!/bin/bash`
trap `"kill 0"` EXIT
`sleep` `5` &
wait`

然后timeout它将终止该脚本,并且该脚本将终止其所有子脚本。

具有超时逻辑和日志记录的示例脚本
复制代码
#!/bin/bash`

`log_file="/var/log/mytask.log"`
`cmd="./long_task.sh"`
`timeout_sec=30`

`echo` `"[INFO] Running command with timeout ${timeout_sec}s"` | `tee` `-a` `"$log_file"`

`if` timeout `--kill-after=`5s `"$timeout_sec"` `"$cmd"` >> `"$log_file"` `2`>&1; `then`
  `echo` `"[INFO] Command finished successfully"` | `tee` `-a` `"$log_file"`
`else`
  `status=$?`
  `if` [ `"$status"` `-eq` `124` ]; `then`
    `echo` `"[ERROR] Command timed out"` | `tee` `-a` `"$log_file"`
  `elif` [ `"$status"` `-eq` `137` ]; `then`
    `echo` `"[ERROR] Command killed forcefully"` | `tee` `-a` `"$log_file"`
  `else`
    `echo` `"[ERROR] Command failed with exit code $status"` | `tee` `-a` `"$log_file"`
  `fi`
`fi

它安全、可读,并且可以嵌入到 Ansible 或 init 脚本中。

watch

watch --- 就像这样cron。它不会将任务放在后台;它每 N 秒显示一次命令的结果。

复制代码
`watch `-n` `2` `'dacongming'

-n 2 --- 启动之间的间隔。---'dacongming' 如果有管道或复杂性,则需要用单引号引起来。

例子:

复制代码
`watch `-n` `1` `'ls -lh /var/log/myapp'
有用的标志

您至少需要学习和记住以下内容:

旗帜 它起什么作用?
-n <> 通话间隔(默认 2 秒)
-d 突出显示已更改的行
-t 摘掉帽子(Every 2.0s: ... date/time
-x 迭代之间不清除屏幕(--no-title
-e watch如果命令失败则退出
典型场景分析

监控可用磁盘空间:

复制代码
`watch `-d` `-n` `5` df `-h` /mnt/data`

如果您要执行几 GB 的卸载、迁移或 ETL,并且不想耗尽磁盘空间,那么这是理想的选择。

查看日志中的最后几行:

复制代码
`watch `-n` `0`.5 `'tail -n 10 /var/log/syslog'

半秒是实时读取的正常间隔。如果日志速度很快,tail -F这个间隔可能更有用,但watch使用起来也更方便。

我们监控 systemd 服务:

复制代码
`watch `-n` `1` `'journalctl -u nginx.service -n 10 --no-pager'

--no-pager必需。否则journalctl,它将卡住,等待您按下按键。

例子
复制代码
`watch `-n` `1` `'ps -eo pid,etime,%cpu,%mem,cmd --sort=-%cpu | head -10'

这将显示按 CPU 使用率排名的前 10 个进程。

突出显示更改:-d

当您监控指标(CPU、IO、网络接口的 tx/rx)时,系统-d只会显示发生变化的行。您无需搜索具体发生了什么变化。

例子:

复制代码
`watch `-d` `-n` `1` `'netstat -antp | grep ESTABLISHED'
别名和习惯

~/.bash_aliases

复制代码
`alias `wtail="watch -n 1 'tail -n 20'"`
alias `wdf="watch -d -n 2 'df -h'"`
alias `wps="watch -n 1 'ps aux --sort=-%cpu | head -10'"

输入它比每次wps记住排序标志要快得多。ps aux

限制和功能

默认情况下,watch它仅写入标准输出。因此,如果命令崩溃,您可能不会注意到。要查看所有内容:

复制代码
`watch `-n` `1` `'dacongming 2>&1'

如果您忘记了引号并且命令包含管道,watch它可能会表现异常或根本无法启动。

糟糕:

复制代码
`watch `-n` `1` tail `-n` `10` /var/log/syslog | `grep` error`

美好的:

复制代码
`watch `-n` `1` `'tail -n 10 /var/log/syslog | grep error'

让我们继续。

at:将来运行命令

如果cron 要讲规律,那就一劳永逸 at。如果你需要在 5 分钟内运行某个程序,然后就不用管它,那么 这是一个简单、方便、Unix 风格的工具。而且,不用写 hack 代码。sleep 300 && your_command &

at它并非总是开箱即用。因此,在 Debian/Ubuntu 上:

复制代码
sudo` apt install at
`sudo` systemctl enable `--now` atd`

如果不启用它atd,您可以随意将任务推送到队列中,但没有人会执行它们。

句法

很简单:

复制代码
echo` `"dacongming"` | at <dacongming>`

或者以交互方式:

复制代码
`at `10`:30`

并且您可以输入命令(每行一个),并通过 完成Ctrl+D

使用示例

2分钟后写入文件:

复制代码
echo` `"echo 'Hello from the future' > ~/future.txt"` | at now `+` `2` minutes`

重新启动服务:

复制代码
echo` `"sudo systemctl restart nginx"` | at now `+` `10` minutes`

删除临时文件:

复制代码
echo` `"rm -rf /tmp/my-temp"` | at `03`:00`

向自己发送通知:

复制代码
echo` `"DISPLAY=:0 DBUS_SESSION_BUS_ADDRESS=unix:path=/run/user/1000/bus notify-send 'Сделай перерыв!'"` | at now `+` `1` hour`

notify-send需要正确的环境变量,尤其是在桌面环境中。它at以系统用户身份运行,并且没有 GUI 环境------您需要手动传递DISPLAY它们DBUS_SESSION_BUS_ADDRESS

如何查看队列
复制代码
`atq`

示例输出:

复制代码
`1   2025-07-28 12:30 a user
2   2025-07-28 14:00 a user`

在哪里:

  • 第一列是任务ID

  • 时间------何时完成

  • a - 活跃(尚未实施)

删除任务
复制代码
`atrm <job_id>`

例子:

复制代码
`atrm `1

或者:

复制代码
`atq | `grep` rotate | `awk` `'{print $1}'` | xargs atrm`

删除与命令中的特定单词相关的所有任务(如果保留命名逻辑)。

如何使用

计划夜间重启服务:

复制代码
echo` `"sudo systemctl restart myservice"` | at `02`:30
`

15分钟后备份当前目录:

复制代码
echo` `"tar czf ~/backup_$(date +\%Y\%m\%d).tar.gz $(pwd)"` | at now `+` `15` minutes`
替代时间格式

他的理解是这样的at

格式 例子
now + 1 hour 从现在开始
midnight 今天 00:00
teatime 今天下午 4:00
tomorrow 明天 00:00
12:30 今天 12:30
08/01/2025 13:00 确切的日期和时间

如果您需要快速完成任务"推迟命令并忘记"我们使用at


结果

timeout以及 ------三个简单却实用的实用程序,涵盖各种场景:从终止冻结进程到实时监控和定向任务执行。请在评论区分享你的使用案例watchat

相关推荐
想唱rap3 小时前
Linux开发工具(4)
linux·运维·服务器·开发语言·算法
robin59113 小时前
Linux-通过端口转发访问数据库
linux·数据库·adb
视觉AI3 小时前
如何查看 Linux 下正在运行的 Python 程序是哪一个
linux·人工智能·python
扣脚大汉在网络4 小时前
如何在centos 中运行arm64程序
linux·运维·centos
lang201509284 小时前
Linux命令行:cat、more、less终极指南
linux·chrome·less
攒钱植发5 小时前
嵌入式Linux——“大扳手”与“小螺丝”:为什么不该用信号量(Semaphore)去模拟“完成量”(Completion)
linux·服务器·c语言
三五度5 小时前
vmware的ubuntu20.04无网络图标
linux·ubuntu
菜鸟祥哥6 小时前
xfs文件系统磁盘损坏修复
linux
Y淑滢潇潇6 小时前
RHCE Day2 时间管理服务器 NFS服务器
linux·运维·服务器