watch 命令详解与参数实测(Ubuntu 22.04)

周期执行与全屏刷新的 watch:无 tty 真实报错、script 捕获 ANSI 渲染逐段解读、-n 间隔、-d 变化高亮、-t 去标题、-g 变化即退出、-x exec 模式、q 键与 Ctrl-C 退出对照及 while+sleep 轮询替代

Linux命令Linux系统UbuntuUbuntu 22.04命令行文本处理2026/10/15

watch 命令详解与参数实测(Ubuntu 22.04)

目标:全面掌握 procps watch 的周期执行与全屏刷新能力——无 tty 直接运行的真实报错、用 script 捕获 ANSI 渲染输出的逐段解读(备用屏幕、Every 1.0s 头部)、-n 刷新间隔、-d 变化高亮、-t 去标题、-g 变化即退出(耗时对照)、-x exec 模式、退出方式的实测澄清(q 键与 Ctrl-C 的对照)以及非 tty 场景的 while+sleep 轮询替代,全部命令与回显已在 Ubuntu 22.04(procps-ng 3.3.17)实测通过。

一、环境信息

本节列出本文所有实测所依赖的环境与测试数据,便于读者按同规格复现。

  • 操作系统:Ubuntu 22.04.5 LTS(x86_64)
  • watch 版本:procps-ng 3.3.17(watch --version 实测;软件包名 procps)
  • watch 属于 procps 软件包,Ubuntu 22.04 默认预装,无需额外安装
  • 演示目录:/root/demo/watch/(仅实战 4.1 用到,用于生成增长的日志文件)
  • 测试命令:watch 观测的是「一条命令」而非文件,本文用 date、date +%s、date +%F、wc -l 作被观测命令,它们的输出随时间变化,最适合观察刷新与高亮行为

二、命令概览

2.1 语法与测试数据准备

watch 的基本语法是 watch [options] command:每隔 -n 指定的秒数(默认 2 秒)重复执行 command,并全屏重绘其输出——先清屏、再画一行头部(刷新间隔、命令原文、主机名与当前时间),最后是命令输出,反复覆盖同一块屏幕。它是一个 ncurses 全屏交互程序,依赖终端(tty)才能运行,这一点决定了本文的实测方式:无 tty 环境直接运行会报错(3.1 节实测),捕获其渲染结果需要借助 script 分配伪终端(3.2 节实测)。

💡 技术拓展:「周期性观察一条命令的输出」有两种范式,横向对比——

方式形态终端依赖输出留存
watch全屏清屏重绘,永远只看到最新一屏必须有 tty(ncurses)不留历史,Ctrl-C 退出(3.8 节实测)
while + sleep循环追加输出,历史逐行滚屏无 tty 也能跑(脚本/cron 友好)可重定向落盘

交互终端前人工盯屏幕用 watch,脚本与定时任务里采集数据用 while 轮询,本文两者都实测。

watch 无需预置数据文件,直接用系统自带命令作被观测对象;准备动作仅一条——确认环境无 TERM 变量时会是什么行为(这也是 3.1 报错的前提):

head -2 /etc/os-release
uname -m

2.2 --help 全量回显

watch --help 输出全部参数清单(实测原样保留,可作为参数速查表):

Usage:
 watch [options] command

Options:
  -b, --beep             beep if command has a non-zero exit
  -c, --color            interpret ANSI color and style sequences
  -d, --differences[=<permanent>]
                         highlight changes between updates
  -e, --errexit          exit if command has a non-zero exit
  -g, --chgexit          exit when output from command changes
  -n, --interval <secs>  seconds to wait between updates
  -p, --precise          attempt run command in precise intervals
  -t, --no-title         turn off header
  -w, --no-wrap          turn off line wrapping
  -x, --exec             pass command to exec instead of "sh -c"

 -h, --help     display this help and exit
 -v, --version  output version information and exit

For more details see watch(1).

