说实话,写《Linux系统常用命令》这个系列挺费心血的。前六篇把最基础的 ls、cd、cp、mv、rm、grep、awk、sed、tar 这些高频操作都讲透了,但每次我打开评论区,总有人催更,问“什么时候讲 find”“scp 怎么用才能不踩坑”“线上 CPU 飙高到底怎么定位”。所以这篇第七篇,我打算换个思路,不按命令清单从头罗列,而是按“真实工作场景”来组织,挑那些最容易被忽略、但关键时刻能救命的命令和用法来讲。
这篇会覆盖文件定位与内容检索、远程传输与增量同步、进程排查与故障定位、vim 高频编辑效率,以及命令行的使用习惯养成。适合的人群很清晰:刚入门 Linux 一两年的运维、后端开发、嵌入式工程师,以及那些已经把基础命令背熟、但想知道“老手到底怎么用命令”的人。
1. 文件定位与内容检索:find、grep 的高级打开方式
很多人的 find 用法停留在 find / -name "xxx",grep 停留在 grep "xxx" file。这没有错,但面对真实的服务器环境,这两个命令的组合使用才是效率的关键。
1.1 find 的精确筛选:不再大海捞针
find 最强的地方不是按名字找文件,而是按“元数据”组合筛选。线上排查磁盘占用时,我需要找出所有大于 500M、超过 30 天没动过的日志文件,一条命令就能扫完:
bash复制find /var/log -type f -size +500M -mtime +30 -exec ls -lh {} \;
这里 -type f 限定只查普通文件,-size +500M 是大文件,-mtime +30 是修改时间早于 30 天前。-exec ls -lh {} \; 是逐个把结果取出来看大小,说白就是“找到什么,就对它执行什么操作”。
很多人在 -exec 的结尾符号上反复纠结。我记了这么多年只记住一个规律:{} 是占位符,代表每个匹配到的文件,后面的 \; 是命令结束符,必须转义。如果你觉得这个写法难记,还有一个更简单的方法:用管道加 xargs,效果类似,但处理大量文件时更稳:
bash复制find /data/logs -name "*.log" -mtime +7 | xargs rm -f
但我不建议你这么莽撞地删,生产环境至少先 ls 一次确认。另外一个实用场景是按时间精确“掐点”找,比如游戏服务器凌晨 3 点 20 分左右出现报错,想查这个时间点改过的配置文件:
bash复制find /etc/nginx -type f -newermt "2025-01-08 03:15:00" ! -newermt "2025-01-08 03:30:00"
-newermt 可以对单个文件直接带日期时间比较,配合 ! -newermt 就能圈定一个时间窗口。这个用法在定位“谁动了我的配置”时特别有效,比翻 bash 历史快得多。
1.2 grep 与 rg:内容检索的降维打击
grep 系里有两个场景我会区分:日志已经落盘,用 grep -E "ERROR|FATAL" app.log 是常规操作;但如果是搜一个几万行代码的工程,我更推荐用 rg(ripgrep)。rg 是 Rust 写的,性能比 grep 快很多,而且默认会忽略掉 .gitignore 里面的文件和二进制文件,专注代码搜索引擎。
上个月帮同事定位一个老项目里的接口定义,代码量大概十几万行,用 grep 全量递归搜要等将近 7 秒:
bash复制grep -r "getUserInfo" /data/project/src
换 rg 之后,1 秒内出结果:
bash复制rg "getUserInfo" /data/project/src
如果你暂时没条件装 rg,grep 也够用,但一定记住两个选项:-n 显示行号,-C 5 显示匹配行前后各 5 行上下文。没有行号的 grep 结果在大型日志里等于没用。
还需要特别注意 grep 的经典坑:搜索的字符串如果带 - 开头,会被当成选项解析。比如搜 -auth 这个词,必须写成:
bash复制grep -- "-auth" login.log
-- 之后的参数全部视为字面值,这是很多新手踩过坑的地方。
1.3 locate:最被低估的快速查找
find 是按目录实时扫,代价是文件量大时非常慢。如果你只是想快速知道“这个文件在不在系统里”,用 locate 才是最优解。它查询的是一个预生成的文件索引库,速度是毫秒级:
bash复制locate nginx.conf
但 locate 的索引不是实时更新的,新文件必须等 updatedb 跑完才能被发现。有些最小化安装的 Linux 发行版没装 locate,需要手动装一下。我的建议是:日常快速定位用 locate,需要精确条件筛选用 find,两者配合几乎覆盖所有找文件场景。
2. 远程传输与同步:scp、rsync、sftp 的区别和选型
服务器之间传文件,这是运维和开发每天都要面对的事。很多教程会告诉你 scp 怎么用、rsync 怎么用,但没有说清楚什么时候该用哪个。我根据自己的经验,给出一套选型逻辑。
2.1 scp:简单直接的一次性传输
scp 最大的优点是简单,全系统自带,不需要额外配置。基本用法:
bash复制scp -P 2222 /data/backup.tar.gz root@192.168.1.10:/data/
从远程服务器拉文件下来,方向反过来:
bash复制scp -P 2222 root@192.168.1.10:/data/app.log /data/local/
有几个细节经常被忽略:第一,指定端口是大写 -P,SSH 登录用大写,而 ssh 命令本身是小写 -p,这个字母大小写错位太容易出错了。第二,传输目录要加 -r:
bash复制scp -r -P 2222 /data/config/ root@192.168.1.10:/data/
第三,scp 默认不校验文件完整性,传完最好用 md5sum 对比一下两边校验值,尤其是传压缩包或二进制程序。第四,断点续传?scp 不支持。传了一半断了,只能从头再来,所以大文件我建议优先考虑 rsync。
2.2 rsync:增量同步的生产力工具
rsync 是我心中“远程传输”的王者。它最核心的能力是增量同步:第一次全量,之后只传变化的部分,这个机制在备份场景下非常省带宽。
最常用的组合是:
bash复制rsync -az --progress /data/project/ root@192.168.1.10:/data/project/
-a 是归档模式,保留权限、时间戳、软链接等元数据;-z 是传输时压缩。很多人会问为什么要用 -a?因为如果你传输的是程序目录,权限和属主变了,程序部署上去很可能起不来。
要做“严格镜像同步”,也就是让目标目录和源目录完全一致,可以加 --delete:
bash复制rsync -az --delete /data/site/ root@192.168.1.10:/data/site/
这个命令会删除目标目录里源目录没有的文件,相当于是“双向校准”。但用 --delete 务必谨慎,目录路径写错可能会导致目标端被清空。我在生产上经历过一次教训,所以后来定了个规矩:凡是带 --delete 的命令,先在源目录后面加 --dry-run 跑一遍,看看它会删什么:
bash复制rsync -az --delete --dry-run /data/site/ root@192.168.1.10:/data/site/
2.3 sftp:交互式管理的合适选择
如果你只想临时操作远程服务器上的几个文件,又不想记复杂的命令行参数,sftp 是体验最好的方式。连接方式和 ssh 一样:
bash复制sftp root@192.168.1.10
进去之后是交互式界面,ls 查看远程目录,lcd 切换本地目录,get 下载文件,put 上传文件。sftp 支持 Tab 补全,操作体验有点像个简易版 FTP 客户端。它还支持通配符批量下载:
bash复制mget *.log
有交互提示,适合处理数量不多、需要人工判断的传输任务,安全性也比 FTP 高,因为走的是 SSH 协议,账号密码都是加密传输的。
3. 进程排查与故障定位:从 ps 到 gdb 的一站式思路
这部分我想重点展开。因为招聘面试里常考命令,但真正的线上问题是多个命令组合排查出来的。
3.1 先看进程:ps 与 top/htop 的高频组合
排查问题第一步永远是搞清楚“当前系统上正在运行什么”。我最常用的命令是:
bash复制ps aux --sort=-%cpu | head -20
--sort=-%cpu 按 CPU 使用率降序,head -20 只看前 20 条,一眼看到哪个进程在吞 CPU。如果内存不够用,换成 --sort=-%mem。
ps aux 输出的每一列我都建议背下来:USER 是进程用户,PID 是进程号,%CPU 和 %MEM 是资源占用,VSZ 是虚拟内存大小,RSS 是物理内存大小,TTY 是终端,STAT 是进程状态,START 是启动时间,TIME 是累计占用 CPU 时间,COMMAND 是命令。其中 STAT 列的 D 表示不可中断的睡眠,R 表示运行,S 表示睡眠,T 表示暂停,Z 表示僵尸进程。
ps 是静态快照,要看实时变化就必须用 top 或 htop。top 进入交互界面之后,按 P 按 CPU 排序,按 M 按内存排序,按 1 看每个 CPU 核心的负载,按 c 显示完整命令行。htop 是 top 的增强版,可以鼠标操作,F6 按键能选择排序字段,颜色标注也更直观。有些环境没预装 htop,我一般直接用 top 也完全够用。
3.2 端口与文件占用:lsof 和 ss 的典型场景
遇到“端口被占用,程序起不来”的问题,第一个命令就是:
bash复制lsof -i:8080
这条命令会列出占用 8080 端口的进程 PID,接下来就可以直接 kill -9 PID。有时候会看到 COMMAND 列是 java 但 PID 是子进程,这时候顺着 ps aux | grep PID 往上找父进程即可。
lsof 还能用来查看“文件被谁占用”。比如你想删除一个日志文件,系统提示 Text file busy,说明有进程正在用这个文件,此时用:
bash复制lsof /var/log/app.log
就能看到具体是哪个 PID 在占用。
现在很多新版系统里,netstat 命令可能没装,ss 成了查看网络连接的更现代替代方案。查看所有监听端口:
bash复制ss -lntp
-l 表示只显示监听中的 socket,-n 是数字地址不反解域名,-t 是 TCP,-p 是显示进程信息。这一条命令比 netstat 快,输出也更简洁,建议尽早养成用 ss 的习惯。
3.3 strace:追踪系统调用的万能钥匙
当程序“卡住”或者“假死”的时候,光看 ps 和 lsof 往往不够,你要知道进程到底在做什么。strace 就是这样一个工具,它能跟踪进程发起的每一次系统调用。
线上案例:某个服务突然响应缓慢,CPU 不高,内存也不高,但请求就是超时。我用:
bash复制strace -tt -p 8321
实时跟踪 PID 为 8321 的进程。几秒后看到输出停在 connect(3, {AF_INET, ...}, 16) 这个调用上,说明进程卡在一个网络连接请求上。再用 lsof 查这个 socket 对应的目标地址,发现是要连一个内网数据库的 IP,但那个数据库已经宕机了,连接请求一直在等待超时。整个过程从接手到定位只用了 5 分钟。
strace 最常用的参数是 -p PID 跟踪已有进程,-e trace=file 只看文件相关系统调用,-o output.log 把输出保存到文件。线上排查不建议直接 strace 生产进程阻塞很久,先 strace -f -c -p PID 跑几秒,等一个统计汇总,再用 -e trace=... 定向跟踪,效果会好很多。
注意 strace 会让被跟踪的进程慢非常多,在高频调用下尤其明显。所以不要在白天高峰期直接上 strace,最好是流量低峰或者先把进程切换到副本处理。
3.4 gdb:定位崩溃问题的最后手段
如果你有一个 C/C++ 程序崩溃了,只留下一个 core dump 文件,那么 gdb 是分析崩溃原因的标准工具。虽然 gdb 本身是一个庞大的调试器,日常工作中常用的命令其实没几个:
bash复制gdb ./app core
进入 gdb 交互界面后,第一条执行的命令是 bt(backtrace),它会打印崩溃时的调用栈,直接告诉你程序崩在哪个函数、哪一行。这条命令解决了我至少 80% 的崩溃分析。
如果崩溃发生在第三方库或没有符号信息的地方,栈可能不完整,这时用 info registers 看寄存器值,用 frame N 切换栈帧,用 print 变量名 查看函数参数和局部变量。比如:
bash复制(gdb) frame 2
(gdb) print buffer
就能看到上层调用时的数据内容,判断是不是内存越界或者空指针。
还有一个高频场景:排查“程序莫名其妙卡死”。用 gdb attach 到进程:
bash复制gdb -p PID
然后执行 bt,能看到它卡在哪个函数。如果卡在某个锁的等待上,你就能立刻看出来。排查完执行 detach 退出,程序会继续正常运行,注意这里不要 quit 后乱敲 y,否则很容易把进程一起终止。
4. vim 高频编辑效率:从“会用”到“用得溜”
vim 是 Linux 服务器上绕不开的编辑器。很多人的使用水平停留在 i 进入插入、Esc 退出、wq 保存的层面,这没问题,但遇到“改 30 个相同字段”“批量缩进 30 行”这种场景,就显得很慢了。提升 vim 效率不需要背几千条命令,只要掌握下面几个组合就够用。
4.1 查找和替换的精准控制
日常最实用的查找操作是按下 / 输入关键字,回车跳转,按 n 跳到下一个匹配,按 N 跳回上一个。
批量替换建议使用全局替换命令:
bash复制:%s/old_string/new_string/g
% 代表整个文件,s 是替换,g 是替换一行内所有匹配(不加 g 只替换每行第一个)。如果只想在某个行号范围内替换,把 % 改成行号区间:
bash复制:100,200s/old_string/new_string/g
这个命令只处理 100 到 200 行之间,非常精确。
替换前最好先加一个确认选项 c:
bash复制:%s/old_string/new_string/gc
每次替换都会询问,让你看清楚再决定,避免误替换。我在改线上配置文件时从不用不带 gc 的全量替换,不是怕慢,是怕把说明文档里的类似字段也一起改了。
4.2 多文件编辑与窗口分屏
日常运维中经常遇到“要把 A 文件里的某段配置复制到 B 文件”这种场景。老办法是打开 A 文件,复制,退出,打开 B 文件,粘贴。vim 的 -o 多窗口模式能一步解决:
bash复制vim -o /etc/nginx/nginx.conf /etc/nginx/conf.d/default.conf
进入后是上下分屏,按 Ctrl+w 然后按 w 可以在窗口间切换。复制时 yy 复制光标所在行,切到另一个窗口后按 p 粘贴,整个过程不用反复进出文件。对开发来说,vim -O(大写)是左右分屏,适合一边看代码一边看文档。
4.3 宏录制:批量改写的“录播”技巧
宏录制是我最想推荐给所有人的功能。它的逻辑是“录下你的一次操作,然后重复执行任意多次”。
假设我有一个配置文件,里面有 30 行都是 host=192.168.1.1,需要全部改成 host=192.168.1.2。先录制一次操作:
- 把光标移到第一行要改动的地方,按
qa开始录制宏到寄存器 a。 cw修改当前单词,输入192.168.1.2,Esc 回到正常模式。- 按
j跳到下一行。 - 按
q停止录制。
然后选中接下来要执行宏的所有行,或者直接按 30@a,vim 就会把宏重复执行 30 次,每一行都完成同样的修改。这个功能在重复性修改中实在太强了,学会之后,你会觉得之前的逐个手改是在浪费生命。
4.4 常见 vim 问题速查
| 问题 | 原因 | 解决 |
|---|---|---|
| 粘贴代码格式全乱 | 开启了自动缩进 | 粘贴前先 :set paste,粘贴后 :set nopaste |
| 打开时提示 swap 文件存在 | 上次异常退出 | 按 r 恢复内容,确认后删除 .swp 文件 |
| 按 Esc 没反应 | 想退出插入模式但键位映射错误 | 用 Ctrl+[ 等效替代 Esc |
| wq 保存提示“只读文件” | 文件权限不是当前用户 | :wq! 强制写(前提是你对文件有权限) |
| 不小心改乱了 | 还没保存 | 按 u 撤销,多次按多次撤销 |
按了 Ctrl+S 界面卡住 |
终端流控被暂停 | 按 Ctrl+Q 恢复 |
粘贴代码乱这个是所有新手都会遇到的坑:如果你把一个缩进很规范的代码块粘到 vim,它可能在每一行前追加额外缩进,整个代码结构全乱。设置 :set paste 后,vim 不再做任何自动缩进,粘贴的原文是什么样,进去就是什么样。
5. 命令行使用习惯:让效率提升一倍的关键细节
讲完具体命令,最后想聊一点“软技能”——怎么把命令用出更好的习惯。很多老手并不是记住了更多命令,而是养成了让命令更好用的习惯。
5.1 history:给命令行为装上“回放”
每次敲过的命令都会记在 ~/.bash_history 里。按 Ctrl+R 进入反向搜索,直接输入关键字,比如我敲 rsync,终端会自动带出我最近一次使用过的 rsync 命令,回车即可重新执行。
查找某个历史命令:
bash复制history | grep "rsync"
这个组合很常用,但 history 默认只保留当前 shell 退出时写入的内容,有时候你会遇到“明明上一条命令还能看到,但 history 里查不到”的情况。这是因为多终端同时工作时,每个终端的命令是退出时才写回文件,互相覆盖。解决办法是在 ~/.bashrc 里加:
bash复制export HISTFILESIZE=20000
export HISTSIZE=10000
shopt -s histappend
histappend 让命令追加写入而不是覆盖写入,多终端就不互相打架了。还可以设置:
bash复制export HISTTIMEFORMAT="%F %T "
让 history 输出带上日期和时间戳,排查“当时到底敲了什么”时这招很有用。
5.2 alias:给常用长命令起个短名
alias 能把又长又容易出错的命令缩成一个词。我个人的 .bashrc 里长期维护着:
bash复制alias rm='rm -i --preserve-root'
alias cp='cp -i'
alias mv='mv -i'
alias ll='ls -alF'
alias untar='tar -xzf'
alias grep='grep --color=auto'
rm -i 是删除前逐条确认,虽然很多人嫌麻烦,但我更怕误删。grep --color=auto 让关键字段标色,读日志体验完全不一样。这些 alias 在新装的机器上都要重新配置,所以我维护了一份 dotfiles 仓库,换环境直接克隆下来建立软链接即可。
5.3 man 和 tldr:快速查命令用法
遇到不熟悉的命令,第一反应不是去搜索引擎,而是:
bash复制man 命令名
man 里信息最全,但排版冗长。如果只想快速看“这个命令怎么用”,推荐装 tldr:
bash复制tldr tar
它给出的是精简的示例集合,每个参数都有实际例子,比如 tar -xzf file.tar.gz 解压、tar -czf file.tar.gz dir/ 压缩,直接拷贝即可。装 tldr 只需要一句:
bash复制npm install -g tldr
或者用 pip 装。tldr 这个名字是“太长不看”的英文缩写,定位就是快速上手命令。
5.4 后台运行:nohup 与 setsid 的正确使用
最后一个高频场景是“命令跑很久,我想关掉终端但它不能断”。最常用的写法:
bash复制nohup python train.py > train.log 2>&1 &
nohup 让进程忽略 SIGHUP 信号,> train.log 把标准输出写入日志,2>&1 把错误输出也合并到同一个日志,最后的 & 让命令在后台执行。这个组合我几乎每天都在用,训练模型、打包大目录、迁移数据都靠它。
如果希望进程完全脱离当前终端的关系,可以用 setsid:
bash复制setsid python train.py > train.log 2>&1 &
setsid 让进程变成新的会话组长,彻底脱离终端生命周期。在自动化脚本里,我常用它替代 nohup,因为不需要额外输出 nohup.out 文件,干净很多。
还有一个容易踩的坑:后台任务不要用 Ctrl+Z 停住再 bg 恢复,这种方式在关掉终端之后依然可能被杀掉。真正要“退出终端后继续跑”的任务,直接 nohup 或 setsid 才是正解。
6. 写在最后的一些个人经验
命令这个东西,用起来不难,难的是“在什么场景想起用什么命令”。我见过很多同事把 grep、ps 背得滚瓜烂熟,但遇到真实的故障时,还是容易拿着 ps 和 top 反复刷屏,始终定位不到根因。我自己的经验是:与其背命令清单,不如多复盘问题。每次线上出现故障,我都会把排查路径写进一个 markdown 文档,内容包括当时的现象、用到的命令、命令输出说明了什么、最终怎么定位修复。
坚持半年之后,你会有一种很强的“条件反射”:看到端口占用会自然想到 lsof,看到进程卡住会想到 strace,看到文件找不到会想 find 还是 locate,看到要传大文件会直接敲 rsync。这种反应不是背出来的,是在一次次真实问题里磨出来的。
最后再分享一个实用小技巧:如果你在操作生产环境前心里没底,先敲 echo 把命令打印出来检查一遍。比如要批量删除文件,先运行 find /data -name "*.tmp" | xargs echo,确认输出列表无误后,再把 echo 换成 rm -f 执行。多花十秒钟检查命令,少了无数个熬夜补救的夜晚。希望这篇第七篇对你有用,我们之后的系列内容里再继续聊。
