大家好,我是程序员柏风,AI 最全的 Vibecoding 学习地图 http://coderoadmap.cn 作者。
常用命令
这一课你将能做到
- 用
cp/mv/rm/mkdir管理部署文件,用cat/head/tail/less翻阅配置与日志,用tail -f实时盯启动日志 - 组合
find + grep + du + sort完成三个生产高频任务:日志中搜异常堆栈、找出占磁盘的目录、定位超过 100M 的大文件 - 用
tar打包备份 JAR 与配置、用rsync增量同步发布产物,并知道两者差别
为什么要学
前两课你有了目录树概念和权限意识,但手上「兵器」还不够:面试官问「线上 CPU 飙高你怎么查」「磁盘满了怎么找元凶」,靠的不是背概念,而是 find、grep、du 这类命令的组合拳。
后端部署场景里,你这辈子在 Linux 上敲得最多的就是三类命令:看日志(tail/grep)、管文件(cp/mv/rm/tar)、查资源(df/du/ps)。本课把这三类一次练熟,全部命令在 Ubuntu 直接可执行,WSL2 或云服务器上跑即可。
先建立图像
把常用命令按「运维四问」归位:
运维四问 对应兵器
─────────────────────────────────────────────────────
文件在哪?动它! ls cd cp mv rm mkdir touch find
内容是什么? cat head tail less grep wc
东西归谁、占了多少? df du stat ls -h ps top
怎么搬运/备份? tar rsync scp ln
再记两个组合技的思路:
- find 找路径,grep 找内容:找「哪个文件叫 xx」用 find;找「哪个文件里有 xx 字样」用 grep。
- du 管目录大小,df 管磁盘水位:df 看整体(分区满了没),du 钻进去看是谁撑的。
跟着做
建一个实验场,本课所有命令都在里面练:
mkdir -p ~/cmd-lab/{logs,conf,releases} && cd ~/cmd-lab
步骤 1:文件操作五件套
mkdir -p releases/v1 releases/v2 # -p 连父目录一起建、已存在不报错
touch releases/v1/backend.jar # 造空文件
echo "fake jar v1" > releases/v1/note.txt # 写内容
cp releases/v1/note.txt releases/v2/ # 复制
cp -r releases/v1 releases/v1.bak # -r 复制目录
mv releases/v2/note.txt releases/v2/note.md # 改名(mv 本质就是改名/移动)
mv releases/v1.bak /tmp/ # 移动到别处
rm releases/v2/note.md # 删文件
rmdir releases/v2 # 删空目录;非空用 rm -r(谨慎!)
ls -R releases # -R 递归列出确认结果
安全习惯:rm 前先用同参数 ls 看一遍会删什么;rm -rf 只对明确路径使用,变量路径先 echo 展开。
步骤 2:看文件的四把勺子
# 造一份像样的应用日志
for i in $(seq 1 200); do
echo "2026-10-06 10:$(printf %02d $((i%60))) INFO request /api/map/$i ok" >> logs/app.log
done
echo "2026-10-06 10:23:45 ERROR java.sql.SQLException: Connection refused" >> logs/app.log
echo "2026-10-06 10:24:01 ERROR java.lang.OutOfMemoryError: Java heap space" >> logs/app.log
cat logs/app.log | head -3 # 只看前 3 行
tail -n 5 logs/app.log # 只看最后 5 行
tail -n 20 logs/app.log # 启动失败时最常敲的:看日志末尾 20 行
less logs/app.log # 翻页器:空格下一页,G 跳末尾,/ERROR 搜索,q 退出
wc -l logs/app.log # 共 202 行
步骤 3:实时日志 tail -f(部署必练)
# 开一个窗口跑(会一直滚动等待新内容):
tail -f logs/app.log
# 另开一个窗口往里写一行:
echo "2026-10-06 11:00:00 INFO Started BackendApplication in 3.9s" >> ~/cmd-lab/logs/app.log
# 回到第一个窗口 → 新行立刻出现。Ctrl+C 退出 tail -f。
# 常用变体:
tail -f logs/app.log | grep --line-buffered ERROR # 实时滚动中只看 ERROR 行
tail -F logs/app.log # -F:日志被轮转(文件被改名重建)后自动跟到新文件
「启动服务 → tail -f 看日志 → 等到 Started/报错」是 Java 部署的标准姿势,比反复 cat 高效得多。
步骤 4:grep——日志里捞异常(最高频)
grep ERROR logs/app.log # 所有 ERROR 行
grep -c ERROR logs/app.log # 计数:2
grep -n "SQLException" logs/app.log # 带行号,方便定位
grep -i "error" logs/app.log # -i 忽略大小写
grep -v INFO logs/app.log # -v 反选:排除 INFO 行
grep -A 3 "SQLException" logs/app.log # 命中行 + 之后 3 行(异常堆栈关键)
grep -B 1 "OutOfMemory" logs/app.log # 命中行 + 之前 1 行
grep -E "ERROR|WARN" logs/app.log # -E 扩展正则:多关键词或
grep -r "Connection refused" ~/cmd-lab/ # -r 递归搜整个目录下所有文件
记忆锚点:-c 计数、-n 行号、-i 忽略大小写、-v 排除、-A/-B 上下文、-r 递归、-E 多模式。查 Java 异常时 -A 10 把堆栈一起带出来最实用。
步骤 5:find——按名字、大小、时间找文件
find ~/cmd-lab -name "app.log" # 按文件名(全名匹配)
find ~/cmd-lab -name "*.log" # 通配符:所有 log
find /var/log -name "*.gz" -mtime +7 # 7 天前修改过的压缩日志
find ~/cmd-lab -size +1M # 大于 1M 的文件
find ~/cmd-lab -type d -name "releases*" # -type d 只找目录
find ~/cmd-lab -name "*.tmp" -delete # 找到即删(先不带 -delete 预览!)
铁律:先执行不带 -delete 的 find 看清单,确认无误再加 -delete。
步骤 6:df + du——磁盘水位与元凶定位
df -h # 各分区使用率(重点看 / 的 Use%)
df -i # inode 使用率(海量小文件场景)
du -sh ~/cmd-lab # -s 汇总 -h 可读:这个目录一共多大
du -h ~/cmd-lab | sort -rh | head -5 # 从大到小排,前 5 名
du -sh /var/log /tmp /www 2>/dev/null # 一次量多个常见嫌疑目录
磁盘告警时的标准动作:df -h 确认哪个分区满 → du 从 / 逐层下钻 → 找到大日志/旧备份 → 确认无用后删除或压缩。
步骤 7:tar 打包与 rsync 同步
# tar:czf = c创建 z用gzip压缩 f指定文件名
tar czf backend-backup-$(date +%Y%m%d).tar.gz releases/v1/
ls -lh *.tar.gz # 确认包已生成
tar tzf backend-backup-*.tar.gz # t 列表:不解包先看里面有什么
mkdir restore && tar xzf backend-backup-*.tar.gz -C restore/ # x 解包 -C 指定目标目录
ls -R restore
# rsync:增量同步(只传有变化的部分),发布产物常用
rsync -av releases/v1/ releases/v2/ # -a 保留属性 -v 显示过程
echo "changed" >> releases/v1/note.txt
rsync -av releases/v1/ releases/v2/ # 第二次只同步差异
rsync -av --delete releases/v1/ /tmp/mirror/ # --delete 使目标与源完全一致(慎用)
注意 rsync 的尾斜杠:src/ 同步「目录内容」,src(不带斜杠)会把 src 目录本身拷过去——差一个字符,结果不同。
步骤 8:信息查看与打包成一条链
stat releases/v1/note.txt # 文件元信息:大小、时间、权限、inode
date +%F_%T # 当前时间,写备份文件名常用
uptime # 负载一句话
# 综合链:今天日志里 ERROR 出现在哪几个时刻?
grep ERROR logs/app.log | awk '{print $1, $2}' | sort | uniq -c
# awk 取第1、2列(日期、时间),sort 排序,uniq -c 去重计数 —— 管道组合的威力
讲清楚要点
- find 与 grep 分工:find 按「文件属性」(名字/大小/时间/类型)找文件本身;grep 在文件内容里按文本/正则找行。「找文件名用 find,找内容用 grep」。
- tail -f 是部署伴生命令:启动 Java 服务后第一时间
tail -f盯日志,直到看到Started XxxApplication或第一行异常。日志轮转频繁的场景用-F更稳。 - grep -A/-B/-C 是看异常堆栈的正解:Java 异常天然多行,只 grep 命中行会丢堆栈。
grep -A 10 "Exception"比逐页翻日志快十倍。 - df 与 du 永远成对出现:df 告诉你「满了」,du 告诉你「谁撑的」。两者数字差距巨大时通常是「文件已删除但进程仍占用」(见卡点急救)。
- tar 三件套 c/x/t + z + f:
czf打包压缩、xzf解包、tzf预览。记住「c 创 x 解 t 看」,f后面紧跟文件名。 - rsync 优于 cp 的场景:可断点续传、只传增量、可跨机(走 SSH,SSH 课会用
rsync -avz向服务器发布产物)、--delete能做镜像。日常单文件搬运 cp 就够。
你可能会懵的地方
rm删掉的文件能恢复吗? 常规手段基本不能(ext4 删除后数据块标记复用)。所以删除靠「预防」:危险操作前先ls预览、先tar备份、用回收站式习惯(mv到 /tmp 而不是直接 rm)。*通配符和正则是一回事吗? 不是。*在 shell 里匹配「任意字符的文件名」(*.log);grep 里的正则*表示「前一字符重复 0+ 次」。混着想会写出错误模式。grep 用-E才是完整的扩展正则。- 为什么 du 统计的目录比 df 显示的占用小很多?
两个常见原因:① 已删除但仍被进程占用的文件(du 看不见、df 算在内);② 硬链接只算一次而挂载点重复统计。配合
lsof | grep deleted(进程课会用到)排查。 - 命令输出中的
-rw-r--r--我还是没完全懂? 回顾文件课:三组 rwx 权限位,本课的ls -lh(-h 人类可读大小)会高频用到。两课配合食用。 - awk/sed 要学到什么程度?
后端够用主义:
awk '{print $1}'取列、sed -n '100,120p'看区间行、sed -i 's/old/new/g'批量替换(编辑器课会实操 sed)。不必背复杂语法,记住这三个套路。
错法对照
| 错法 | 问题 | 正解 |
|---|---|---|
rm -rf $DIR/*(DIR 未定义) | 展开成 rm -rf / 级灾难 | 使用前 : "${DIR:?未设置}" 或先 echo 确认 |
find ... -delete 直接上 | 删错范围无法挽回 | 先运行 find 预览清单,确认后加 -delete |
grep Exception app.log 后逐页找堆栈 | 堆栈被截断,定位极慢 | grep -A 10 Exception app.log 带上下文 |
cp -r dir dir.bak 后在备份里改了原目录 | 方向搞反,改错对象 | cp 后 ls -l 两边确认;重要操作先 pwd |
tar czf backup.tar.gz backup.tar.gz | 把包打进自己,报错或损坏 | 排除自身:--exclude=backup.tar.gz |
rsync -av src dst 忘写尾斜杠 | 多套一层目录:dst/src/... | 明确语义:同步内容写 src/ |
磁盘满直接 rm 正被写的日志 | df 仍显示满(进程占用) | 重启对应服务或 truncate -s 0 文件 清空 |
卡点急救
- 删了大日志但
df -h还是满的:进程仍持有该文件的句柄。lsof +L1或lsof | grep deleted找到占用进程,重启该服务释放;应急可用: > /proc/<PID>/fd/<N>清空(高风险,先确认)。预防:清日志用truncate -s 0 app.log或> app.log,不要 rm 正被写的文件。 - grep 报 binary file matches:文件被判定为二进制(混入了控制字符)。加
-a按文本处理:grep -a ERROR app.log。 - tar 解压报
Unexpected end of file:包不完整,通常是 scp 中断或磁盘满导致。校验大小与源文件是否一致,重新打包/传输。 - less 里找不到东西:
/关键词向下搜、?关键词向上搜、n下一个、G跳到文件尾(大文件先用 G 看最新再往上翻)、-N显示行号(启动时less -N file)。 - 中文日志乱码:
file app.log看编码;GBK 日志转 UTF-8:iconv -f GBK -t UTF-8 app.log > app-utf8.log。
面试常问
- 线上日志文件 10G,怎么查今天的 ERROR?
先用时间缩小范围(日志按天/小时切割时直接找对应文件),
grep -c ERROR量化,grep -n -A 10 "Exception" today.log | less带堆栈看关键样本;实时问题用tail -f | grep --line-buffered ERROR。大文件不要直接 cat 整个文件。 - 磁盘使用率告警,如何定位并处理?
df -h确认分区 →du -sh /* 2>/dev/null逐层下钻找大目录 → 常见元凶:应用日志、旧备份、Docker 镜像堆积、/tmp → 确认后删除或压缩归档(tar czf 后移走);若是 inode 满(df -i)则清理海量小文件目录。 - find 和 grep 的区别?常用参数? find 按文件属性找文件(-name 名字、-size 大小、-mtime 修改天数、-type 类型,可接 -exec/-delete);grep 按内容找文本行(-i 忽略大小写、-n 行号、-r 递归、-v 反选、-c 计数、-A/-B/-C 上下文、-E 扩展正则)。
- 怎么实时监控日志里的关键字?
tail -f app.log | grep --line-buffered "ERROR"(--line-buffered 保证逐行刷新不被缓冲吞掉);要统计频次可接| awk '{print $1}' | uniq -c。 - tar 的 czf/xzf/tzf 分别是什么?
c=create 创建包、x=extract 解包、t=list 只列内容;z=gzip 压缩、f=指定文件名。组合:
tar czf out.tar.gz dir/打包、tar xzf out.tar.gz解包、tar tzf out.tar.gz预览(解包前先 t 一遍是好习惯)。
自测三问
- 找出
/var/log下 7 天内修改过的、名字含backend的文件并统计行数,命令链怎么写? grep -A 3 -B 1 "OutOfMemory" app.log的输出会包含什么?为什么查 Java 异常必须带上下文?df -h显示磁盘 95%,但du -sh /加起来只有一半,可能是什么原因?用什么命令验证?
小结一句话
后端在 Linux 上的日常 = 文件操作 + 日志三勺(cat/tail/less)+ grep 捞异常 + find/du 定位资源 + tar/rsync 搬运备份——这五组练成肌肉记忆,排障就不再需要「重启大法」。
延伸
- GNU Coreutils 手册(ls/cp/du 等官方文档)
- GNU Grep 手册
- 下一课预告:编辑器与配置——改 nginx.conf、改 application-prod.yml、改 systemd 单元文件,都绕不开服务器上唯一可靠的编辑器 vim。十分钟学会「够用一辈子」的那 20% 命令。