watch 周期监控使用指南
watch 适合“反复执行同一条查询,只关心当前状态”的场景:下载是否增长、端口是否启动、进程是否还在、构建产物是否生成。它把每轮结果刷新在同一个终端画面里,省去反复按上箭头和回车。
# 场景与命令速查
以下命令以 procps-ng 的 watch 为准;被观察的命令也需要安装。macOS 上若 command -v watch 找不到,可用 brew install watch 安装,再通过 watch --version、watch --help 确认实现及选项。Homebrew 的来源见 watch 配方 (opens new window)。
| 场景 | 命令 | 观察内容 |
|---|---|---|
| 下载或打包进度 | watch -n 2 -d 'ls -lh ./downloads/archive.zip' | 文件大小与修改时间 |
| 构建目录体积 | watch -n 5 -d 'du -sh ./build' | 目录占用空间;大目录扫描可适当延长间隔 |
| 开发端口 | watch -n 1 'lsof -nP -iTCP:3000 -sTCP:LISTEN' | 本机可见的监听进程;无输出时检查服务和进程查看权限 |
| 某个进程 | watch -n 2 'ps -p 12345 -o pid,etime,%cpu,%mem,command' | 替换为实际 PID,查看存活时间、CPU 和内存占比 |
| Git 工作区 | watch -n 2 -d 'git status --short' | 修改、暂存和未跟踪文件 |
| 最近提交 | watch -n 5 'git --no-pager log --oneline -5' | 本地已获取的提交;不会自动 fetch |
| 磁盘空间 | watch -n 5 df -h | 文件系统容量和剩余空间 |
| Android 连接 | watch -n 2 adb devices -l | 设备连接、离线与授权状态 |
| 容器状态 | watch -n 2 docker ps | 正在运行的容器;需要 Docker 服务可用 |
| 内存概览(Linux) | watch -n 5 free -h | Linux 内存状态;macOS 可改用 watch -n 5 vm_stat |
| 进程内存排序(Linux) | watch -n 2 'ps -eo pid,comm,%mem --sort=-%mem' | GNU ps 的排序选项,不能直接套用 macOS 的 ps |
带空格的文件名,适合用 -x 保留独立参数:
watch -n 2 -d -x ls -lh './downloads/large file.zip'
# 常用参数
默认每轮命令结束后等待约 2 秒再执行,按 Ctrl+C 结束。默认画面展示当前屏幕能容纳的输出,不保留历史;长输出先用过滤或汇总缩小范围。
| 参数 | 用途 | 示例 |
|---|---|---|
-n 秒数 | 设置刷新间隔 | watch -n 1 date |
-d | 高亮相邻两轮输出的差异 | watch -n 2 -d 'git status --short' |
--differences=permanent | 累积显示从首轮开始变化过的位置 | watch --differences=permanent 'ls -l ./build' |
-t | 隐藏 watch 自己的标题栏 | watch -t -n 2 date |
-c | 解释子命令输出的 ANSI 颜色 | watch -c 'git -c color.status=always status --short' |
-g | 屏幕可见输出变化时退出 | 适合观察状态转变,不等同于“条件满足即退出” |
-e | 子命令失败时冻结画面,按键后退出 | watch -e 'test -f ./build/app.apk' |
-b | 子命令失败时尝试蜂鸣提示 | 终端是否响铃取决于其设置 |
-p | 尽量按相邻两轮的开始时间计算间隔 | watch -p -n 5 date;命令超时仍会等待,不会并行启动多份 |
-x | 直接执行程序,跳过默认的 sh -c | 适合有空格的参数;不会执行管道和重定向语法 |
-c 只负责解释颜色,子命令本身仍需输出颜色;很多工具在检测到输出不是终端时会关闭颜色。-d 比较屏幕显示位置,不理解 JSON 字段或表格主键;时间戳和随机顺序会制造大量差异。
参数语义见 procps-ng 上游手册 (opens new window)。不同安装版本可能有增减,以本机帮助为准。
# 常用组合与边界
轮询本地服务状态
watch -n 5 'curl --silent --show-error --fail --max-time 3 -o /dev/null -w "HTTP %{http_code}\n" http://127.0.0.1:3000/health'
将 /health 换成服务实际提供的接口。它适合观察启动或重启期间的状态码,--max-time 防止单次请求长期卡住。通常先用 2–5 秒间隔,网络请求或大目录扫描不宜高频重复。
等待文件或端口发生状态变化
把输出压缩成稳定的状态文字,避免误把 PID、时间戳等变化当成就绪状态:
# 从 waiting 变成 ready 时退出。
watch -n 1 -g 'if [ -f ./build/app.apk ]; then echo ready; else echo waiting; fi'
# 从 waiting 变成 listening 时退出。
watch -n 1 -g 'if lsof -nP -iTCP:3000 -sTCP:LISTEN >/dev/null 2>&1; then echo listening; else echo waiting; fi'
2
3
4
5
-g 比较相邻轮的可见输出:如果启动时已经是 ready,它不会立刻退出;反方向变化也会触发退出。不要把它当作部署脚本里的条件判断。若要求“已经存在就立即通过,否则一直等待”,直接用循环:
until [ -f ./build/app.apk ]; do
sleep 1
done
printf '%s\n' '构建产物已生成'
2
3
4
watch -g 'ls myfile.txt' 也有局限:普通 ls 成功后只输出文件名,不会因为内容更新而变化。-g 通常以成功状态结束,也不能代替检查子命令的退出码;-e 才专门处理子命令失败,并且会先冻结画面等待按键。
让管道、变量和通配符每轮重新求值
默认情况下,命令会交给新的 sh -c 执行。外层单引号让管道、变量和通配符留到每轮执行时再解析:
watch -n 2 'ls -lt ./build | head -n 10'
watch -n 2 'ls -lh ./logs/*.log'
watch -n 1 'printf "%s\n" "$(date +%T)"'
2
3
如果写成 watch -n 2 ls ./logs/*.log,通配符会先被当前 shell 展开,之后新出现的文件可能不会被纳入。引号并非只能用单引号;双引号会让当前 shell 提前展开 $变量、$(命令) 等,适合有意固定启动时参数的情况。
watch 子命令能继承已导出的环境变量,但不会自动继承当前 zsh 的别名和函数,也不会默认读取 .zshrc。自定义函数应整理为可执行脚本,再让 watch 调用。所有 watch 选项放在被执行命令之前,例如 watch -n 2 -d git status --short。
与日志追踪、文件监听和定时任务的区别
| 需求 | 选择 |
|---|---|
| 每隔几秒查看一个查询的最新结果 | watch |
| 持续阅读追加的日志,包含轮转或重建场景 | tail -F app.log |
| 文件变化后触发测试或构建 | 文件事件监听工具;按项目的监听机制配置 |
| 退出终端后仍需按计划执行 | 系统定时任务或服务管理器 |
| 保存每轮结果用于事后分析 | 显式写日志的脚本;watch 默认只刷新当前画面 |
优先监控只读查询。watch 会重复执行命令,删除文件、部署、发送消息等有副作用的操作不应随手放进轮询。
参考资料