Linux 常用命令这事儿,说简单是真简单,无非是 ls、cd、cp、mv 那一套;说难也真难,同样的命令在不同发行版、不同 shell、不同场景下,行为还真不一样。我这些年日常维护服务器、写部署脚本、排查线上问题,见过太多人卡在同一个地方——不是不会敲命令,而是不知道什么时候该用哪个命令、出了问题怎么排查。这篇文章不打算搞成命令字典,而是把我自己从基础到进阶最常用的一套命令串起来,讲清楚每条命令背后的逻辑和适用场景。看完之后,你至少能做到:拿到一台陌生机器,能迅速摸清它的状态;处理日志和文本,不再只靠肉眼;遇到报错,知道往哪个方向查。
1. 先把思路理顺:Linux 命令不是背出来的
1.1 Unix 的哲学藏在每条命令里
很多人学 Linux 命令的最大误区,是想把命令当单词表一样背下来。这不是不行,但效率极低。Linux 从诞生那天起就遵循一套非常朴素的设计思想:每个工具只做好一件事,工具之间通过标准输入输出组合成更强大的工具。这意味着你真正需要理解的核心其实只有两个:一是每条命令的输入输出是什么,二是怎么把它们串起来。
比如 grep 只负责按规则过滤文本,sort 只管排序,uniq 只管去重。单独看都不复杂,但把它们用管道串成一条命令,就能完成一段看起来相当复杂的日志分析工作。理解了这条底层逻辑,你就不会面对几百条命令发怵了。
1.2 这篇文章适合谁来读
如果你是刚接触 Linux 的新人,我的建议是从第 2、3 章开始,把文件操作和文本处理练熟,这是日常使用频率最高、性价比最高的部分。如果你已经会基本操作,但对权限、进程、网络排查这些模块还停留在"用过但不懂"的阶段,重点看第 4、5、6 章。如果你是想提升效率和脚本能力的老手,第 7、8 章的进阶技巧和问题排查实录,多少能给你一些新思路。
我默认你手上有一台能折腾的 Linux 环境,不管是虚拟机、云主机还是本机装了双系统,都可以。看文章的同时亲手敲一遍,比什么都强。
1.3 动手之前,先养成这三个习惯
第一,不知道命令怎么用,先查man或--help,而不是立刻去搜网页。man ls能告诉你的参数和注意事项,比绝大多数零散教程都完整。
第二,永远别把 Tab 键浪费了。命令补全和路径补全能帮你避免百分之九十的拼写错误。我见过太多人在路径上卡半天,最后发现就是少打了一个字母。
第三,记住 Ctrl+C 是中断当前操作,Ctrl+Z 是把当前进程挂起到后台,这两个组合键处理的报错次数,比你想象的多得多。
2. 文件与目录操作:你每天敲得最多的命令
2.1 看清自己在哪里:pwd、ls、cd 的三个隐藏细节
pwd用来查看当前所在目录,大部分人知道这就够了。但pwd -L和pwd -P的区别值得多说一句:-L 显示的是逻辑路径,也就是你 cd 的时候看到的路径;-P 显示的是物理路径,也就是符号链接解析之后的真实位置。当你进入了带软链接的目录,经常会出现 pwd 显示的路径和你心理预期不一致的困惑,这时候用pwd -P看一眼最保险。
ls是使用率最高的命令,我的默认习惯是ls -lh。-l 显示详细属性,-h 把文件大小转成人话(K、M、G)。想看隐藏文件就加 -a,想按时间排序就用-lt,想按大小排序就用-lS。很多人不知道ls -lt里那个 t 是 time 的缩写,ls -lS里的 S 是 size,理解了缩写逻辑,参数就好记多了。
cd的细节更隐蔽。cd -是回到上次所在的目录,这个在两张目录之间来回切换时极其好用。cd ~去用户主目录,cd ..去上级目录,都是常识了。但注意cd到没有权限的目录时,bash 会直接报错,有些 shell 会先切进去再报错,行为差异正好能帮你判断当前 shell 是哪种。
2.2 文件和目录的增删改:touch、mkdir、cp、mv、rm
创建空文件用touch,它的真正用途其实是修改文件时间戳,但大家默认拿它建文件。创建目录记得mkdir -p,-p 的意义是递归创建父目录,比如mkdir -p /data/logs/2026/01,无论中间的目录存在与否都能一次建好,避免了逐层创建的麻烦。
复制文件用cp,复制目录必须加 -r(递归)。我日常更推荐cp -a,它把文件属性、权限、时间戳一起保留,备份配置文件的黄金选择。mv既能移动文件也能重命名文件,跨文件系统移动时其实是先复制后删除,所以大文件移动会感觉到明显延迟,这不是命令出了问题,是机制如此。
rm是所有人最先学会、也最容易出事的命令。我的建议是:生产环境少用裸奔的rm -rf,至少加个-i让它逐个确认。不是胆小,是我真实见过有人把变量没拼对,一条命令把整个项目目录清空的场面。大活人差点当场坐地上。删除前先ls确认一下路径,花两秒钟,能省一整天的后悔药。
注意:
rm -rf /tmp/test/和rm -rf /tmp/test/的区别不在命令本身,而在你对路径的判断。永远不要在不确定绝对路径的时候使用rm -rf。我自己坚持一个习惯:删除前先执行pwd确认当前位置,再执行echo 目标路径看一眼展开结果。
2.3 看文件内容不是只有 cat
cat看小文件没问题,看大文件就是一泻千里,又费滚动又费眼。这时候用less,它支持上下翻页、搜索。进到 less 之后,按空格翻页,按g跳到文件头,按G跳到文件尾,输入/关键词搜索,按q退出。这一套熟了之后,你再也回不去 cat 了。
head和tail用在看文件开头和结尾。head -n 50看前 50 行,tail -n 100看后 100 行,但真正的杀手锏是tail -f。它不退出,而是持续跟踪文件新增内容,看日志的神器。线上排查问题的时候,我基本都会开一个终端窗口挂着tail -f 应用.log,一边操作一边观察日志实时输出,问题定位速度直线上升。
wc用来统计行数、单词数、字节数,wc -l统计行数的用法最常用。想知道一份文件有多少行,或者计算日志条数,它比什么都快。
2.4 通配符与引号:shell 扩展的入门
*匹配任意多个字符,?匹配单个字符,[0-9]匹配数字范围。比如ls *.log列出所有日志文件,mv file?.txt dest/移动file1.txt、fileA.txt这类文件。这套规则叫 glob 匹配,是 shell 帮你展开的,不是命令自己实现的。理解这一点很重要:如果你在一个目录下敲rm *.bak,shell 先把所有 .bak 文件的完整名字列出来,再逐个交给 rm 执行。
引号的使用同样关键。单引号里的内容原样传参,双引号里的变量和命令替换会被解析,反引号或$()则把命令的输出替换到当前位置。写脚本时经常遇到"变量没展开""路径带空格被拆成两个参数"这类问题,本质都是没搞清楚引号的语义。我的经验是:路径里有空格就老老实实加双引号,不想让 shell 做任何解析就用单引号。
3. 文本处理三板斧:grep、sed、awk
3.1 grep:定位关键信息最快的方式
grep是所有 Linux 用户最先进阶的文本工具。最基本用法是grep "关键词" 文件,它把匹配的行原样打印出来。我在实际使用中几乎一定会带几个参数:-n显示行号,-i忽略大小写,-v反向选择,-c只统计匹配行数,-r递归搜索目录。
搜索日志是 grep 最常见的场景。比如想看某服务今天有没有报错,直接grep -i "error" /var/log/服务.log。想排除掉某些噪音行,用grep -v "正常信息"。多个关键词同时匹配,可以用grep -E "error|exception|failed",也可以连续管道过滤。-E是扩展正则的意思,日常写正则尽量带它,不然很多语法(比如|和+)会被当普通字符处理。
grep 也支持正则表达式,但新手最容易犯的错是把正则当成语文搜索去用。比如grep "2026-01-01"中的-在正则里没什么特殊含义,但grep "."里的点号是匹配任意字符,想匹配真正的句点必须写成\.。这个坑我踩过不止一次,查半天以为数据有问题,结果就是正则里的点号在捣乱。
3.2 sed:替换、删除、打印一气呵成
sed的全名是流编辑器,它逐行处理文本,最适合做替换和按行操作。最常用的是sed 's/旧内容/新内容/g' 文件,把文件里每行的旧内容换成新内容,最后的 g 表示全局替换,不加 g 只替换每行第一个匹配。
把替换结果写回原文件,需要-i参数。我强烈建议第一次使用-i时带上备份后缀,也就是sed -i.bak 's/old/new/g' 文件,这样会生成一个.bak备份文件。改配置文件的场景里,这个习惯能救你命。我曾经在批量替换一批服务器的配置文件时,发现替换规则里少写了一个转义,如果带了备份,一条命令就全部还原了。
sed -n '10,20p' 文件打印指定行号区间的行,sed '3d' 文件删除第 3 行,sed 's/^/prefix/' 文件在每行开头插入内容。这些用法组合起来,就足够覆盖日常百分之八十的需求了。要提醒的是,sed 默认不修改原文件,只会把处理结果输出到屏幕,想保存结果请重定向到新文件或使用 -i。
3.3 awk:想提取字段的时候用它
awk在处理"按列提取"这种需求上几乎没有对手。它默认按空格或制表符分隔每一行,$1表示第一个字段,$2表示第二个,$NF表示最后一个,$0表示整行。用法示例:awk '{print $1, $2}' 文件,提取每一行的前两个字段。
想处理分号或其他分隔符,用-F指定。经典场景是解析/etc/passwd,awk -F: '{print $1}' /etc/passwd就能把所有用户名列出来。NF是每行字段数量,NR是行号,awk 'NR>=2 && NR<=10' 文件可以按行号范围过滤,比 sed 的写法更直观。
awk 真正强大的地方在于可以写条件判断和循环,但日常使用中,我建议先从"提取字段 + 简单的过滤条件"入手。比如df -h | awk '$5 > 80 {print $1}',只打印磁盘使用率超过百分之八十的分区,这一条命令就相当于一个小型告警工具。
3.4 管道组合:从日志里挖出你要的真相
单条命令的价值有限,管道把它们串起来之后才是真正的生产工具。管道的符号是|,它把左边命令的标准输出,变成右边命令的标准输入。
给你一个我实际常用的例子:统计一个站点访问日志里哪些 URL 被访问次数最多。
awk '{print $7}' 访问日志.log | sort | uniq -c | sort -rn | head -20这段命令的生命周期是这样的:awk 从日志每一行里提取第 7 个字段,也就是请求的 URL;sort 把这些 URL 排序,让相同的 URL 靠在一起;uniq -c 统计每组连续相同行的数量;sort -rn 按统计数量反向排序;最后 head -20 只取出前 20 条。整条命令不用写任何脚本,一行搞定,输出就是排好序的热门 URL 列表。
这就是我反复强调的"思路比命令更重要"的典型例子:你不需要背二十条命令,你只需要知道 awk 能提取字段、sort 能排序、uniq 能被排序后的内容去重计数。剩下的,就是组合。
4. 权限与用户管理:别再把 chmod 777 当万能药
4.1 看懂 -rw-r--r-- 在说什么
ls -l输出里第一列像-rw-r--r--的东西,总共 10 个字符,第一个字符表示文件类型。-是普通文件,d是目录,l是符号链接,b和c是块设备和字符设备。后面 9 个字符分成三段,每段 3 个字符对应一组权限:所有者(u)、所属组(g)、其他人(o)。
每段里的 r、w、x 分别代表读、写、执行。注意目录的执行权限含义不一样:对目录来说,x 代表能否进入这个目录,r 代表能否列出目录内容。一个目录只有 r 没有 x,你用ls能看到文件名,但cd进不去,操作文件名时也会碰壁。这种"目录权限伤脑筋"的情况,理解了这个差异就能解开。
4.2 chmod 的两种姿势:符号模式与数字模式
chmod是用来修改权限的命令。第一种是符号模式,比如chmod u+x 脚本.sh给所有者加执行权限,chmod g-w 文件去掉组写的权限。这种写法适合微调,表达的是"我要给谁加什么权限"。
第二种是数字模式,本质是二进制位的十进制表示。r 等于 4,w 等于 2,x 等于 1,三段相加。chmod 755 文件就是所有者 rwx(7),组和他人 r-x(5)。我整理了一张常用对照表,可以直接照抄:
| 权限组合 | 数值 | 典型用途 |
|---|---|---|
| rw------- | 600 | 私有配置文件,只有自己能读写 |
| rw-r--r-- | 644 | 普通文件,全员可读,仅所有者可写 |
| rwx------ | 700 | 私有目录 |
| rwxr-xr-x | 755 | 可执行文件、公开目录 |
| rwxrwxrwx | 777 | 不推荐,任何人可读可写可执行 |
实践建议:普通文件用 644,脚本和目录用 755,私密内容用 600 或 700。777 不是不能用,而是绝大多数场景不需要。设置成 777 等于对所有人敞开大门,出了问题你连追责的入口都没有。
4.3 chown 与 chgrp:修改文件所有权
chmod改的是权限,chown改的是文件所有者。命令格式是chown 用户名:组名 文件,比如chown www:www /data/html,这是部署站点的标准操作,把目录交给运行 Web 服务用的用户来管理。只想改所属组,可以单独用chgrp,不过chown 用户名:组名一步到位更常见。
这里有个容易忽略的点:把文件从一个用户转给另一个用户通常需要 root 权限,普通用户只能改自己名下文件的组。所以你在执行 chown 时看到 Permission denied,不是文件坏了,而是你权限不够,需要配合 sudo 使用。
4.4 用户管理:useradd、passwd、su 与 sudo
创建用户用useradd 用户名,只在系统层面建一个用户,还没设置密码。设置密码用passwd 用户名,它会交互式地让你输入两次密码。批量设置可以用echo "用户名:密码" | chpasswd。
用户之间的切换,su 用户名是切到另一个用户,单纯输入su默认切到 root。但从普通用户切到 root 需要输入 root 密码,这就让很多环境变得很尴尬——root 密码根本没人知道。更符合现代运维习惯的是sudo 命令:它不需要对方的密码,只需要当前用户在 sudo 组里,权限控制更清晰。
判断当前用户和身份,用whoami和id。id的输出能告诉你 uid、gid 和所属组,排查"我明明有这个权限为什么不生效"的问题时,先跑id确认自己到底是谁。很多所谓权限 bug,其实就是登录错了用户。
5. 进程与系统状态:判断机器健康的基本功
5.1 ps、top:进程到底在干嘛
ps是查看进程快照的命令。我最常用的写法是ps aux,它列出了所有进程的详细信息,包括用户、PID、CPU 占用、内存占用和命令本身。想找某个特定进程,直接用管道过滤:ps aux | grep 进程名。但注意,这条命令会把自己的 grep 进程也列出来,所以你看到一条额外匹配是正常的,别被它吓到。
top是动态刷新版的进程查看器。进入 top 后按1可以看每个 CPU 核心的负载,按M按内存占用排序,按P按 CPU 占用排序,按q退出。我一直强调,分析机器卡顿问题时不要只看进程列表,先看 top 第一行的 load average,这个三个数分别代表过去 1 分钟、5 分钟、15 分钟的系统平均负载。如果三个数都很高,说明系统一直处于高负载,不是一瞬间的抖动。
5.2 kill 的正确姿势:别动不动 kill -9
kill是用来给进程发送信号的命令。默认的kill PID发送的是 SIGTERM(15 号信号),相当于礼貌地请进程退出,让进程有机会清理现场。而kill -9 PID发送的是 SIGKILL,直接强制从内核层面干掉进程,不给任何清理机会。
我见过太多人拿 kill -9 当万能药,连普通进程都用强杀。问题是强杀可能带来文件损坏、数据丢失、配置没来得及落盘。正确的顺序是:先kill PID温和地请求退出,等几秒看它有没有退,实在不退再用kill -9。排查的时候配合ps确认 PID,别估算,估算错了就是误杀。批量结束进程可以用pkill -f 进程名关键词,但同样从温和信号开始。
如果进程变成了僵尸进程,输出里状态是 Z,这时候 kill 对它是无效的,因为它已经死了,只是残留了进程表项。僵尸进程的回收要靠它的父进程来收尸,普通手段很难处理,一般建议重启父进程或干脆重启机器。
5.3 磁盘和内存:df、du、free 的读数方法
磁盘空间看df -h,h 表示人类可读格式。这一条命令输出当前所有挂载文件系统的使用情况,哪块分区满了一目了然。进一步定位到目录级,用du -sh 目录看单个目录总大小,du -sh *列出当前目录下所有子目录的大小,du -h --max-depth=1限制递归深度。找大文件的通用流程是:df -h发现某个分区满了,然后du -sh /分区下各目录逐层缩小范围,配合sort -rn排序,一层层定位到是哪个目录在占空间。
内存看free -h。输出的第二行是整体内存情况,真正要注意的是 available 这一列,它代表实际可用的内存。很多人看到 used 很高就慌,其实 Linux 的内存策略是尽量用空闲内存做缓存,buff/cache 占用的部分在需要时是能被释放的。判断内存够不够,看 available,不要只看 used。
5.4 systemctl 与 systemd 日志
现代发行版的服务管理基本都是 systemd 的天下了。systemctl status 服务名查看服务运行状态,systemctl start/stop 服务名启动或停止服务,systemctl enable 服务名设置开机自启,systemctl restart 服务名重启服务。这几个命令属于现在必须掌握的标配。
服务日志用journalctl查看。journalctl -u 服务名看某个服务的全部日志,journalctl -u 服务名 -f实时跟踪日志,journalctl --since "10 minutes ago"看最近十分钟的日志。排查"服务起来又挂了"这类问题,基本套路就是先systemctl status看状态,再journalctl -u看报错,两条命令能把七成问题定位出来。
6. 网络命令:连不上、下载慢、端口被占怎么办
6.1 ping 与端口测试
ping用来测试目标主机是否可达,发 ICMP 回显请求。注意两点:第一,ping默认会一直发下去,加-c 4指定发 4 个包就停;第二,某些主机或网络环境会屏蔽 ICMP,所以 ping 不通不代表服务不通,还需要测端口。
测端口最朴素的是telnet 主机 端口,能连上会进入连接状态,连不上直接报错。但 telnet 客户端不是所有机器都装,更常见的是用nc -vz 主机 端口快速测试。我自己更习惯用 bash 自带的/dev/tcp技巧:timeout 3 bash -c 'echo > /dev/tcp/目标主机/端口' && echo 通 || echo 不通。不需要额外装任何工具,脚本里用尤其方便。
6.2 curl 与 wget
curl是我心中最值得熟练掌握的网络命令,没有之一。curl -I 网址只看响应头,curl -v 网址显示完整的请求和响应过程,curl -o 文件名 网址下载并保存。调试接口时,curl -X POST -H "Content-Type: application/json" -d '{"key":"value"}' 接口地址这种用法,可以直接在命令行里模拟请求,排查接口问题的效率比写代码高得多。
wget更适合下载场景,支持断点续传,wget -c继续之前的下载。批量下载一组文件,wget -i 列表文件按列表逐个拉取。我的经验是:调试接口首选 curl,下载大文件首选 wget,各司其职。
6.3 查端口和连接的 netstat、ss、lsof
端口被占是服务器上问得最多的网络问题。查看本机监听端口,老派的是netstat -tlnp,t 对应 TCP,l 是 listening,n 是不做反向解析,p 是显示进程 PID。新派的是ss -tlnp,输出更简洁、速度更快,两个命令存在代际差异但参数逻辑一致。
更进阶的是lsof -i :端口号,它能直接告诉你占用这个端口的进程是谁。lsof的另外一个高光场景是:磁盘空间满但df显示还有空间,因为可能有大文件被删除了但还被某个进程持有。这时候lsof | grep deleted就能把这种"幽灵文件"找出来。
7. 进阶玩法:重定向、管道、后台任务与 Shell 环境
7.1 重定向的流向要搞清楚
标准输入、标准输出、标准错误是 Linux 程序的三个默认通道。重定向就是把这三个通道重新指向别处。>把标准输出写到文件(覆盖),>>追加到文件末尾,2>重定向标准错误,2>&1把标准错误合并到标准输出。
顺序是这里最阴险的细节。command > file 2>&1和command 2>&1 > file表面差不多,实际完全不同。前者先把标准输出指向文件,再把标准错误指向标准输出,所以两者都进了文件;后者先让标准错误指向当前的标准输出(终端),再把标准输出指向文件,结果报错还是打在屏幕上。我在脚本里犯过不止一次这个错,现在写重定向一律按"先文件,再合并"的顺序。
7.2 后台任务:&、nohup、Ctrl+Z
默认情况下,命令在前台运行,占用当前终端。想在后台跑,在命令末尾加&,比如python 脚本.py &。它会返回一个任务号和一个 PID,程序在后台运行,终端还能继续使用。
但有个大坑:当你关闭终端时,后台任务通常也会被挂断信号杀死。要让它脱离终端独立运行,用nohup 命令 &,nohup 的意思是忽略挂断信号。标准做法是nohup 命令 > 日志文件 2>&1 &,输出重定向到日志,错误一起收集,任务在后台安稳跑。之后再想看它状态,用ps和tail -f 日志文件就够了。
如果命令已经在运行然后你按了 Ctrl+Z,它会挂起。jobs查看挂起/后台的任务列表,fg把任务拉回前台,bg让挂起任务在后台继续跑。这套配合在误操作时特别有用。
7.3 alias 与 .bashrc:让常用命令偷懒
alias给命令起别名。ll='ls -lh'这类操作人人可设,但真正的效率提升在于把复杂的高频命令缩写。我自己的.bashrc里长期存着这样几条:
alias ll='ls -lh' alias la='ls -la' alias ..='cd ..' alias grep='grep --color=auto'改动.bashrc之后记得source ~/.bashrc让配置立即生效。历史上有一个非常经典的教训写在很多地方:默认alias rm='rm -i'的机器上,你写的脚本里如果依赖 rm 不带确认地删除文件,运行行为就会被改变。所以脚本里写命令尽量用完整路径,或者显式绕过别名,避免被交互环境干扰。
8. 打包压缩与软件安装:从 tar 到包管理器
8.1 tar 的三种常用姿势
tar最初是打包工具,现在几乎总是和压缩一起用。常见参数分三组:c 创建、x 解包、t 查看列表;z 表示 gzip 压缩,j 表示 bzip2,J 表示 xz;f 后面跟文件名。最经典的组合是:
tar -czvf 备份.tar.gz /要打包的目录 tar -xzvf 备份.tar.gz tar -tzvf 备份.tar.gz注意-czvf中 z 表示用 gzip 压缩,如果文件后缀是 .tar.gz 就一定要带 z。我的经验是:打包时用-C指定目标目录,可以避免解包时把文件散落到当前目录。另外打包前用--exclude排除日志、缓存目录,是控制包体积的有效手段。
8.2 apt、yum、dnf 怎么选
包管理器分两大家族:Debian 系的 apt,Red Hat 系的 yum 和它的继任者 dnf。它们的逻辑一致,只是命令名不同。更新软件源用apt update或yum makecache,安装软件用apt install 软件名或yum install -y 软件名,卸载用apt remove或yum remove。
日常维护中,我用 apt 的三个高频操作是:apt update刷新源信息,apt upgrade升级全部可升级的包,apt install安装单个软件。Red Hat 系还有一个重要区别:yum install后面最好加-y跳过交互确认,否则在无人值守的脚本里会一直卡在确认提示上。另有一点值得记:装完系统后第一件事就是把包管理器源切到国内镜像,理由不需要多解释,体验过的人都知道差别。
8.3 源码安装的固定流程
有些软件不在包仓库里,只能源码编译。标准的安装流程是三步:./configure检查编译环境并生成 Makefile,make编译源码,make install安装到系统目录。./configure --prefix=/自定义/路径指定安装位置,这个技巧能让软件装在你可控的目录下,不污染系统目录,卸载时直接删目录即可。
源码安装最容易卡在依赖缺失上,configure 阶段会告诉你缺什么库,按照提示用包管理器装上对应的开发包,再重新执行 configure。这个环节的耐心很重要,我的经验是,装之前先看一遍 README 或 INSTALL 文件,里面写清楚了依赖清单和版本要求,能省去大量来回折腾的时间。
9. 实战排查:高频问题与解决实录
9.1 command not found 的排查逻辑
看到command not found,第一反应不是"这个命令不存在",而是先检查拼写。排除了拼写错误之后,再看这个命令是不是在 PATH 路径下。echo $PATH会列出所有可执行文件的搜索路径,如果你的可执行文件放在/usr/local/bin但 PATH 里没有这个目录,系统当然找不到。
处理思路很简单:要么把可执行文件移到 PATH 包含的目录,要么把目录加进 PATH。临时加用export PATH=$PATH:/新路径,永久加写进.bashrc。另外有些命令在不同发行版里属于不同的包,比如某些系统里ifconfig和netstat需要额外安装,所以"command not found"也可能是"包没装"的信号。
9.2 Permission denied 的几种可能
Permission denied是最常见的报错,但原因不止一种。文件权限不够,用chmod加权限;文件所有者不对,用chown改属主;目录没有执行权限导致无法进入,也是权限问题的一种。还有一种隐蔽情况是挂载参数限制了执行,mount时带了noexec的话,哪怕权限全对,目录里的可执行文件也跑不起来。
排查顺序我建议这样:先ls -l看权限位,再id确认当前身份,确认是不是该文件的合法访问者,最后mount查看挂载参数。一层层排除,大多数问题都能解。还有一个偏门但真实存在的坑:某些操作系统里文件系统损坏会挂载成只读,这时候所有写操作都会报错,touch /都不能成功,dmesg | tail能看到文件系统相关的内核日志。
9.3 磁盘明明有空间,却说 No space left
df -h显示空间充足,但你创建文件还是报"磁盘已满",这是两个最典型的原因之一:inode 耗尽或文件被删除但仍被进程占用。
inode 是文件系统的索引节点,它决定这个文件系统能创建多少个文件。空间没满但 inode 满了,一样写不进新文件。用df -i查看 inode 使用率,如果出现百分之百,清理一下无用的小文件即刻恢复。
另一个更经典的原因是文件被删除但进程还握着它。日志文件这种情况最典型:程序打开日志文件,你把日志删了但程序没重启,它依然持有着已经被删除的文件句柄,磁盘空间完全没有释放。这时候lsof | grep deleted能把所有"被删但仍占用"的文件列出来,定位到对应 PID 后重启进程,空间就回来了。这个坑我当年排查了一下午,最后发现罪魁祸首是一天前的日志文件。
9.4 kill 不掉进程怎么办
进程杀不掉,先看它的状态。ps aux输出的 STAT 列,如果是 Z 就是僵尸进程,这种进程本体已经结束,只是等父进程收尸,kill 对它无效,需要处理的是它的父进程。如果是 D 状态,说明进程正在不可中断的内核态等待,大概率是在等磁盘 I/O,这时候 kill 信号根本送不进去,只能等它自己完成或重启系统。
还有一种你没权限的情况。普通用户只能杀属于自己的进程,别人的进程要 root 权限才能杀。看到 Operation not permitted 的时候,先确认你是不是 root,或者用sudo kill。最后啰嗦一句:kill -9 是最后手段,不是第一手段,先把温和信号用一遍,给程序一点体面。
10. 私人建议:把命令变成自己的习惯
写了这么多,最后分享几条我用 Linux 这些年沉淀下来的习惯。第一条,别追求记住所有命令,追求记住"有哪些类型的工具",真正要用的时候man一下对应命令的参数,十分钟就能上手。第二条,高频的命令一定要做成肌肉记忆,比如 ls、cd、grep、awk、tail、ps 这类每天都会碰的,不要想一下才敲得出来。第三条,凡是要在服务器上执行的批量操作,先在测试环境跑一遍,哪怕只是一个echo看一眼命令展开的结果。
我自己的一个小技巧是:在.bashrc里加一条export HISTTIMEFORMAT="%F %T ",让 history 记录带上时间戳。几个月之后回头看命令行历史,你能准确知道当时在哪个时间点执行了什么操作,排查历史问题的时候能少绕很多弯路。
Linux 命令行是个越用越顺手的工具,核心不在于你背了多少命令,而在于你建立了多少"出现问题 → 想到某类工具 → 快速查阅参数 → 解决问题"的链路。把这篇文章里的命令亲手敲一遍,遇到问题再回来翻对应章节,你很快就会发现自己已经能从手工操作进化到写脚本解决问题的阶段了。