帮助原文只有十个功能参数:-d 高亮变化与 -g 变化退出是「盯输出」的黄金搭档;-x 把命令交给 exec 而非 sh -c(少一层 shell);-c 让 watch 解释命令输出中的 ANSI 颜色序列。交互按键帮助里只字未提——3.8 节将用实测澄清退出方式。

2.3 版本确认

确认实测环境的 watch 版本:

$ watch --version
watch from procps-ng 3.3.17

三、参数逐项实测

3.1 无 tty 直接运行:真实报错

watch 必须有终端才能全屏绘制。在没有任何 tty 的环境里直接运行,ncurses 初始化失败,实测报错:

$ timeout 2 watch -n 1 date
Error opening terminal: unknown.

报错末尾的 unknown. 是 ncurses 读取 TERM 变量的结果——当前环境 TERM 未设置,ncurses 把终端类型判为 unknown。同样的报错也会出现在 cron、CI 脚本这类无终端场景中。这不是 watch 的 bug,而是全屏程序的固有约束:处理方式要么在真实终端里运行,要么改用第四节 4.2 的 while 轮询。

3.2 script 捕获 ANSI 渲染输出

要把 watch 的全屏渲染「拍下来」,用 script 命令分配一个伪终端(pty)当舞台,再把整个会话录制到 /dev/null、stdout 输出捕获后用 cat -v 显形。实测需要解决两个环境问题:TERM 未设置(会复现 3.1 的报错)与 timeout 的进程组问题(见第五节 Q2),完整可用的捕获命令是:

