CodeRoad Map 程序员的学习成长路线图。内容免费开放,登录后可同步路线图与课时进度。
由 程序员柏风 独立维护 · 关于作者
学习 更多
常用命令 ls、find、grep、tail、curl。
常用命令
这一课你将能做到
用 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 搬运备份——这五组练成肌肉记忆,排障就不再需要「重启大法」。
延伸