1. 先别急着背命令清单:把命令当成跟系统对话
早些年我刚接触 Linux 命令的时候,干过一件现在想起来有点好笑的事:找了一份《常用 Linux 命令大全》,把 ls、cd、cp、mv 的参数背得滚瓜烂熟,结果到了真正需要排查问题的时候,依然两眼一摸黑。后来真正让我对 Linux 命令开窍的,不是某本速查手册,而是一次在服务器上排查故障时的经历——我把一条一条看起来平平无奇的命令用管道串了起来,突然意识到:原来这些命令并不是一份需要死记硬背的清单,它们本质上是一种"向操作系统提问"的方式。
这篇文章不打算给你罗列几百条命令的用法,我更想聊的是怎么把命令用起来:怎么从一条单命令出发,逐步组合成能解决实际问题的"信息流水线";排查服务器问题时应该按什么思路选择命令;以及那些文档里通常不会写、但实战里特别关键的细节。适合刚学 Linux、总感觉"命令学了就忘"的新手,也适合已经在日常使用 Linux、但遇到问题仍然不知道从何下手的进阶用户。
1.1 命令是"提问",不是"背诵清单"
我后来总结出一个观点:每一条命令都在回答一个具体的问题。ls 回答"这个目录里有什么",ps 回答"现在系统里有哪些进程在跑",df 回答"磁盘空间还剩多少"。当你把命令理解成"提问工具"而不是"要背的单词",学习方式自然就变了——遇到陌生命令,第一反应不再是"我又要背一个了",而是"这条命令能帮我回答什么疑问"。
顺着这个思路,命令后面的选项和参数也不过是让答案更精确的限定条件。比如 ps 这条命令,ps aux 和 ps -ef 都能查看进程呢,但输出格式不同,适合的场景也不同。你不需要把几十个选项全部背下来,只需要知道这条命令能回答"进程状态"这一类问题,然后遇到实际需求时去查它的用法。
查用法有两条路:man 命令名,或者 命令名 --help。很多人看到 man 手册那么长就退缩,其实根本不需要从头读到尾,只看你关心的那个选项就行。真正重要的不是把手册读完,而是养成"先查后试"的习惯。这个习惯比任何命令大全都管用,因为系统自带的帮助信息永远比别人的笔记更新、更贴合手头这个版本。
1.2 从最小可运行命令开始,别一上来就堆参数
我见过不少人一上来就写特别长的命令,比如 find 配合 -exec、多层管道、一堆选项全部叠加,一旦报错,根本不知道是哪一个环节出了问题。我的习惯刚好相反:先跑一个最小版本,确认命令本身能正常工作,输出格式也符合预期,然后再一点点把过滤条件、排序、统计加上去。这个过程很像排查电路故障:先确认总闸有电,再逐条支路检查,而不是一上来就把所有开关都按一遍。
举个例子,你想用 awk 从日志里取某一列,如果上来就写 awk '{print $2}',结果发现 $2 根本不是你想要的那一列,因为你压根没见过日志原始长什么样。正确做法是先 head -n 5 日志文件,看一眼列是怎么排的,确认第几列是IP、第几列是时间,再写 awk。这个"先看输出、再动手处理"的习惯,能帮你省掉大量自我怀疑的时间。
配套的技巧叫"小范围验证":处理大文件时,先用 head 或 grep + head 把输入缩小,逻辑跑通之后再对全量数据执行。尤其是 sed、awk 这类会修改内容的命令,强烈建议先在测试目录或小样本上试一遍,确认结果符合预期再正式执行。别嫌这一步啰嗦,真出问题的时候,它会让你少说很多次"完蛋了"。这套方法同样适用于后面要讲的管道命令——每次只加一段,跑一下,确认没问题,再继续拼。
2. 一条排查命令是怎么长出来的:管道组合实战
很多人学命令是一条一条学的,但实际干活的时候,真正体现功力的地方是把命令用管道串起来。管道说白了就是"把前一条命令的输出,交给后一条命令作为输入"。用好了,一条命令就能完成一次小规模的数据分析。我拿一个特别常见的场景来讲:某天服务响应变慢,怀疑有客户端在反复刷某个接口,日志目录里放着访问日志,现在想找出到底哪些 IP 在频繁请求这个接口。
2.1 场景与需求:我要从日志里找到谁在刷接口
先别急着写命令,第一步是看一眼日志长什么样。执行 tail -n 20 访问日志路径,确认列格式。这一步是整条排查命令的地基,因为后面取哪一列、怎么过滤,完全取决于日志里字段的排列方式。假设我们看到日志格式大致是"IP 时间 请求方法 请求地址 状态码",那 IP 就在第一列。
很多人忽略这个步骤,直接 grep 然后 awk '{print $1}',结果日志格式稍有变化,取到的列根本不是自己想要的东西。这就是"没看清现场就动手"的典型失误。日志格式确认之后,你的需求才能转成清晰的命令目标:先过滤出包含指定接口的日志行,再从这些行里提取 IP 字段,最后按 IP 去重并统计请求次数。每一步对应什么命令,这时就非常自然了。
2.2 逐段拼接:每加一步都验证一遍
我按实际排查过程把这条命令拆开,你可以看到它是怎么一步步"长"出来的。第一步,只筛选出相关请求:
grep "api/login" 访问日志路径跑完先看输出是否符合预期,如果行数太多,可以先在末尾加 head -n 10 看几条样例。第二步,把 IP 字段取出来:
grep "api/login" 访问日志路径 | awk '{print $1}'这时输出会是一堆可能重复的 IP。第三步,排序并统计次数。这里有一个很关键的顺序问题:必须先 sort 再 uniq -c。因为 uniq 默认只统计相邻的重复行,如果同一个 IP 在文件中是分段出现的,直接 uniq -c 会把一个 IP 统计成好几段,结果完全错误。正确写法是:
grep "api/login" 访问日志路径 | awk '{print $1}' | sort | uniq -c到这一步,输出变成"次数 IP"的形式。第四步,按次数降序排列,并只保留前 20 个结果:
grep "api/login" 访问日志路径 | awk '{print $1}' | sort | uniq -c | sort -rn | head -n 20看到这里你应该明白了,这条命令不是背出来的,而是从一个疑问出发,通过不断验证中间输出,自然组合出来的。每加一个管道段,我都会先跑一遍,看一眼输出内容是不是我想要的,再决定下一步往哪边走。这种"逐段验证"的拼法,比一口气写完长命令要可靠得多。
2.3 组合管道时容易翻车的几个细节
管道好用,但有几个坑必须提醒。第一个坑是"管道左侧失败,右侧照跑"。比如文件不存在时 grep 会报错,但整个管道的退出状态取决于最后一个命令。如果你在脚本里启用了 set -e,可能就不会因为文件不存在而中断脚本,问题会被静默放过去,后面拿到一堆错误数据时反而更难排查。
第二个坑是隐藏字符。有些日志文件里带着 \r 回车符或者乱码,输出看起来一切正常,但 sort 和 uniq 的结果就是不符合预期。遇到可疑情况,可以用 cat -A 文件名 | head 看一眼文件中是否藏着看不见的控制字符,再决定要不要用 tr 或 sed 先清理。
第三个坑是 awk 列号写死的问题。如果日志里大部分行有 7 列,但偶尔几行因为格式异常只有 5 列,取 $1 可能还算稳定,取 $4 就可能错位。处理这类脏数据,先分几行看一看字段结构差异,再选择取列方式。我的建议是:拼管道命令时,每加一段就跑一遍,确认中间结果正常,再继续往后面接。这个习惯帮我在排错时节省了大量时间,比任何命令速查表都实在。
3. 资源状态排查:进程、内存、磁盘的真实场景
命令只有放到真实场景里反复用,才会真正变成自己的东西。服务器出问题的时候,其实是学习命令最好的机会。这一节我挑三个高频场景,讲一下我是怎么看状态、怎么快速把问题定位到具体方向的。
3.1 进程:ps aux 只是起点,/proc 里才是真正的细节
ps aux 大家都会用,但实际排查时,有几个细节很容易被忽略。首先,ps aux 默认按 PID 排序,如果想找 CPU 或内存占用最高的进程,要么用 sort 辅助,要么进 top 再按对应列排序。其次,ps aux 能看到进程的基本状态,但看不到这个进程的完整启动命令、当前工作目录、环境变量,以及它打开了哪些文件。
这些细节要去 /proc/PID 目录里挖。比如某个进程 CPU 占用很高,你想知道它到底在干什么,可以先看 /proc/PID/cmdline 拿到完整的启动参数,再看 /proc/PID/status 里的线程数和状态信息。如果怀疑进程打开了某个文件不释放,可以用 lsof -p PID 查看它持有的文件句柄。说实话,刚接触 Linux 的人会觉得 /proc 下一堆数字目录很怪,但用熟了以后会发现,它几乎是系统主动敞开的一扇观察窗口。
补充一个实用命令:想按内存占用排序找进程,可以直接写 ps aux --sort=-%mem | head -n 10,一步到位。不过要提醒一点,进程的 RSS 内存包含它加载的共享库占用的那部分,把所有进程的 RSS 简单相加来估算系统总内存需求是不准确的,这一点初学者非常容易误解。
3.2 磁盘:df 满了,du 却找不到大文件
"磁盘满了但不知道是谁占的",这个场景几乎每个运维和开发者都遇到过。df 和 du 的视角不一样:df 看的是文件系统整体用了多少,du 看的是某个目录下所有文件实际占用多少。如果 df -h 显示根分区已经 100%,但到根目录执行 du -sh * 逐项相加后,发现远小于总量,说明一定有什么东西在"看不见"地占着空间。
最常见的元凶有两个。第一个是"已被删除但还被进程占用"的文件:进程打开了一个文件,随后文件被删除,但进程没有关闭句柄,磁盘空间就不会释放。df 能看到空间没了,du 却无论如何也找不到这个大文件。这种情况用 lsof | grep deleted 就能把它揪出来。第二个是 inode 耗尽:小文件太多,把索引节点用完了,df 显示空间还有剩余,但新文件就是创建不出来。这时候要执行 df -i 看 inode 使用率。很多人只盯 df -h,不看 df -i,所以遇到"空间够但写不进文件"这种诡异问题就会卡住。
还有一种情况是目录被重复挂载。一个目录被挂到两个位置,du 默认会跨挂载点重复计算,导致统计结果虚高。如果只想看当前文件系统自己的用量,给 du 加上 -x 参数,让它不跨越文件系统边界。以后再遇到"df 和 du 对不上"时,别急着怀疑命令,先按这三条逐个排查,思路会清楚很多。
3.3 内存:free 里的 buffer/cache 不是"占用"
执行 free -h 的时候,很多新手看到 used 很高、buff/cache 也很大,就开始慌了,觉得内存是不是快不够了。实际上,buff/cache 是 Linux 的一种正常内存管理机制:把暂时用不上的空闲内存拿去做文件缓存,等应用程序需要更多内存时,这些缓存会被随时释放回来。真正判断内存够不够,要看的是 available 这一列,它表示在不发生 swap 的情况下,还能分配给新进程多少内存。
判断内存压力的信号有这几个:swap 使用率持续上涨、系统日志里出现 OOM 相关的记录、top 里某些进程被莫名其妙杀掉。遇到这些情况,再去查到底是哪个进程占得多,比直接升级内存更有效。我之前处理过类似场景:一个服务平时内存占用正常,但每到某个固定时间点就挂一次,后来翻日志发现是定时任务和主服务同时跑,内存峰值超标了。整个过程用到的命令也就是 free、top、journalctl 这些,但核心在于是否愿意顺着现象多问几层"为什么",而不是停留在"重启一下试试"。
4. 少跑冤枉路的排查思路:从现象到根因
命令只是工具,思路决定你花多长时间解决问题。不少人在排查时喜欢"病急乱投医",这条命令不行换那条,最后直接重启大法收场。其实只要按层次逐步排除,很多问题都能在几分钟内锁定到很小的范围。这一节我想分享的是,我在实际排错中沉淀下来的分层思考框架。
4.1 先确认"现象在哪一层",再决定用什么命令
一个服务访问不了,可能性实际上非常多:客户端 DNS 解析失败、网络不通、服务端口没监听、服务进程挂了、防火墙规则拦截、后端数据库连不上、应用代码本身报错。如果一上来就 ping 网关,很可能把时间浪费在错误的方向上。我的习惯是把问题分四层看:应用层、传输层、网络层、系统层,按顺序逐层验证。
第一层,先在服务器本机测应用层:用 curl 访问本机地址,如果服务本身和端口都正常,curl 应该很快返回业务响应。第二层,从内网或外部机器访问,看是不是网络路径或防火墙拦截的问题。第三层,查服务日志,确认是业务逻辑报错还是资源不足。每一层都用一两个命令去验证,然后缩小范围。比如 curl 本机通、外部不通,问题大概率在网络层或防火墙;本机 curl 都不通,那就直接往进程和端口方向查。
这套思路听着简单,但实际很多人遇到问题的第一个动作就是重启服务。重启确实能让问题暂时消失,但也会把现场破坏掉——进程状态、网络连接、日志上下文全部重置,之后再想复盘根因就非常被动了。我的原则是:重启之前,至少先保存日志、记录进程状态、记下时间线这三样东西。保住现场,比急着恢复服务更有利于找到真因。
4.2 网络类命令的高频组合与正确用法
网络排查的命令本身不难,难的是理解每一条命令到底能证明什么。ping 通了,只能说明 ICMP 这一层通,不能证明业务端口是通的;端口能连上,说明 TCP 握手成功,但也不代表应用层正常。所以我常用的组合是:先 ping 看基础连通性,再 ss -tlnp 看本机端口是否在监听,然后用 nc 从另一端测一下端口连通性,最后用 curl -v 带超时参数去测应用层响应。每一条命令回答的"层"都不同,组合起来才能完成定位。
举一个实际的排查过程:某次遇到"网站间歇性打不开",我在服务器本机用 curl 访问一切正常,但从外部访问就超时。接下来用 nc -vz 目标IP 端口 测端口,发现 TCP 层也通不过,于是基本判断问题出在网络路径或防火墙。再检查防火墙规则和安全组配置,很快就找到了原因。全程没有用任何复杂的命令,但每一条都完成了"排除一个方向"的任务。
这里有个容易被忽略的细节:nc、mtr、dig 这类命令在部分精简安装的 Linux 上默认不存在。在网络问题排查之前,先确认系统里有没有这些工具,缺什么就装什么,否则查了半天才发现命令根本不存在,节奏就被完全打乱了。另外,curl 的 -w 参数可以输出连接耗时、总时间等指标,用来判断"慢在哪一段"尤其好用,值得专门花两分钟熟悉一下。
4.3 日志时间线:别只盯着最新几行
日志是排查问题最直接的现场记录,但很多人只会 tail -n 100 看最近几行。问题如果发生在几小时前,等你发现并登录服务器的时候,关键日志可能早就被新内容冲掉了。正确的做法是先确定"问题是从什么时候开始出现的",然后把那个时间窗口附近的日志完整拉出来看。
目前我用的比较多的方式是 journalctl 这套:执行 journalctl -u 服务名 --since "2 hours ago" 可以看某个服务最近两个小时的日志,还能用 --until 进一步收窄时间窗口。接着用 grep 按关键词过滤,比如搜 OOM、error、timeout,然后再顺着时间线把上下文完整看一遍。很多时候,真正的根因藏在错误日志前面几十行里,只看孤零零的一句报错,很容易被误导到错误的方向。
如果系统没有启用 journalctl,日志只写在传统文件里,可以先看日志文件的修改时间来判断问题的大致时间点,再从那个时间点附近取日志。无论用哪种方式,核心方法是一致的:把"错误发生时刻"前后几分钟的信息放到一起看。排查问题要看时间线,而不是只看单个报错点,这是我跟很多人反复强调的一点。
5. 被默认忽略的命令习惯:安全与效率兼得
最后想聊的是命令使用习惯。这部分很少有人专门教,但踩过的坑往往最疼。我总结了几条可以直接照做的经验,能帮你少走很多弯路。
5.1 rm 这类危险操作:给自己上个保险
rm -rf 是很多人心中的噩梦。最常见的风险来源是这几个:路径变量为空、路径拼写错误、在错误的目录下执行。我的建议有三条。第一,把 rm 替换成带回收站功能的方式,比如设置 alias rm='trash-put',或者写一个自定义函数,把删除的文件移动到一个专门的回收目录里,这样至少还有后悔药可以吃。第二,如果必须在脚本里用 rm,先判断变量是否为非空,比如 [[ -n "$目录变量" ]] 确认后再继续操作。第三,执行删除之前,先 pwd 确认当前目录,再 ls 确认目标路径。
有人觉得这些习惯太啰嗦,但真出过一次事就会明白,多花十秒钟确认,比花一整晚恢复数据划算太多。尤其是在生产环境里,rm 的安全习惯应该变成肌肉记忆,不靠运气,靠流程。
5.2 history、alias、配置:把常用命令沉淀成自己的装备
命令用好之后,很多人还是每次重复敲一长串,效率很低。我习惯把高频组合写成别名,比如 alias ll='ls -lh'、alias g='grep'、alias ..='cd ..',写进 ~/.bashrc 或 ~/.zshrc 之后,日常操作会舒服很多。但这里有一个经典坑要提醒:在脚本里不要依赖别名。非交互式 shell 默认不会展开 alias,你明明配置了 alias g='grep',在脚本里写 g "abc" file 却可能报"命令找不到",这个问题会让不少人困惑很久。
历史记录也值得好好配置。默认情况下 history 只记录命令本身,不记录时间,长度也有限。我通常会在配置里加这几行:
HISTTIMEFORMAT="%F %T " HISTSIZE=10000 HISTFILESIZE=20000
加上之后,history 输出会带上时间戳,复盘问题的时候会非常有用。还有一条安全习惯必须强调:不要把密码、密钥、token 直接写在命令行里,因为 history 会记录,脚本里也会留痕。如果确实需要,应该通过环境变量或配置文件读取,不要图省事直接明文写在命令里。
5.3 重定向、通配符、sudo 的常见坑
重定向是新手最容易出问题的地方。第一点是 > 会覆盖文件,>> 会追加文件;第二点是 2>&1 表示把标准错误重定向到标准输出当前指向的位置,这两者顺序不同,结果也完全不同。一个非常经典的错误是执行 sudo echo 1 > /某个root属主的文件,结果报"权限不足",因为重定向是当前 shell 打开的,sudo 只作用于 echo 命令本身。正确做法是 echo 1 | sudo tee /某个root属主的文件,或者 sudo bash -c 'echo 1 > /某个root属主的文件'。
通配符也有一个容易踩的坑。rm.log 在没有匹配文件时,.log 这个字面字符串会原样传给 rm,然后 rm 报错"文件不存在"。更危险的情况是,如果目录里恰好有一个文件叫 *.log,这个命令会把它也删掉。要避免这类意外,可以写 rm -- *.log,双横线表示后面的参数都作为文件名处理。通配符本质上是 shell 先做展开,再交给命令执行,理解了这个机制,你才能控制它而不是被它坑到。
最后说一句 sudo 的使用边界。很多人习惯遇到权限问题就一长串 sudo,但这会掩盖真实的权限问题。能用普通用户执行,就不要用 root 身份;能限制在单条命令上,就不要开一个 root shell。这句话听起来像老生常谈,但生产环境里权限最小化是真的能兜底的。
根据自己的经验,我最后分享一个小习惯:每周挑一条平时用得少但知道很有用的命令,比如 find、xargs、jq,花十分钟读一遍它的手册,在一个测试目录里用真实数据玩一遍,然后思考它还能怎么跟别的命令组合。坚持一个月,你会发现自己能写出来的命令结构越来越丰富。Linux 命令这东西,背了不用等于没学,用了并且认真思考过,才真正变成你自己的。