ARTICLE · INTELLIGENCE

战地情报 · 详情页

来自尧图项目组的一线实战观察与深度解析

Linux命令实战指南:从rm -rf到history,掌握原理与排障思维

Linux命令实战指南:从rm -rf到history,掌握原理与排障思维 前阵子公司来了个刚毕业的实习生抱着笔记本过来问我Linux删除文件夹用什么命令我随口回了一句rm -rf他又追问那我在网上搜到的为什么是rmdir这问题看似基础其实戳中了很多人学Linux命令的痛点——大家以为命令是靠背的背得越多越厉害。真不是这样。Linux命令更像你手里工具箱里的扳手和螺丝刀你得知道每把工具是干什么的、什么时候用哪把、用了之后会有什么后果而不是把所有工具的名字背一遍就完事。这篇内容我打算换个思路来写不给你堆一份Linux常用命令大全式的清单而是带着你从头梳理一遍命令背后的运行逻辑是什么高频命令的参数怎么选才不出事history、vim、git这些天天要用的命令有哪些提效姿势以及真实运维场景里遇到故障时命令是怎么一步步帮你定位根因的。不管你是刚接触Linux的新手还是准备面试的求职者或者已经在生产环境摸爬滚打的运维这篇文章应该都能给你一些平时文档里查不到的经验。1. 别急着背命令先搞懂命令的三层结构1.1 命令的本质一切皆文件命令就是可执行文件Linux世界里有一句老话叫一切皆文件。命令也不例外。你敲下的每一条命令本质上都是一个存放在某个目录下的可执行文件它可能是用C写的二进制程序也可能是用Python、Shell写的脚本。当你输入ls -l /usr/bin/时你会看到成千上万个文件名那些其实都是你可以直接拿来用的命令。Shell我们平时敲命令的那个界面干的事情很简单读取你输入的一行字符把第一个词当作命令名在PATH环境变量指定的目录列表里挨个查找这个可执行文件找到就执行并把后面的词作为参数传给它。这就像你打电话命令名是你要拨的号码参数是拨通后你话术里的关键词操作对象就是电话那头具体要找的人。不理解这个底层逻辑你就很容易闹出为什么我明明删不掉文件夹却还要用rmdir这种困惑——因为rmdir这个命令的源码逻辑只允许删除空目录它天生就不负责递归删除这件事而rm -rf才会一路闯进子目录把所有东西都清掉。弄懂了这一点你再看网上那些Linux命令大全心态就完全不一样了你不会再企图把几百条命令全塞进脑子里而是会想这个命令解决什么问题它和另一个命令有什么区别它的参数设计为什么这么怪一旦你带着这种疑问去学记忆效率会翻好几倍。1.2 万能的求助三件套help、man、info我刚工作那会儿最喜欢问前辈的一句话是这个命令怎么用。后来被前辈怼了一句你自己不会看文档吗我才老老实实养成了查文档的习惯。面对一个陌生命令你其实有三个递进的求助渠道。第一层是命令 --help它返回的是精简版的参数说明适合快速扫一眼这条命令到底能干嘛。第二层是man 命令这是系统内置的完整手册里面有详细说明、参数解释、示例甚至还有作者信息和Bug列表。第三层是info 命令比man更详尽还支持超链接跳转不过阅读体验笨重一点我平时用得不多。这里多说一句man的小技巧很多人打开man手册后不知道怎么看卡在q都退不出去这一步。其实man内部就是调用less分页器来显示内容的所以less的所有交互快捷键它都支持按/输入关键词可以搜索按n跳到下一个匹配项按q退出。如果你用man 5 passwd这种方式去查你会发现奇怪的现象——为什么会弹出两个不同的文档因为Linux手册是分章节的1是用户命令5是配置文件格式8是系统管理命令。同一个关键词在不同章节可能指代完全不同的东西加个数字参数就是精准定位。type这个命令也值得单独拎出来讲。它能告诉你一条命令到底是内置的Shell关键字、外部可执行文件还是别名。比如你在服务器上执行type cd大概率会看到cd is a shell builtin——这说明cd并不存在于/usr/bin目录里而是Shell自己实现的逻辑。知道这一点你就能理解为什么有些命令在脚本里和交互终端里的行为会有细微差别也能解释一些诡异的报错。2. 高频命令到底怎么用文件、系统、网络三板斧2.1 文件和目录操作rm、find、grep、tar的坑与解文件操作是Linux命令使用频率最高的场景也是最容易出事故的场景。先说说rm。删除单个文件用rm 文件名没问题删除非空目录才需要rm -rf 目录名。其中-r是递归-f是强制也就是说不用一个一个问你、也不要因为权限问题就停下来。组合在一起效果很猛猛到很多人爱拿rm -rf /开玩笑。实际上现代Linux发行版对根目录删除是有保护的但如果你在脚本里写rm -rf $dir而$dir这个变量因为某种原因变成空值那实际执行的就是rm -rf /照样够你喝一壶。我自己的习惯是能不写-f就不写-f删除目录之前先ls看一眼再使用rm -r让它逐个确认多花几秒钟少开几次事故复盘会。find是被低估的大杀器。很多人找文件只会ls加上来回cd其实find / -name xxx.log一秒就能定位。它的经典组合我列一下-name按文件名匹配、-type f只找文件、-mtime 7找七天前修改过的、-size 100M找大于100MB的文件。最有用的其实是-exec它允许你对找到的每个结果执行任意命令。比如你要删掉所有缓存目录下的旧日志find /var/log -name *.log -mtime 30 -exec rm {} \;这条命令的意思是在/var/log下找到所有后缀为.log且30天前修改过的文件对每个文件执行rm。注意末尾的{}和\;是固定语法{}代表找到的每一个文件。顺便提醒一句find配合xargs是另一套常用打法但在文件名包含空格或特殊字符的服务器上容易踩坑后面避坑章节我会专门讲。grep是文本处理的核心。最简单的用法是grep 关键字 文件名生产环境里我最常用这几个参数组合grep -rn 关键字 目录递归搜索所有文件并显示行号、grep -i忽略大小写、grep -v反向过滤排除某个关键字、grep -E支持扩展正则表达式。为什么grep这么重要因为Linux系统的灵魂就是纯文本服务配置、应用日志、进程状态全都是文本只要能过滤文本你就能从一堆噪音里把想要的信息拎出来。tar是打包压缩的主力。我见过太多人一看到.tar.gz就发懵其实这个后缀的含义是先由tar打包成.tar再用gzip压缩成.gz。打包加压缩一条命令搞定tar -czvf backup.tar.gz /home/user/data参数拆开是-c创建归档、-z调用gzip压缩、-v显示过程、-f指定文件名。解压则是-x解包代替-ctar -xzvf backup.tar.gz -C /tmp-C是很多人忽略的好东西它指定解压到哪个目录。不加-C它就会在当前目录原地解压万一压缩包里自带一个乱七八糟的顶层目录结构你的工作目录就被搅得一团糟。这里顺带回应一个热搜词windows怎么用命令解压tar——Windows自带的cmd确实不内置tar语法但Win10以上的系统里其实藏着一个tar.exe可以直接用用法跟Linux一致不过日常我建议重度用户直接用WSL或者虚拟机省去跨平台折腾的时间。2.2 系统状态监控top、free、df、ps的读法系统出问题时第一件事永远不是重启而是先看清楚系统到底怎么了。top是第一个要学的它实时刷新进程的CPU和内存占用。第一行的load average三个数字代表1分钟、5分钟、15分钟的平均负载这个值超过CPU核数就得警惕了。在top界面里按P可以按CPU使用率排序按M按内存排序按q退出。生产环境我更推荐用htop界面友好得多还能用F5键以树形方式查看进程父子关系但htop不一定预装所以要记住top永远兜底。free -h看内存核心不是看used那一列而是看available。Linux的内存管理非常激进它会尽可能把空闲内存用作buff/cache文件缓存所以你经常看到明明没跑什么程序内存却用了90%的假象。available这一列才是考虑要不要扩内存的真实依据。df -h看磁盘分区使用率du -sh *看当前目录下每个子目录占多大。这两条命令的区别很多人搞混df是在文件系统层面统计du是在目录树层面统计。我遇到过磁盘明明显示100%满了但du怎么找都找不到大文件的场景最后用lsof | grep deleted才发现是某个进程把一个大文件删了但句柄没释放空间被占用着不还回来。这种问题光靠rm解决不了必须定位到那个进程重启它或者kill掉才管用。ps -ef和ps aux看起来差不多都是列出所有进程只是输出格式侧重不同。工作中我习惯用ps aux | grep 关键词来确认某个程序到底起来了没有再用ps -ef --forest查看进程树理解谁是谁的子进程。面试的时候面试官很喜欢问怎么查看某个进程的线程状态正确答案是用ps -Lf PID或者进top后按H键切换到线程视图——这个细节能区分你是不是真的处理过线上问题。2.3 网络排查命令ping、telnet、ss、curl网络层面的问题命令不在多在于组合。新手最容易犯的错是服务器连不上先ping一下通了就觉得网络没问题。实际上ping只代表ICMP协议通代表不了TCP端口通。判断某个端口通不通老派做法是telnet 服务IP 端口它成功时会跳到全黑屏或者显示空白字符失败会直接报Connection refused。注意telnet在新版Mac和部分发行版里默认不装了装之前先确认一下。查本机端口监听状态我推荐ss而不是老旧的netstat。ss -tlnp的含义是查看所有TCP监听端口并显示对应的进程名和PID。那个-p参数在排查端口占用时简直是救命稻草——没它你只能看到端口号有它你能直接看到是哪个进程占了这端口连lsof都不用再敲一遍。如果你需要看当前所有建立的TCP连接ss -s可以快速统计出连接数总量。curl是测试HTTP接口的首选。curl -I https://example.com只返回响应头看状态码够不够快curl -v显示整个请求的详细信息包括DNS解析过程、TLS握手细节curl -X POST -d {key:value} -H Content-Type: application/json是测试接口的标配写法。学会了curl你在没有图形化接口测试工具的生产环境里照样能把接口问题查得明明白白。3. 效率翻倍的进阶命令history、vim、git、shell脚本3.1 history命令详解不只是往上翻一翻我观察过很多人的终端用法用过的命令想再执行一次就一直按键盘上方向键往上翻翻半天翻不到就干脆重新敲一遍。这太浪费时间了。history命令是Shell自带的历史记录机制你敲过的所有命令它都有记账本。最高效的调取方式其实是CtrlR反向搜索。按下之后输入关键词它会自动匹配最近一次包含该关键词的命令再按一下CtrlR继续往前找上一条。这个习惯一旦养成了效率提升立竿见影。当然你还可以玩点花的!!代表上一条命令!$代表上一条命令的最后一个参数!vi代表最近一次以vi开头的命令。比如你刚执行过docker ps -a | grep nginx现在想重新跑一遍直接敲!!回车就行。再比如你先敲了cp /etc/nginx/nginx.conf /etc/nginx/nginx.conf.bak紧接着想编辑这个文件又能随手敲vi !$Shell会把它展开成vi /etc/nginx/nginx.conf.bak。还有一个容易被忽略的痛点默认情况下history只记录命令本身不记录执行时间。排查到底谁在几点几分执行了那条要命的命令这类问题时就会很被动。你可以在~/.bashrc里设置export HISTTIMEFORMAT%F %T 设置之后历史记录里就会显示每一条命令的具体执行时间和日期。顺带一提history -c清空记录这个功能最好只用在自己个人电脑上在服务器上干这种事容易破坏审计链而且你的所有操作本来就在被记录别心存侥幸。3.2 vim命令速查拒绝鼠标的编辑哲学我知道新手对vim的第一印象通常是怎么进去就出不来了但vim的底层逻辑其实简单得惊人它有多种模式普通模式下你按的键是操作指令插入模式下你按的才是输入字符。很多人的误区是进去就按i进入插入模式需要保存退出了也不知道先按Esc回到普通模式。基础编辑流程怎么练启动vim后按i进入插入模式开始写内容写完了按Esc回到普通模式输入:wq回车保存退出。想放弃修改直接退出输入:q!就行。光标移动在普通模式下也可以用h j k l替代方向键熟悉之后手不用离开键盘主区域速度比鼠标快得多。跳转方面gg跳文件首行G跳文件尾行0跳行首$跳行尾Ctrlf翻下一页Ctrlb翻上一页。删除复制粘贴有一套dd删除当前行、yy复制当前行、p粘贴到下一行、u撤销。真正的工作效率来自批量操作。比如你要把文件里所有的foo替换成bar普通模式下输入:%s/foo/bar/g这条命令的意思是在整篇文本范围内%执行替换s把foo全替换成barg代表全局。如果你只想替换当前行去掉%即可。再配合前面说的/搜索、n跳转改几百行的配置文件也就分分钟的事。十几年前我第一次用vim改Nginx配置时因为不知道ZZ普通模式下直接保存退出这个快捷键每次都用:wq!倒也没出错但后来知道ZZ省两个按键也挺香的。3.3 git命令高频场景从懵圈到条件反射git本身是个庞大的系统但你日常工作根本用不到那么多底层命令。我梳理一份高频清单git status看工作区状态git log --oneline --graph看提交历史分支图git diff看未暂存的改动内容git add -p分块暂存文件比无脑git add .稳妥得多git commit -m 说明提交git push origin main推到远端。比较考验人的是分支切换和合并冲突。git checkout -b feature/test从当前分支创建并切换到一个新分支git merge feature/test把功能分支合并回主分支。如果合并时出现冲突git status会标出哪些文件处于Unmerged状态你打开文件会看到类似这样的标记 HEAD 当前分支的内容 被合并进来的内容 feature/test你要做的是手动编辑文件把不需要的部分删掉保留正确的代码然后保存文件、git add、git commit收尾。第一次遇到冲突会心慌其实只要记住冲突标记只是给了你一个选择题删干净标记重新保存再提交这个心法就没有解决不了的。面试的时候如果被问撤销已提交的commit怎么办git reset --soft HEAD~1是标准答案但切记这是针对本地提交的已经push到远端的提交别乱reset用git revert才安全。3.4 Shell脚本基础shift、并行执行、重定向写脚本是把命令串联成自动化流程的转折点。热搜词里有个shell的shift命令这确实是很多面试爱问的点。shift的作用是让脚本的位置参数左移一位执行shift后$2变成$1$3变成$2以此类推。这在你需要循环处理一组参数时非常有用。比如你写了个部署脚本调用方式是./deploy.sh test /path/to/config脚本逻辑可以先处理第一个参数环境名然后shift一次剩下的参数统一当作文件路径来处理。这样就能用while [ $# -gt 0 ]; do循环灵活地解析任意数量的参数。再看并行执行命令。默认情况下你在Shell里执行多条命令它们是串行的。想并行直观的做法是在命令后面加比如process_data_a process_data_b wait这个脚本的意思是后台同时跑两个任务wait等待两个任务都结束再继续往下走。如果你要批量处理很多小任务更推荐用xargs的并行能力cat urls.txt | xargs -P 10 -I {} curl -I {}-P 10表示最多同时开10个进程-I {}允许你自定义占位符。处理几百个URL批量探测场景时这个组合能把时间从几分钟压缩到十几秒。最后是重定向。把标准输出覆盖写进文件追加写2把错误输出重定向到文件。新手最容易忘的是把错误和正常输出分开command out.log 21可以把标准输出和标准错误融合到同一个文件里。排查脚本为什么没按预期运行时第一件事就是检查它的输出文件——很多时候你以为它没执行其实是错误全被吞进了2指定的黑名单文件里。4. 运维排障实战从故障现象到根因定位4.1 案例一磁盘被写满服务频繁报错有一回同事找到我说线上服务突然开始拒绝写入报错内容明显和磁盘空间有关。我登到服务器上先执行df -h看到根分区用了100%确认是磁盘满的问题。下一步按理说应该找大文件但du -sh /var/log/* | sort -rh | head -10一轮扫下来居然最占空间的也就几百MB跟满掉的磁盘对不上。这时候就要想到文件被删除但句柄未释放的经典场景了。我用lsof | grep deleted一查果然发现一个已经被删除的日志文件还挂在服务进程下面占着几十GB的磁盘空间。解决办法不是去文件系统里找这个文件它已经不存在了而是kill -HUP 进程PID让服务重新打开日志句柄或者直接重启这个服务。磁盘立刻释放出大量空间。这个案例里最大的教训就是du统计的是目录里还能看到的文件而df统计的是文件系统总的使用量两者对不上时八成是有幽灵文件被进程捏在手里不放。4.2 案例二CPU使用率飙高系统负载拉满另一个高频故障是CPU跑满。top一打开第一行的load average飙到几十按P排序后明确看到一个Java进程把CPU全部吃光了。到这一步很多人就卡住了因为进程名都很正常看不出有啥毛病。再往下挖就要看这个进程内部在干什么。top里按H切到线程视图找出占用最高的那个线程的PID转换一下变成十六进制然后jstack 进程PID | grep -A 30 十六进制线程号才能看到这个线程到底停在哪一行业务代码上。如果确认是死循环或GC线程疯狂运转代码层面去修。如果你只是想临时止血taskset命令可以把进程绑定到指定CPU核上或者用systemctl restart重启服务先恢复可用再慢慢找根因。这轮排查下来你会发现Linux排查问题从来不是靠某一条神奇命令而是靠top - ps - strace - jstack这样一层一层往深处传递线索。命令只是你的探针真正的逻辑判断靠人。4.3 案例三端口被占用新服务起不来部署新服务时报端口已被占用也是天天见的老朋友。排查流程就三步。第一步ss -tlnp | grep 8080看到底是哪个进程占用了端口。如果查出来了看这个进程是不是还需要留着不需要就kill掉需要就换端口启动新服务。第二步如果ss里查不到明确进程或者PID显示不出来多半是权限问题加sudo再查一次。第三步如果端口明明在监听但你就是连不上就要检查防火墙iptables -L -n看规则列表或者直接sudo systemctl stop firewalld临时关掉防火墙做对比测试。这里要提醒一句线上系统千万别图省事关防火墙。合理的做法是firewall-cmd --add-port8080/tcp --permanent然后firewall-cmd --reload精确放行需要的端口。说到没找到rpm命令这个热搜词它本质上是命令不在PATH里或软件包没装好。解决套路是rpm -qa | grep rpm确认rpm包里的工具装没装没装就用yum install rpm补上再不行检查一下export PATH是不是漏了什么目录。5. 新手必看Linux命令的几个致命误区5.1 关于rm -rf玩笑可以开事故要避免先说说那个段子级别的rm -rf /。虽然现代系统有保护机制但在普通用户权限下如果误删除自己的目录后果一样是灾难性的。我见过一个同行写脚本时不小心在变量拼接的路径里混入了一个/结果把公司存储了一年的客户备份删了个干净。自救方案不止一种。第一把你觉得危险的高危命令加一层确认alias rmrm -i让删除每个文件之前都要交互确认杜绝误删。把这个alias写进~/.bashrc所有交互终端都有保护。注意脚本里默认不加载alias所以要保护脚本还得靠其他手段。第二做删除操作之前先在文件名前面打个echo测试一遍路径对不对比如echo rm -rf $dir确认输出是你想要的路径再真正执行。第三重要的目录你甚至可以临时改掉它的权限chmod 000 /path/to/important让普通用户连读的资格都没有自然删不掉。方法很土但简单有效。5.2 管道与xargs空格和换行带来的暗坑管道符|能让前一个命令的输出变成后一个命令的输入这个设计非常漂亮但隐含着一个陷阱。比如你想统计当前目录下每个log文件的行数ls *.log | xargs wc -l如果目录里有个文件名带空格比如my log.logxargs会默认以空白字符为分隔符把my log.log拆成两个文件名去处理然后抛出一堆No such file or directory。这问题在生产服务器上出过太多次了。解决办法是让ls以\0为分隔符输出xargs也跟着以\0为分隔符接收ls *.log | xargs -0 wc -l用-0参数把分隔符从空白改成空字符文件名里就算有空格、换行、甚至隐藏字符都不会再出错。同理在Shell脚本里遍历文件列表时老老实实用find ... -print0配合xargs -0或者用while IFS read -r file循环来逐行读取这两种写法才是安全实践。5.3 sudo和PATH命令找不到与环境变量的真相面试里经常问sudo是什么面试官想听的不只是临时获取root权限更想听到sudo与su的区别以及为什么sudo有时候会找不到普通用户能执行的命令。先说su它意味着切换到另一个用户身份需要输入目标用户的密码登录型切换环境变量会跟着那个用户走。sudo则是用当前用户密码去执行一条特权命令它直接继承了当前用户的部分环境变量。某些发行版上普通用户的PATH里包含了/usr/local/bin但root的PATH里没包含于是你带着sudo执行一个放在/usr/local/bin下的程序系统就会提示command not found。排查这类问题使用sudo -i进入一个干净的root登录Shell再执行which 命令名能更清楚地看清PATH差异。还有一个小习惯强烈建议养成不要在不确定一个命令会干什么的情况下随手在前面加sudo。尤其是chown、chmod、rm、mv这四类命令带sudo执行的效果往往不可逆。真要查看某个配置文件先sudocat看一眼比直接sudovim打开更安全——因为vim保存退出时可能会顺手帮你改掉一些格式化细节。结语几句实话用Linux十年最深的体会是命令这东西背是永远背不完的真正值钱的是你知道遇到问题时该往哪个方向查以及怎么用命令组合去验证你的猜想。我见过有人背了几百条命令遇到生产故障还是手忙脚乱也见过有人只熟练掌握四五十条命令但把文件查找、日志过滤、进程脉络、网络状态这些基础链路吃透了照样能解决绝大多数线上问题。如果你刚入门千万别急着去啃什么命令大全手册打开终端从ls、cd、cat、grep开始每天在真实操作里用上几次比你抄写十遍笔记都管用。网上还有不少免费的在线Linux练习环境不用自己折腾虚拟机也能敲命令尤其适合通勤路上拿手机练练手。踩过几次坑之后你就会发现学Linux命令最爽的时刻不是背下来多少条而是某天你看着一条报错脑子里清晰浮现出这问题该用哪条命令查下一步该看哪个字段的时候。
RELATED READING

延伸阅读

更多一线实战笔记与深度复盘,助您持续精进