$ script -qec "TERM=xterm timeout --foreground 2 watch -n 1 date" /dev/null | cat -v | head -15
^[[?1049h^[[22;0;0t^[[1;24r^[(B^[[m^[[4l^[[?7h^[[H^[[2JEvery 1.0s: date^[[1;43Hf1034b9326b2: Thu Oct 15 08:20:28 2026^[[3;1HThu Oct 15 08:20:28 UTC 2026^[[24;80H^[[1;75H9^[[3;19H9^[[24;80H^[[24;1H^[[?1049l^[[23;0;0t^M^[[?1l^[>

cat -v 把不可见控制符显形(^[[ 即 ESC 键),逐段解读这条 ANSI 流:

  • ^[[?1049h:进入备用屏幕(alternate screen,watch 退出时用 ^[[?1049l 恢复原屏);
  • ^[[H^[[2J:光标回原点并清屏;随后是头部文本 Every 1.0s: date——间隔 1 秒、命令为 date;
  • ^[[1;43H:把光标定位到第 1 行第 43 列,接着画头部右半段 f1034b9326b2: Thu Oct 15 08:20:28 2026(主机名与刷新时刻);
  • ^[[3;1H:定位到第 3 行第 1 列,画出命令输出 Thu Oct 15 08:20:28 UTC 2026;
  • ^[[1;75H9^[[3;19H9:末位数字变化时,只重画那两个字符——这就是 watch 的增量重绘;
  • ^[[24;1H^[[?1049l^[[23;0;0t:回到备用屏幕底部、退出备用屏幕,会话结束。

这段回显证实了 watch 的工作原理:不是重复打印,而是像动画一样反复覆盖同一块屏幕,头部信息(Every 1.0s、主机名、时间)由 watch 自己生成。

3.3 -n:刷新间隔

-n <secs>(--interval)设定两次刷新的间隔秒数,间隔值直接显示在头部。实测 -n 2 后头部变为 Every 2.0s: date:

$ script -qec "TERM=xterm timeout --foreground 3 watch -n 2 date" /dev/null | cat -v | head -12
^[[?1049h^[[22;0;0t^[[1;24r^[(B^[[m^[[4l^[[?7h^[[H^[[2JEvery 2.0s: date^[[1;43Hf1034b9326b2: Thu Oct 15 08:20:30 2026^[[3;1HThu Oct 15 08:20:30 UTC 2026^[[24;80H^[[1;75H2^[[3;19H2^[[24;80H^[[24;1H^[[?1049l^[[23;0;0t^M^[[?1l^[>

间隔也支持小数(如 -n 0.5 表示半秒),值越小对被观测命令的执行频率越高;-p(--precise)可让 watch 按固定节拍对齐执行,抵消命令本身的耗时漂移。

3.4 -d:高亮变化

-d(--differences)对比两次刷新的输出,把发生变化的部分以反显(reverse video)标出。实测观测 date +%s(每秒变化的是秒计数末位):

$ script -qec "TERM=xterm timeout --foreground 3 watch -n 1 -d date +%s" /dev/null | cat -v | head -15
^[[?1049h^[[22;0;0t^[[1;24r^[(B^[[m^[[4l^[[?7h^[[H^[[2JEvery 1.0s: date +%s^[[1;43Hf1034b9326b2: Thu Oct 15 08:20:33 2026^[[3;1H1792052433^[[24;80H^[[1;75H4^[[3;10H^[(B^[[0;7m4^[[24;80H^[(B^[[m^[[1;75H5^[[3;10H^[(B^[[0;7m5^[[24;80H^[(B^[[m^[[24;1H^[[?1049l^[[23;0;0t^M^[[?1l^[>

解读:^[[3;10H^[(B^[[0;7m4 表示把光标定位到第 3 行第 10 列(时间戳 1792052433 的末位所在位置),用 ^[[0;7m 反显画出新值 4,随后 ^[[m 复位;下一秒同样的位置反显 5。变化的字符被逐个标亮,这正是 -d 的价值——长输出中肉眼立刻锁定「哪里动了」。给 -d 传值 <permanent>(帮助原文 --differences[=<permanent>])可让首次出现的变化永久保持高亮。

3.5 -t:去掉标题

-t(--no-title)关闭顶部的 Every N.Ns 头部,屏幕只保留命令输出。实测对比可见输出区上方再无头部行:

$ script -qec "TERM=xterm timeout --foreground 2 watch -n 1 -t date" /dev/null | cat -v | head -8
^[[?1049h^[[22;0;0t^[[1;24r^[(B^[[m^[[4l^[[?7h^[[H^[[2JThu Oct 15 08:20:36 UTC 2026^[[24;80H^[[1;19H7^[[24;80H^[[24;1H^[[?1049l^[[23;0;0t^M^[[?1l^[>

清屏后直接是 Thu Oct 15 08:20:36 UTC 2026,没有 Every 1.0s: date、没有主机名。屏幕空间宝贵(如观测多行输出)或需要把渲染结果转储时用它。

3.6 -g:输出变化即退出

-g(--chgexit)让 watch 在检测到命令输出变化时自动退出。用 time 实测观测 date +%s——秒数一变 watch 即退出,仅运行 1.035 秒:

$ time script -qec "TERM=xterm timeout --foreground 5 watch -n 1 -g date +%s" /dev/null
[?1049h[22;0;0t[1;24r(B[m[4l[?7h[H[2JEvery 1.0s: date +%s[1;43Hf1034b9326b2: Thu Oct 15 08:20:38 2026[3;1H1792052438[24;80H[1;75H9[3;10H9[24;80H[24;1H[?1049l[23;0;0t[?1l>
real	0m1.035s
user	0m0.016s
sys	0m0.008s

对照不带 -g 的运行——跑满外层 timeout 的 5 秒:

$ time script -qec "TERM=xterm timeout --foreground 5 watch -n 1 date +%s" /dev/null
[?1049h[22;0;0t[1;24r(B[m[4l[?7h[H[2JEvery 1.0s: date +%s[1;43Hf1034b9326b2: Thu Oct 15 08:20:39 2026[3;1H1792052439[24;80H[1;74H40[3;9H40[24;80H[1;75H1[3;10H1[24;80H[1;75H2[3;10H2[24;80H[1;75H3[3;10H3[24;80H[24;1H[?1049l[23;0;0t[?1l>
real	0m5.032s
user	0m0.025s
sys	0m0.017s

💡 说明:1.035s 与 5.032s 的对照就是 -g 的语义——「等输出变化,变即止」。脚本化的典型用法:等某个日志文件出现新内容(watch -g wc -l 日志文件)、等某进程状态翻转,变化后 shell 拿到退出码继续后续动作;与 -e(命令退出码非零即退出)配合可覆盖大多数等待场景。

3.7 -x:exec 模式

-x(--exec)把命令直接交给 exec 而不是默认的 sh -c,省去一层 shell 解析。实测头部照常显示命令原文,输出为 date +%F 的结果:

$ script -qec "TERM=xterm timeout --foreground 2 watch -n 1 -x date +%F" /dev/null | cat -v | head -10
^[[?1049h^[[22;0;0t^[[1;24r^[(B^[[m^[[4l^[[?7h^[[H^[[2JEvery 1.0s: date +%F^[[1;43Hf1034b9326b2: Thu Oct 15 08:20:44 2026^[[3;1H2026-10-15^[[24;80H^[[1;75H5^[[24;80H^[[24;1H^[[?1049l^[[23;0;0t^M^[[?1l^[>

头部 Every 1.0s: date +%F、第 3 行输出 2026-10-15,行为与默认模式一致。差异在底层:默认模式下命令里的管道、通配符由 shell 解释,-x 模式下整串作为单个可执行文件的参数,适合观测不含 shell 语法的命令。

3.8 退出方式实测:q 键无效,Ctrl-C 有效

watch 是交互程序,但退出方式值得实测澄清。先实测把 q 字符注入伪终端(无论 watch 启动前还是运行 1 秒后注入),watch 都不退出、跑满外层 timeout 的 5 秒:

$ time printf 'q' | script -qec "TERM=xterm timeout --foreground 5 watch -n 1 date" /dev/null | cat -v | tail -1
q^[[?1049h^[[22;0;0t^[[1;24r^[(B^[[m^[[4l^[[?7h^[[H^[[2JEvery 1.0s: date^[[1;43Hf1034b9326b2: Thu Oct 15 08:20:50 2026^[[3;1HThu Oct 15 08:20:50 UTC 2026^[[24;80H^[[1;75H1^[[3;19H1^[[24;80H^[[1;75H2^[[3;19H2^[[24;80H^[[1;75H3^[[3;19H3^[[24;80H^[[1;75H4^[[3;19H4^[[24;80H^[[24;1H^[[?1049l^[[23;0;0t^M^[[?1l^[>
real	0m5.041s
user	0m0.024s
sys	0m0.024s

再实测注入 Ctrl-C(\x03 字符经 pty 转成 SIGINT 信号)——watch 立即退出,仅运行 1.031 秒:

$ time { sleep 1; printf '\x03'; } | script -qec "TERM=xterm timeout --foreground 5 watch -n 1 date" /dev/null | cat -v | tail -1
^[[?1049h^[[22;0;0t^[[1;24r^[(B^[[m^[[4l^[[?7h^[[H^[[2JEvery 1.0s: date^[[1;43Hf1034b9326b2: Thu Oct 15 08:20:55 2026^[[3;1HThu Oct 15 08:20:55 UTC 2026^[[24;80H^[[24;1H^[[?1049l^[[23;0;0t^M^[[?1l^[>
real	0m1.031s
user	0m0.013s
sys	0m0.010s

💡 说明:两个实测给出结论——本版本(procps-ng 3.3.17)的 watch 不处理 q 按键(网络流传的「按 q 退出」在本机版本不成立,帮助原文也只字未提交互键),实际退出方式是 Ctrl-C(SIGINT)或被外层 timeout/SIGTERM 终止;watch(1) 手册同样未记载任何按键命令,以实测为准。

四、实战示例

4.1 监控日志行数增长(-d -t 组合)

观测一个正在增长的日志文件:后台每秒追加一行,前台用 watch -n 1 -d -t wc -l 盯行数——-d 标亮变化、-t 腾出整屏。先造一个持续增长文件并启动观测:

$ rm -rf /root/demo/watch && mkdir -p /root/demo/watch && printf '' > /root/demo/watch/grow.log

$ (for i in 1 2 3; do echo "line $i" >> /root/demo/watch/grow.log; sleep 1; done) &

$ script -qec "TERM=xterm timeout --foreground 4 watch -n 1 -d -t wc -l /root/demo/watch/grow.log" /dev/null | cat -v | head -12
^[[?1049h^[[22;0;0t^[[1;24r^[(B^[[m^[[4l^[[?7h^[[H^[[2J1 /root/demo/watch/grow.log^[[24;80H^[[H^[(B^[[0;7m2^[[24;80H^[(B^[[m^[[H^[(B^[[0;7m3^[[24;80H^[(B^[[m^[[H3^[[24;80H^[[24;1H^[[?1049l^[[23;0;0t^M^[[?1l^[>

解读:清屏后首屏画出 1 /root/demo/watch/grow.log(当时行数 1);随后两次增量重绘中,行数 2、3 都以 ^[[0;7m 反显标亮。同样的骨架换成 tail、df -h、kubectl get pods 等命令,就是现成的监控面板。

4.2 非 tty 场景的 while + sleep 轮询替代

cron、CI、管道等无终端环境跑不了 watch,用 while 加 sleep 得到同样的周期执行,且输出可正常重定向。实测每秒打印一次当前时间、共 3 秒:

$ timeout 3 bash -c 'while true; do date +%T; sleep 1; done'
08:20:56
08:20:57
08:20:58

把 date +%T 换成任何检查命令、把外层 timeout 3 换成业务超时,即是无终端环境的标准轮询写法;输出追加滚动、可落盘,与 watch 的「全屏覆盖、不留历史」互补。

五、注意事项与常见问题

Q1:watch 报 Error opening terminal: unknown. 怎么解决? 分两种场景:环境里有终端但 TERM 变量没设置(如某些远程登录或嵌套终端),先 export TERM=xterm(或匹配的实际终端类型)再运行;环境里根本没有 tty(cron、CI、管道、脚本),watch 无法运行也不应运行,改用第四节 4.2 的 while + sleep 轮询,或借助 script 分配伪终端(3.2 节)。

Q2:为什么用 timeout 包裹 watch 会卡住或把 watch「冻住」? GNU timeout 默认把子进程放进新的进程组,而 watch 是要读终端键盘的 ncurses 程序——后台进程组读取 tty 会触发 SIGTTIN,watch 进程随即进入 stopped(T)状态,表现为屏幕冻结、timeout 永远等不到它退出。解决办法是给 timeout 加 --foreground,让 watch 留在前台进程组正常读写终端,本文 3.2 节起所有捕获命令均采用 timeout --foreground。

Q3:watch 和 while + sleep 到底怎么选? 看三点:终端(watch 必须 tty,while 不需要)、输出留存(watch 全屏覆盖不留历史,while 追加可落盘)、退出方式(watch 靠 Ctrl-C/timeout,见 3.8 节实测;while 靠循环条件)。人工实时盯屏选 watch,脚本与定时任务选 while。

Q4:-d 高亮的到底是什么? watch 保存上一次刷新的输出,与本次输出逐字符对比,把差异部分反显标亮(3.4 节实测中时间戳末位 4 与 5 被逐字符标亮),不变部分原样重绘。加 =permanent 参数(帮助原文 --differences[=<permanent>])后高亮不再随下次刷新清除,适合追踪首次出现的关键变化。

Q5:默认 2 秒的刷新间隔能更快或更精确吗? -n 接受任意正数(含小数)设定间隔;默认情况下 watch 是「命令跑完再等间隔」,长期运行会有漂移,-p(--precise)让 watch 按固定节拍对齐执行(帮助原文 attempt run command in precise intervals)。间隔过小会让被观测命令(尤其重量级命令)高频执行,反而干扰观测目标。

六、参考链接