这个命令是干啥的
做运维监控,很多情况需要反复看同一个命令的输出。比如:
- ·磁盘空间还剩多少,过一会儿再看有没有涨
- ·进程有没有挂掉,过几秒再刷一次
- ·日志里有没有新报错,等着看它出来
刚开始我都是手动敲,过一会儿 df -h,再过一会儿 ps aux | grep java。后来发现 watch 这个命令,感觉打开了新世界的大门。它帮你自动反复执行同一命令,还能用高亮标出变化的部分。
简单说:watch 就是你跟命令行之间的"自动刷新按钮"。
基本用法(3分钟上手)
最简单的用法
# 每隔2秒执行一次 ls,默认间隔就是2秒
watch ls -la
屏幕会分成两部分:
- 顶部第一行:显示刷新间隔和执行命令
- 下面的内容:命令输出,每隔2秒刷新一次
按 Ctrl+C 退出。
指定刷新间隔
# 每隔1秒刷新一次
watch -n 1 df -h
# 每隔5秒刷新一次
watch -n 5 free -m
高亮变化的内容
这是 watch 最实用的功能:
# 用 -d 高亮出两次执行之间变化的部分
watch -d -n 1 free -h
跑了之后你会看到,内存数字变化的地方会自动高亮,一眼就能看到"哪变了"。
保留命令输出颜色
很多命令(如 ls --color、grep --color)的输出自带颜色,但 watch 默认不保留颜色:
# 加上 -c 参数保留颜色输出
watch -c -n 2 'ls -la --color=auto'
进阶骚操作
持续监控磁盘空间
# 监控所有挂载点的磁盘使用率
watch -d -n 5 'df -h | grep -v tmpfs'
解释一下:-d 高亮变化的百分比,-n 5 每5秒刷新,grep -v tmpfs 过滤掉tmpfs虚拟文件系统,只看真正的磁盘。
监控进程变化
# 每隔2秒监控 Nginx 进程数量
watch -d -n 2 'ps aux | grep nginx | grep -v grep | wc -l'
# 监控某个端口是否在监听
watch -n 3 'ss -tlnp | grep :8080'
# 监控 MySQL 连接数
watch -d -n 5 'mysql -u root -p"password" -e "show processlist;" 2>/dev/null | wc -l'
监控网络连接
# 实时监控连接状态
watch -d -n 2 'netstat -ant | grep -E "ESTABLISHED|TIME_WAIT" | head -20'
# 监控特定IP的连接
watch -d -n 1 'ss -ant | grep 192.168.1.100'
监控日志尾部
# 相当于带自动刷新的 tail -f
watch -d -n 2 'tail -20 /var/log/nginx/access.log'
# 监控错误日志
watch -d -n 3 'tail -n 20 /var/log/syslog | grep -i error'
注意:watch 是清屏重新执行,不是像 tail -f 那样追加。数据量大的日志用 tail -f 更合适,watch 适合看结构化的统计输出。
管道和引号的处理
复杂的命令需要用引号包起来:
# 单条简单命令可以不用引号
watch df -h
# 包含管道、变量的命令,必须用引号
watch 'ps aux | grep nginx | grep -v grep | wc -l'
# 包含环境变量的,建议用双引号
watch "echo '当前用户:' \$USER"
# 用单引号可以防止变量展开
watch 'echo "当前时间: $(date)"'
精确到微秒的刷新
# 每隔0.5秒刷新一次
watch -n 0.5 'date +%H:%M:%S.%N'
执行长命令时注意
watch 默认在当前命令执行完毕后才开始计算下个间隔。如果命令本身要跑3秒,-n 2 实际间隔可能不是2秒:
# 这条命令本身要跑3秒
watch -n 2 'sleep 3; df -h'
# 实际执行间隔至少3秒,不是2秒
-p(precise)参数可以让固定间隔执行,但命令超时了可能重叠:
# 尝试精确2秒间隔执行(即使命令超时)
watch -p -n 2 'df -h'
避坑指南
坑1:引号问题(最常见!)
这是我踩过最多的坑:
# 这么写会报错!因为 shell 先解释了管道
watch ps aux | grep nginx
# 正确写法:用引号包起来
watch 'ps aux | grep nginx'
不加引号时,shell会把 watch ps aux 当作完整命令,然后 | grep nginx 是对 watch 的输出做过滤,而不是过滤 ps 的输出。
坑2:特殊字符被提前解析
# 这个不行,$ 被 shell 提前替换了
watch "echo $PATH"
# 正确:用单引号阻止变量展开
watch 'echo $PATH'
单引号里所有字符都是字面量,双引号仍然会展开变量。复杂的命令建议一律用单引号。
坑3:命令中有交互提示
# 如果命令中途要等输入,watch 会卡住
watch 'rm -i /tmp/*'
# 更好的是用非交互版本
watch 'rm -f /tmp/*'
坑4:大量输出导致界面闪烁
# 这样输出刷屏,什么都看不清
watch 'find / -name "*.log"'
# 限制输出行数
watch 'find / -name "*.log" 2>/dev/null | tail -20'
坑5:性能问题
watch -n 1(每秒刷一次)看起来爽,但如果是查数据库、查大日志的生产服务器,频繁执行会产生不必要的负载。特别是在白天业务高峰期,别开太多 watch 窗口。
监控类的 watch 间隔设到5-10秒足够了,想看精细变化用专门的监控工具。
实战场景(重点!结合真实运维场景)
场景1:发布时观察状态
上线发布新版本时,需要观察各个指标是否正常:
# 第一个终端:看服务进程
watch -d -n 2 'ps aux | grep java | grep -v grep'
# 第二个终端:看日志报错
watch -d -n 3 'tail -10 /var/log/app/error.log | grep -i "exception\|error\|timeout"'
# 第三个终端:看端口监听
watch -d -n 1 'ss -tlnp | grep -E ":8080|:443"'
我一般开个 tmux 分屏,同时盯着这几个窗口。一旦发现有进程挂了或者报错突增,马上回滚。
场景2:磁盘空间预警
写个"三合一"监控命令:
# 同时监控磁盘、内存、CPU
watch -d -n 5 '
echo "=== 磁盘 ===" && df -h / /data /backup 2>/dev/null
echo ""
echo "=== 内存 ===" && free -h
echo ""
echo "=== 负载 ===" && uptime && echo "进程数:" && ps aux | wc -l
'
放到一个单独的终端窗口里,一边干活一边瞟一眼,比一个个命令敲快多了。
场景3:等待某个条件出现
比如在等一个文件生成、等某个端口开放、等某个进程启动:
# 等脚本生成报告文件
watch -n 2 'ls -la /tmp/report_*.csv 2>/dev/null'
# 等服务端口开放
watch -n 1 'curl -s -o /dev/null -w "%{http_code}" http://localhost:8080/health'
# 等网卡接收流量
watch -d -n 2 'ip -s link show eth0 | grep "RX packets\|TX packets"'
一旦看到预期的变化,就说明条件满足了。
场景4:watch + crontab 组合
watch 管"实时观察",crontab 管"定期执行",两者互补。
先写个脚本做检查:
#!/bin/bash
# /usr/local/bin/check_disk.sh
# 检查磁盘使用率
DISK_USAGE=$(df / | tail -1 | awk "{print \$5}" | sed 's/%//')
if [ $DISK_USAGE -gt 85 ]; then
echo "磁盘使用率: $DISK_USAGE !!!"
else
echo "磁盘使用率: $DISK_USAGE% 正常"
fi
crontab 定期跑,把结果写文件:
# crontab 每5分钟检查一次,写结果到临时文件
*/5 * * * * /usr/local/bin/check_disk.sh > /tmp/disk_status 2>&1
然后 watch 读这个文件:
# 另一个终端 watch 读结果文件
watch -d -n 10 'cat /tmp/disk_status'
这样 crontab 负责后台定时检查,watch 让你实时看到最新结果。
场景5:排查网络连接异常
有次服务器出现大量 TIME_WAIT 连接,用 watch 实时追踪:
# 各个状态的连接数
watch -d -n 2 '
echo "=== 连接状态统计 ==="
netstat -ant | awk "{print \$6}" | sort | uniq -c | sort -rn
echo ""
echo "=== TOP10 远程地址 ==="
netstat -ant | grep ESTABLISHED | awk "{print \$5}" | cut -d: -f1 | sort | uniq -c | sort -rn | head -10
'
同一个窗口里同时看到连接分布和来源IP TOP10,排查问题非常直观。
今日作业
1. 打开两个终端,在第一个终端里运行:
`bash
watch -d -n 2 'ps aux | grep "$$" | grep -v grep'
`
2. 在第二个终端里执行一些简单命令(sleep 5, ls -R /tmp 等等)
3. 观察第一个终端里的进程变化
4. 再试试这个组合监控命令:
`bash
watch -d -n 3 '
echo "进程数: $(ps aux | wc -l)"
echo "内存: $(free -m | awk "/Mem:/{print \$3\"M / \"\$2\"M\"}")"
echo "磁盘: $(df -h / | tail -1 | awk "{print \$5}")"
'
`
5. 在第二个终端里打开 Chrome 或者启动一个程序,观察监控数据的变化
做完后,说说你在不同场景下会设置多少秒的刷新间隔,以及为什么。