第一次通过 SSH 连上一台 Linux 服务器,很多人都会愣几秒:黑底白字,一个光标在闪,没有桌面、没有图标、没有可以点的按钮。想看看磁盘还剩多少空间,得敲命令;想找一段日志,得敲命令;想知道某个服务是不是还活着,还是得敲命令。
于是不少人学 Linux 命令的路径就变成了“背大全”:找一份常用命令列表,从 ls、cd、pwd 开始一条条往下记。背了一周,能认出七八十个命令名,但真给他一台服务器,让他排查“网站打不开了”,他还是不知道第一条命令该敲什么。
问题不在于背得不够多,而在于顺序反了。Linux 命令不是一门需要记忆的词汇课,它更像一套操作系统的控制语言:你先得理解它描述的那个世界——文件和进程——然后才会发现,绝大多数命令不过是同一套动作作用在不同对象上的重复。ls 是“看”,cat 是“看”,ps 也是“看”;rm 是“删”,kill 也是“删”,只不过一个删文件,一个删进程。理解了这个对应关系,命令数量就不再是负担。
这篇文章想讲的主判断是:从入门到精通的分水岭,不是你记住了多少条命令,而是你能不能围绕一个具体问题,把几条命令按正确顺序组合起来。 单条命令解决的是“知道”,组合命令解决的是“能干活”。下面按这个思路往下拆。
1. 先别急着背命令,先建立“文件和进程”这两个观察视角
零基础学 Linux 命令最大的挫败感,往往不是来自命令本身。ls 谁都会敲,cd 谁都会用,真正让人放弃的是:学完之后遇到问题,脑子里没有一条可走的路径。
我见过太多人卡在同一个地方:知道 grep 能搜文本,知道 tail 能看日志,但真让他从一份 30 万行的日志里找出“昨天下午三点之后所有 500 错误的请求路径”,他就不知道从哪下手了。不是命令不会,是不知道这些命令之间怎么接。
所以这一节先不谈具体命令,先把视角立起来。Linux 世界里你日常打交道的东西,说白了只有两大类:文件和进程。文件是静态的,进程是动态的;文件是“存在哪”,进程是“正在跑什么”。你后面学的所有命令,几乎都可以归到这两个视角里的某一个。
1.1 为什么零基础学命令,最容易死在“没有反馈”上
图形界面最大的好处不是好看,是即时反馈。你点一个文件夹,它打开了,你就知道点对了;你拖一个文件到回收站,它消失了,你就知道操作成功。每一步都有视觉确认,错了马上能看出来。
命令行把这种反馈拿掉了。你敲下 rm 之后,如果什么都没输出,那到底是删成功了,还是根本没匹配到文件?你敲下一串命令,屏幕安静得像什么都没发生,新手的第一反应通常是“是不是坏了”。
这里必须先记住一条约定俗成的规则:在 Linux 命令行里,沉默通常意味着成功。 大量命令遵循“没有消息就是好消息”的设计——执行成功就不输出任何东西,只有出错时才打印信息。这跟图形界面的直觉是相反的,但理解了这一点,你就不会再因为“没反应”而反复重敲同一条命令。
对应的还有另一条:出错时一定要看退出码和标准错误,而不是只看屏幕上有没有字。 很多命令把正常输出和错误输出分到两个不同的流里,后面的管道章节会详细讲。现在你只需要建立一个意识:屏幕安静不代表没发生事情,屏幕有字也不代表出错了。
这个认知差异看起来很小,但它解释了为什么很多人学命令学到一半就卡住——他们在等一个永远不会出现的“确认提示”。命令行不给你确认,它默认你知道自己在干什么。这既是它的效率来源,也是它的风险来源。
1.2 一切皆文件:这条主线能帮你省掉一半死记硬背
“一切皆文件”这句话被讲烂了,但大部分人只是把它当成一句口号,没有真正用起来。
具体怎么用?举几个例子。你想看系统内存情况,直觉是“应该有个专门的内存命令吧”,确实有 free,但更底层的信息在 /proc/meminfo 这个文件里,直接 cat 就能看。你想看 CPU 信息,/proc/cpuinfo 就是一个文本文件。你想看某块磁盘的分区情况,/proc/partitions 也是文件。甚至你在终端里插一个 U 盘,系统识别出来的设备节点 /dev/sdb 在文件系统里也表现为一个文件。
这条主线带来的实际收益是:当你不知道用什么命令时,先去文件系统里找对应的文件。 系统状态几乎都挂在 /proc 和 /sys 下面,硬件设备挂在 /dev 下面,配置挂在 /etc 下面,日志挂在 /var/log 下面。这四个目录撑起了日常运维的一大半工作。
再往深一层,你会发现很多“命令”本质上是对文件的封装。ls 读的是目录文件,cat 读的是普通文件,df 读的是文件系统的统计信息。它们的差别不在“操作方式”,而在“操作对象”。一旦你按对象去归类命令,记忆量会急剧下降——你不需要记 100 条命令,你只需要记“查看类”“修改类”“删除类”“权限类”这几组动作,然后往里面填对象。
这个思路也不是万能的。进程就不完全是文件,网络连接也不是普通文件,它们有自己的一套查看方式。但即便在这些领域,“去对应的虚拟文件系统里找”依然是有效的第一反应。
1.3 一条命令的标准结构:命令、选项、参数和组合符
在敲具体命令之前,先把语法骨架弄清楚,能省掉后面大量“为什么这条命令报错”的困惑。
一条典型命令的结构是这样的:
bash复制命令名 [选项] [参数]
以 ls -lh /var/log 为例:ls 是命令名,-lh 是选项(-l 表示长格式,-h 表示人类可读的大小单位),/var/log 是参数,也就是操作对象。
这里有三个新手最容易混淆的点,值得单独说清楚:
第一,短选项和长选项。 短选项用单个减号加一个字母,比如 -l、-a、-h,可以合并写,ls -lah 等价于 ls -l -a -h。长选项用两个减号加单词,比如 --help、--all,可读性更好但敲起来更长。两者在多数命令里是等价的,只是形式不同。
第二,选项和参数的位置。 大部分命令允许选项写在参数后面,但有些命令(尤其是老式 Unix 命令)对顺序敏感。稳妥的习惯是把选项写在参数前面,这样几乎不会出问题。
第三,组合符。 真正让命令行强大的不是单条命令,而是把多条命令连起来的符号。最常用的三个是:
| 符号 | 作用 | 典型用法 |
|---|---|---|
| |
管道,把前一条命令的输出交给后一条作为输入 | ps aux | grep nginx |
> |
重定向,把输出写入文件(覆盖) | ls -l > filelist.txt |
>> |
重定向,把输出追加到文件末尾 | echo "done" >> run.log |
管道是整个命令行体系里最有价值的设计,它让“小工具各干一件事”成为可能。这一节先记住符号,具体怎么组合放到第 3 节展开。
还有一点:遇到不认识的命令,--help 是第一反应,man 命令名 是第二反应。不要一上来就搜网页,本地手册往往更准确,也更贴近你当前系统上的实际版本。
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. 文件与目录:这组命令决定了你后面学得快不快
文件操作是命令行里频率最高的一类,也是最容易出事故的一类。频率高是因为你每天都要看文件、找文件、改文件;容易出事是因为 rm 和通配符组合起来,破坏力非常直接。
这一节按“先看清楚,再动手术”的顺序组织。先解决定位和查看,再讲修改和删除。这个顺序不能反——很多误删事故的根源,就是跳过“看清楚”这一步直接动手。
2.1 先回答三个问题:我在哪、这里有什么、我要去哪
任何一次命令行操作,起点都是定位。三个问题对应三条命令:
bash复制pwd # 我在哪:打印当前工作目录的绝对路径
ls -lah # 这里有什么:列出目录内容,包含隐藏文件,带大小和时间
cd /var/log # 我要去哪:切换到目标目录
pwd 看起来最没用,但它是排查“为什么我的命令找不到文件”的第一条命令。大量“文件不存在”的报错,根源不是文件真的不存在,而是你当前所在的目录跟你以为的不一样。尤其是从别的目录 cd 过来、或者脚本里切换过目录之后,先 pwd 一下能省掉很多无效排查。
ls 的参数值得多说几句。默认的 ls 只显示文件名,信息量太少;ls -l 显示长格式,包含权限、所有者、大小、修改时间;ls -a 显示以点开头的隐藏文件;ls -h 把字节数变成 K/M/G 这种人类可读的单位。这三个选项组合起来 ls -lah,基本就是你日常最需要的那一屏信息。
cd 有几个高频简写:cd ~ 回用户主目录,cd - 回上一次所在的目录,cd .. 回上一级,cd / 回根目录。其中 cd - 值得特别记住,它相当于命令行里的“后退键”,在两个目录之间来回切换时非常好用。
还有一条经验:不确定路径写对没写对的时候,用 Tab 补全。 敲前几个字符然后按 Tab,系统会自动补全或者列出所有可能的匹配。这不仅是省事,更是防错——补全出来的路径一定真实存在,手敲的路径则不一定。
2.2 查看文件内容:cat、less、head、tail 各有各的场合
打开一个文件看看内容,这件事有好几种做法,选错了会让体验很难受。
cat 是最直接的,把整个文件一次性输出到屏幕。它的适用场景是小文件,比如配置文件、脚本、几行说明。用 cat 去看一个几百兆的日志文件,结果就是屏幕疯狂滚动、终端卡住,你得按半天 Ctrl+C 才能恢复。
less 是查看大文件的标准工具。它打开的是一个可翻页的视图,用空格翻页、/关键词 搜索、q 退出。相比 cat,less 不会一次性把内容全刷到屏幕上,也不会把终端的历史记录冲掉。看几十兆以上的日志,less 几乎是唯一合理的选择。
head 和 tail 是取片段。head -n 20 file 看前 20 行,适合快速确认文件格式和表头。tail -n 20 file 看最后 20 行,适合看日志尾部。而 tail -f file 是另一个重量级用法——它会持续跟踪文件新增的内容,日志一有新行就实时打印出来。排查“服务正在报什么错”的时候,tail -f 搭配另开一个终端触发请求,是最朴素的调试方式。
这里有个容易忽略的细节:tail -f 跟的是文件描述符,如果日志被轮转(比如从 app.log 重命名成 app.log.1 然后新建了 app.log),tail -f 可能还盯着旧文件。部分实现提供了 -F 选项,会在文件被替换后重新打开,长期挂着看日志时更稳妥。
至于编辑文件,vim 和 nano 是两条路线。nano 上手快,底部直接显示快捷键提示,适合改几行配置。vim 学习曲线陡,但熟练之后效率明显更高,服务器上也几乎一定装着。建议是新手上手先用 nano 把事做完,同时慢慢熟悉 vim 的基本模式切换(i 进入编辑、Esc 退出编辑、:wq 保存退出),不要指望一天学会。
2.3 增删改查和权限:真正容易出事的地方
文件的新建、复制、移动、删除,命令本身都很短,但每一条背后都有容易踩的坑。
bash复制mkdir -p /data/app/logs # 递归创建多级目录,父目录不存在也能建
touch test.txt # 新建空文件,或更新已有文件的时间戳
cp -r src/ dest/ # 递归复制目录
mv old.txt new.txt # 重命名;也可以用来移动文件
rm -rf /tmp/cache # 递归强制删除,危险操作
mkdir -p 里的 -p 很关键。不加的话,中间任何一级目录不存在都会报错;加上之后,缺哪级补哪级。写部署脚本时几乎总是要加。
cp -r 里的 -r 表示递归,复制目录必须加。很多人第一次复制目录失败,就是因为忘了这个参数。
rm -rf 是这一节最需要强调的地方。-r 递归,-f 强制(不询问)。这两个参数组合在一起,等于“不问、不提示、直接删到底”。它的破坏力跟目标路径直接相关,所以有两条硬性习惯值得从现在开始养成:
注意:执行
rm -rf之前,先把命令里的路径单独用ls敲一遍,确认展开结果跟你想的一致。带通配符的删除命令,尤其要先看清楚它会匹配到哪些文件。
通配符是另一个隐蔽的风险点。rm -rf /data/app/* 看起来没问题,但如果变量为空、或者路径写错一位,* 展开的范围可能完全超出预期。在脚本里使用变量拼接路径时,变量为空导致路径退化成更上层目录,是真实发生过很多次的事故类型。稳妥做法是在脚本开头加 set -u,让未定义变量直接报错而不是静默展开为空。
权限部分,先记住三组数字就够了:
| 数字 | 权限 | 常见用途 |
|---|---|---|
| 644 | 所有者读写,其他人只读 | 普通文件、配置文件 |
| 755 | 所有者读写执行,其他人读执行 | 目录、可执行脚本 |
| 600 | 只有所有者可读写 | 密钥、含敏感信息的配置 |
对应的命令是 chmod 644 file、chmod 755 script.sh。chown user:group file 用来改所有者。这里最常见的困惑是“为什么我的脚本执行不了”,八成是少了执行位,chmod +x script.sh 就能解决。
还有一条经验:目录的权限和文件的权限含义不一样。 目录上的 r 表示能列出内容,x 表示能进入,w 表示能在里面创建删除文件。一个目录只有 r 没有 x,你能看到文件名但打不开;只有 x 没有 r,你进得去但列不出内容。这个差别在排查“为什么我访问不了某个目录”时非常关键。
3. 管道和重定向,才是从“会用命令”到“能解决问题”的分界线
如果只能保留一个命令行特性,我会选管道。单条命令解决的是固定任务,管道解决的是任意任务——你可以把几个简单工具串起来,临时组合出一个专门应对当前问题的“一次性工具”。这种能力是没有上限的,也是命令行真正比图形界面强的地方。
这一节从底层机制讲起,再讲组合套路,最后落到一个完整例子。
3.1 标准输入输出:理解这三个流,重定向就不用背
每个 Linux 进程启动时,系统都会给它打开三个流:
| 编号 | 名称 | 默认去向 |
|---|---|---|
| 0 | 标准输入 stdin | 键盘 |
| 1 | 标准输出 stdout | 终端屏幕 |
| 2 | 标准错误 stderr | 终端屏幕 |
关键点在于:标准输出和标准错误是两个独立的流,只是默认都显示在屏幕上。 这就是为什么有时候你把命令输出重定向到文件了,屏幕上还是会冒出错误信息——因为错误走的是 2 号流,而 > 只重定向了 1 号流。
理解了这一点,几个看起来像咒语的写法就都能读懂了:
bash复制command > out.log # 标准输出写入文件,错误仍然打到屏幕
command 2> err.log # 只把错误写入文件
command > all.log 2>&1 # 标准输出和标准错误都写入同一个文件
command >> all.log 2>&1 # 追加而不是覆盖
command > /dev/null 2>&1 # 全部丢弃
2>&1 的意思是“把 2 号流指向 1 号流当前指向的地方”。注意顺序很重要:> all.log 2>&1 是对的,2>&1 > all.log 是错的——后者会先让 2 号流指向屏幕,再把 1 号流指向文件,结果是错误还是打到屏幕上。
/dev/null 是一个特殊的“黑洞”文件,写进去的东西直接丢弃。定时任务里经常看到 > /dev/null 2>&1,作用就是彻底静默,不让输出堆积或者触发邮件告警。但要注意,静默掉输出也意味着出问题时你什么都看不到,排查阶段不建议这么干。
管道的本质也是重定向:| 把前一条命令的标准输出接到后一条命令的标准输入上。所以 ps aux | grep nginx 的意思是“ps 的输出不打印到屏幕,而是交给 grep 去过滤”。标准错误不走管道,这也是为什么有时候管道后面的命令收不到预期的错误信息。
3.2 grep、awk、sed、sort、uniq 的组合套路
文本处理这块有几个核心工具,每个负责一件事:
grep:按行过滤,保留匹配的行awk:按列处理,取出或计算指定字段sed:按规则替换或删除sort:排序uniq:去重(通常和 sort 连用)wc:计数
单独用都很简单,组合起来才是它们的主场。几个高频套路值得直接记住:
统计某个关键词出现了多少次:
bash复制grep -c "ERROR" app.log
统计每种错误各出现多少次,按次数倒序:
bash复制grep "ERROR" app.log | awk '{print $5}' | sort | uniq -c | sort -rn | head -20
这条链路值得逐段拆解:grep 先筛出错误行,awk '{print $5}' 取第 5 列(假设错误码在这一列),sort 排序让相同内容相邻,uniq -c 统计连续重复行的次数,sort -rn 按数字倒序,head -20 取前 20 条。每一步都很简单,串起来就完成了一次完整的日志聚合分析。
为什么 uniq 前面一定要 sort? 因为 uniq 只合并相邻的重复行。输入是乱序的话,相同的值分散在不同位置,uniq 根本识别不出来。这是新手最常踩的坑之一,表现为“统计结果里同一个值出现了好几次”。
实时跟踪日志里的关键字:
bash复制tail -f app.log | grep --line-buffered "ERROR"
这里的 --line-buffered 是个细节。默认情况下 grep 在管道里会使用块缓冲,输出不是逐行刷新的,导致你看到的内容有明显延迟。加上这个参数后变成行缓冲,日志一来就能看到。
递归搜索目录下的内容:
bash复制grep -rn "数据库连接" /data/app/config/
-r 递归,-n 显示行号。找配置项、找硬编码、找某个函数在哪被调用,这个组合用得非常多。
3.3 一次真实的日志排查:从几万行里捞出那几行
光看套路不够,得走一遍完整流程。假设一个场景:某天下午监控告警,接口错误率上升,你想知道具体是哪些请求在报错。
第一步,先确认日志在长什么样。不要上来就写复杂管道,先看看格式:
bash复制tail -n 5 /var/log/app/access.log
输出大概是这样(示例结构):
code复制2024-06-11 14:32:01 INFO /api/user 200 45ms
2024-06-11 14:32:03 ERROR /api/order 500 1203ms
2024-06-11 14:32:04 ERROR /api/order 500 1180ms
第二步,确认错误确实存在,并且量级有多大:
bash复制grep -c "ERROR" /var/log/app/access.log
如果这个数字很大,说明日志级别打得太细,后面不适合直接 grep 全量,得先按时间窗口缩小范围。
第三步,按时间窗口过滤。假设问题出现在 14:30 之后:
bash复制awk '$2 >= "14:30:00"' /var/log/app/access.log | grep "ERROR" | wc -l
第四步,看是哪些接口在报错:
bash复制awk '$2 >= "14:30:00"' /var/log/app/access.log \
| grep "ERROR" \
| awk '{print $3}' \
| sort | uniq -c | sort -rn
这一步的输出会直接告诉你:/api/order 出现了 800 次,其他接口只有零星几次。问题范围一下就收窄到了一个接口。
第五步,看这个接口的错误有没有规律,比如耗时是不是都特别长:
bash复制grep "/api/order" /var/log/app/access.log | grep "ERROR" | awk '{print $5}' | sort -n | tail -5
如果耗时集中在 1000ms 以上,那大概率是下游依赖超时,而不是本服务的逻辑问题。排查方向立刻从“改代码”转向“查下游”。
整个过程中用到的命令没有一条是“高级命令”,全是 grep、awk、sort、uniq、wc、tail。真正的能力体现在顺序上:先确认现象,再缩小范围,再归类,再看规律。这个顺序比命令本身重要得多。
4. 进程、端口和资源:服务出问题时你真正要看的地方
文件那套东西解决的是“静态内容”,但线上问题大部分是动态的:服务挂了、端口不通、磁盘满了、内存涨了。这些现象对应的观察对象是进程、网络和系统资源。
这一节的排序有讲究:先看进程(服务到底还在不在),再看端口(在的话有没有在监听),最后看资源(监听正常但响应慢,是不是资源问题)。反过来查会绕远路。
4.1 进程视角:ps、top、kill 的分工
ps 是拍快照,top 是看实时。这个区别决定了它们的使用场景。
查某个服务在不在,用 ps:
bash复制ps aux | grep nginx
ps -ef | grep java
ps aux 和 ps -ef 是两个流派的写法,输出字段略有差异,但都能用。前者是 BSD 风格,后者是 System V 风格,记住一种就够。输出里重点看 PID(进程号)、CPU 和内存占用、启动命令。
grep 的结果里经常会多出一行 grep nginx 本身,因为 grep 进程的命令行里也包含这个关键词。这个“幽灵进程”是新手常见的困惑点。解决办法有两种:用 grep -v grep 过滤掉,或者用 pgrep nginx 直接按进程名匹配,后者更干净。
看实时资源占用,用 top:
bash复制top
第一屏信息量很大,但真正需要先看的是三行:load average(系统负载)、%Cpu(s)(CPU 使用分布)、KiB Mem(内存使用)。负载值要结合 CPU 核数看,8 核机器 load 到 8 才算打满,4 核机器 load 到 8 就已经过载了。这一点经常被误读。
top 里按 P 按 CPU 排序、按 M 按内存排序,这两个快捷键能帮你快速定位“是谁在吃资源”。
kill 是终止进程:
bash复制kill 12345 # 发送 SIGTERM,请求进程优雅退出
kill -9 12345 # 发送 SIGKILL,强制杀死
这两者的区别很关键。SIGTERM 是可以被进程捕获的,程序收到后可以保存状态、关闭连接、清理临时文件,属于“好好商量”。SIGKILL 无法被捕获,进程直接被内核干掉,来不及做任何清理。
注意:先
kill再考虑kill -9,中间给几秒缓冲。直接上-9可能导致数据没落盘、连接没正常关闭,事后排查更麻烦。
4.2 端口和连通性:ss、curl 的排查顺序
进程活着,不代表服务可用。中间还隔着一层:端口有没有在监听。
bash复制ss -lntp
这几个参数:-l 只看监听状态,-n 显示数字端口而不是服务名,-t 只看 TCP,-p 显示对应进程。输出里能看到哪个端口被哪个 PID 占着。
ss 是 netstat 的现代替代品,在较新的发行版上默认就有,输出也更快。老系统上可能还是 netstat -lntp,参数含义基本一致。
排查端口问题有个固定顺序,值得记住:
- 进程在不在?
ps aux | grep 服务名 - 端口在不在监听?
ss -lntp | grep 端口号 - 本机能不能连通?
curl -v http://127.0.0.1:端口/健康检查路径 - 其他机器能不能连通?从另一台机器
curl或者用telnet 主机 端口
这四步能快速把问题定位到具体层级。进程不在,是启动失败,去看启动日志;进程在但端口没监听,通常是绑定地址写错(比如绑了 127.0.0.1 而不是 0.0.0.0);本机能通外部不通,是网络层或安全组的问题;全都不通,回到第一步。
curl -v 的 -v 会打印完整的请求和响应过程,包括 DNS 解析、TCP 连接、TLS 握手、HTTP 头。排查“接口为什么慢”的时候,看这几个阶段各花了多久,比看应用日志更直接。
4.3 磁盘和内存:df、du、free 的差别
df 和 du 经常被混淆,其实一个看分区,一个看目录。
bash复制df -h # 各分区的使用情况
du -sh /data/* # 各子目录占用的空间
df -h 回答的是“哪个分区快满了”。输出里重点看 Use% 那一列,超过 80% 就该关注,超过 90% 很多服务会开始出问题(写日志失败、临时文件创建不了)。
du -sh 回答的是“这个分区里的空间被谁占了”。-s 是汇总,-h 是人类可读单位。常见用法是先 du -sh /data/* 找出占用最大的子目录,再一层层往下钻,直到定位到具体文件。
这里有个经典现象:df 显示磁盘满了,但 du 加起来远远不够。原因通常是文件被删了但进程还持有句柄——文件在目录里看不见了,空间却没释放。这时候用 lsof | grep deleted 能找到持有句柄的进程,重启那个进程空间就回来了。
内存看 free:
bash复制free -h
重点看 available 那一列,而不是 free。Linux 会把空闲内存大量用于缓存,所以 free 数值小是正常现象,available 才是真正还能给新进程用的量。只看 free 就断定“内存不够”,是非常常见的误判。
5. 排查链路:拿到一个故障现象,命令该按什么顺序敲
前面几节讲的是“工具”,这一节讲“用法”。工具再多,没有顺序就是乱敲。这一节把排查过程抽象成一个可以反复套用的框架。
5.1 先分层,再动手:五个层级的定位顺序
任何线上问题,都可以按这个顺序往下切:
| 层级 | 看什么 | 常用命令 |
|---|---|---|
| 服务层 | 进程还在不在 | ps aux、systemctl status |
| 端口层 | 有没有在监听 | ss -lntp |
| 应用层 | 本机请求通不通 | curl -v、看应用日志 |
| 资源层 | CPU、内存、磁盘是否吃紧 | top、free -h、df -h |
| 依赖层 | 数据库、缓存、下游是否正常 | curl、telnet、看连接数 |
这个顺序的原则是从近到远、从确定到不确定。前三层都是本机可验证的,速度快、结论明确;后两层涉及外部,排查成本高。如果前三层就能定位问题,就不用往下走了。
反过来的常见错误是:一上来就怀疑下游数据库,花半小时抓包,最后发现是自己进程根本没起来。先做便宜的检查,再做昂贵的检查。
5.2 常见现象对应的命令速查
把几个高频现象和对应的第一反应列出来,可以当成一个随身清单:
“网站打不开了”
bash复制ps aux | grep -E "nginx|java|node" # 服务进程在不在
ss -lntp | grep 80 # 80 端口有没有监听
curl -v http://127.0.0.1/ # 本机能不能访问
df -h # 磁盘是不是满了
顺序不要乱。磁盘满是很隐蔽的原因——日志写不进去,服务不一定崩,但会各种异常。
“接口特别慢”
bash复制top # 先看 CPU 和负载
free -h # 看 available
curl -v http://127.0.0.1/api/xxx # 看各阶段耗时
tail -f /var/log/app/access.log # 看慢请求的分布
curl -v 能区分是 DNS 慢、连接慢还是响应慢,这个信息决定了下一步查哪。
“磁盘空间不够”
bash复制df -h # 确认哪个分区满
du -sh /data/* | sort -rh | head # 找出大目录
lsof | grep deleted # 检查已删除但未释放的文件
find /var/log -name "*.log" -size +1G # 找超大日志文件
sort -rh 里的 -h 能识别 K/M/G 单位,比 sort -rn 更准确。
5.3 一个完整的排查示例
假设收到告警:“订单服务不可用”。
第一反应不是重启,是确认状态:
bash复制systemctl status order-service
输出显示 active (running),说明进程还在。那问题不在启动环节。
接着看端口:
bash复制ss -lntp | grep 8080
有监听,说明服务确实在接收连接。问题可能在应用内部或者依赖。
本机发一个请求试试:
bash复制curl -v --max-time 5 http://127.0.0.1:8080/health
结果卡住 5 秒后超时。说明服务虽然监听,但处理不过来。这时候看资源:
bash复制top
发现 CPU 只有 20%,但进程状态里有大量 D 状态(不可中断睡眠)。D 状态通常意味着在等 IO。那就去看磁盘:
bash复制df -h
iostat -x 1 3
df 显示根分区 100% 使用率。找到原因了:磁盘写满,应用写日志时阻塞,请求线程全部卡在 IO 上。
再往下找是什么占满的:
bash复制du -sh /var/* | sort -rh | head -5
发现 /var/log 占了 40G,其中一个日志文件 30G。
处理方式是先清理,再看为什么会涨到 30G——日志轮转配置有问题,或者某个错误在疯狂刷屏。只清理不解决根因,过几天还会再来一次。
这个例子的价值在于:每一步的结论都决定了下一步的方向。 如果一开始就重启服务,问题会暂时消失,但磁盘还是满的,过一会儿又会复发,而且你丢掉了所有现场信息。
6. 从会用到用得稳:别名、历史、脚本和危险命令边界
命令敲熟了之后,下一步不是学更多命令,而是减少重复劳动、降低出错概率。这一节讲的是“怎么把经验固化下来”。
6.1 把重复操作沉淀成 alias 和历史检索
有些命令组合你一天要敲十几次,这时候就该给它起个短名字:
bash复制alias ll='ls -lah'
alias grep='grep --color=auto'
alias ports='ss -lntp'
alias 只在当前会话有效,要持久化就写进 ~/.bashrc 或者 ~/.zshrc。改完执行 source ~/.bashrc 立即生效。
历史记录是另一个被低估的工具。history 列出所有执行过的命令,Ctrl+R 进入反向搜索,输入几个字符就能找回之前那条长命令。这两个功能能省掉大量重复输入。
历史记录里还有个实用技巧:!! 表示上一条命令,!$ 表示上一条命令的最后一个参数。比如你刚 ls /data/app/config,接着想 cd 进去,直接 cd !$ 就行。
需要提醒一点:历史记录会记录你敲过的所有命令,包括带密码的那些。在共享服务器上,避免把敏感信息直接写在命令行里,用交互式输入或者环境变量的方式更稳妥。
6.2 最小可用脚本模板
当一件事需要重复做、或者需要按顺序做很多步,就该写成脚本了。脚本不需要写得很复杂,一个稳妥的最小模板大概是这样:
bash复制#!/bin/bash
set -euo pipefail
LOG_FILE="/var/log/myjob.log"
log() {
echo "[$(date '+%Y-%m-%d %H:%M:%S')] $*" | tee -a "$LOG_FILE"
}
main() {
log "任务开始"
# 具体逻辑放这里
log "任务结束"
}
main "$@"
模板里有几个关键点值得解释:
set -euo pipefail 这一行包含三个开关。-e 让命令失败时立即退出,而不是继续往下执行(否则错误会被掩盖);-u 让引用未定义变量时报错(防止空变量展开成危险路径);-o pipefail 让管道中任何一段失败都算整体失败(默认只检查最后一段)。
日志函数用 tee -a 同时输出到屏幕和文件,排查时既能实时看到,事后也有记录。时间戳格式统一,方便后续 grep。
脚本里凡是涉及路径的地方,建议用变量集中定义,不要散落在各处。这样改路径只改一处,也便于在测试环境替换。
6.3 危险命令的边界:rm、通配符和权限
命令行最大的风险不是不会用,是在权限足够的情况下用错了命令,而且没有撤销。
几条值得刻进习惯的规则:
规则一:删除前先打印。 把 rm -rf $DIR 改成先 echo rm -rf "$DIR",确认输出符合预期再执行。或者干脆用 ls "$DIR" 先看一眼目标。
规则二:变量一定加引号。 rm -rf $DIR 和 rm -rf "$DIR" 在变量为空时行为完全不同。前者会退化成 rm -rf(缺少目标,部分实现会报错,但也有实现会出问题),后者会变成 rm -rf ""(空字符串,直接报错)。加引号是廉价的安全网。
规则三:绝对路径比相对路径安全。 在脚本里用 /data/app/cache 而不是 ./cache,因为脚本的工作目录不一定是你以为的那个。
规则四:不要长期用 root。 日常操作使用普通用户,需要提权时再 sudo。这样即使命令敲错,破坏范围也被权限限制住了。
规则五:重要操作前有备份。 改配置前 cp config config.bak.$(date +%F),这个习惯成本极低,收益极高。
注意:
rm没有回收站,删掉就是删掉了。凡是涉及-r的操作,都值得多花十秒钟确认路径。
7. 学习路径:三个阶段和几个常见误区
最后回到学习本身。Linux 命令这个主题,最容易走的两条弯路是“贪多”和“求全”——想一次学完所有命令,想搞清楚每个参数。实际学习中,这两条路都走不通,因为命令的数量和参数组合远超记忆容量,而且大部分你一辈子用不上。
7.1 三阶段路径
按下面的顺序走,每一步都有明确的验收标准:
第一阶段:能独立完成日常操作(一到两周)
目标是能在一台服务器上完成“看文件、改配置、传文件、重启服务”这一套动作。涉及的命令大概 20 条:pwd、ls、cd、cat、less、tail、vim、mkdir、cp、mv、rm、chmod、chown、ps、kill、df、du、free、ss、curl。
验收标准:给你一台干净的服务器,让你部署一个静态页面并让它能被访问,全程不查资料。
第二阶段:能用管道解决具体问题(两到四周)
重点从“单条命令”转向“组合”。核心是 grep、awk、sed、sort、uniq、wc 这几个工具,加上重定向和管道。
验收标准:给你一份日志,你能在五分钟内回答“错误最多的是哪个接口”“哪个时间段错误集中”“慢请求的耗时分布”。
第三阶段:能把流程固化成脚本(长期)
开始写脚本,把重复操作自动化。重点是错误处理、日志、参数校验,而不是功能本身。同时开始理解权限模型、环境变量、进程管理这些更底层的东西。
验收标准:你写的脚本别人能直接跑,出问题时日志里能看到足够的信息定位。
7.2 几个高频误区
误区一:以为要背下来才算会。 实际上没人背命令。真正熟练的人靠的是肌肉记忆加 --help,遇到不常用的参数一样要查。记住“有这么个工具”比记住“所有参数”重要得多。
误区二:追求学全。 Linux 有几百条命令,日常高频使用的不到 50 条。把 awk 学透,收益远大于把 100 条命令各学个皮毛。
误区三:只在本地虚拟机上练,不碰真实环境。 虚拟机上删错了可以重装,这种环境练不出谨慎。当然也不是让你直接上生产,而是建议在一个“删了会有后果”的测试环境里练手,比如自己搭的服务。
误区四:忽视输出格式。 很多人写管道卡住,是因为没先看原始输出长什么样。awk '{print $5}' 取第 5 列,如果实际格式跟预期不一样,取出来的就是垃圾。先 head 几行看清楚格式,再写处理逻辑,这个习惯能省掉大量调试时间。
误区五:不写注释。 脚本里一行 awk 可能三天后自己都看不懂。关键步骤加一行注释,成本几秒钟,收益是未来几个小时的排查时间。
7.3 适用边界:命令不是万能的
命令行很强,但它有明确的边界,认清这些边界比多学几条命令更有价值。
命令行的优势场景:批量处理、远程操作、自动化、日志分析、快速验证。这些场景里,图形界面要么做不到,要么效率低一个数量级。
命令行的劣势场景:可视化分析、复杂的数据探索、需要频繁对比的场景。比如看一个监控趋势图,图形界面几秒钟就能看出异常时段,命令行得写一堆聚合逻辑。工具选错了,努力会白费。
不适合新手的场景:直接在生产环境做破坏性操作。命令行没有确认弹窗,也没有回收站,学习阶段应该在有恢复手段的环境里练。
还有一点值得说清楚:命令行的学习曲线不是线性的。前两周进步很快,因为基础命令简单直接;中间会有一段平台期,感觉怎么学都还是在敲那几条;突破平台期的关键通常不是学新命令,而是完整地解决一个真实问题——从现象到定位到修复,走完一遍,之前零散的命令会突然串起来。
这也是为什么我一直建议:不要按“命令列表”学,按“问题”学。今天的问题是“日志太大了怎么快速定位错误”,那就把 grep、awk、sort、uniq、tail 这一组吃透;明天的问题是“服务起不来了”,那就把 ps、ss、systemctl、journalctl 这一组吃透。问题驱动学到的命令是带上下文的,比单纯记忆牢固得多,也更容易在下次遇到类似问题时被调用出来。
真正拉开差距的,从来不是谁记得多,而是谁能在看到现象的那一刻,知道第一条命令该敲什么。
