最近后台收到不少留言,问的问题都比较集中:Linux 命令到底怎么学才高效?为什么背了一大堆命令,一到服务器上实操就发懵?还有人直接把面试题丢过来,说看到 awk、sed 就头大。今天这篇就把我这些年折腾 Linux 的经验捋一捋,不搞那种几百条命令堆出来的“大全”,而是给你一条真正能落地的学习主线,覆盖日常运维、开发排查、面试突击这几个最实际的场景。
1. 先破除一个误区:背命令不如懂命令的分类逻辑
很多新手学 Linux 最容易踩的坑,就是拿着命令手册从头背到尾,好像 curl、wget、tar、zip、unzip、rsync 全都得记下来才算学会。结果真到用的时候,连 ls -l 的输出都读不利索,更别说排查问题了。
1.1 命令的本质:每个命令都是一个程序
先明确一件事:命令并不是什么神秘的东西,它本质上就是一个可执行程序,只不过放在了系统的 PATH 环境变量所指定的目录里。你在终端敲 ls,系统其实是在 /bin、/usr/bin 这些目录里找到了名为 ls 的二进制文件,然后把它跑起来。
可以用 which 命令查看某个命令到底在哪个路径下:
bash复制which ls
# /usr/bin/ls
再用 type 看看这个命令是不是有别名或者内建版本:
bash复制type ll
# ll is aliased to 'ls -l --color=auto'
搞清楚这一点,你就不会对着某个“新命令”发怵了——所谓“新命令”,不过是一个你还没见过的程序而已。遇到没见过的命令,第一反应不该是去翻书,而是直接敲 命令 --help,或者 man 命令 查手册。这两个命令自带的使用说明,比市面上绝大多数教程都准确、都新。
1.2 分类逻辑:按“要操作的对象”来组织知识
我不建议按字母表去背命令,更有效的方式是按“操作对象”来分类。Linux 系统里,你日常打交道的东西其实就那么几类:文件与目录、用户与权限、进程与服务、网络与磁盘、文本内容。每一类对应一小撮高频命令,把这些吃透,你已经能覆盖 90% 的工作场景了。
我整理了一个极简分类表,这基本就是我对 Linux 命令知识体系的核心框架:
| 操作对象 | 高频命令 | 典型场景 |
|---|---|---|
| 文件与目录 | ls, cd, pwd, mkdir, cp, mv, rm, find |
日常文件操作、清理磁盘 |
| 用户与权限 | useradd, usermod, chown, chmod, sudo, su |
建账号、授权、部署应用 |
| 进程与服务 | ps, top, kill, systemctl, journalctl |
看负载、查进程、重启服务 |
| 网络与磁盘 | ip, ss, ping, df, du, mount |
配IP、查端口、看空间 |
| 文本处理 | grep, sed, awk, sort, uniq, wc |
分析日志、处理输出 |
这篇文章后面的内容,就沿着这张表逐层展开。你不用一次性记完,只需要把每一次实操中遇到的命令,归类到这张表里,慢慢地它就会变成你自己的知识体系。
1.3 学习建议:用“场景”代替“背诵”
我个人强烈建议,练命令别光盯着终端发呆,最好是先给自己设定一个场景,比如“新装了一台服务器,我要创建一个部署账号,把代码放上去,装好 nginx,再配个静态 IP”。这个过程中你自然会用到 useradd、mkdir、cp、tar、dnf、systemctl、nmcli 这一串命令。
这种“场景驱动”的学习方式,比刷十遍命令大全都管用。因为你每敲一条命令,脑子里都会形成一条关联记忆:这个命令在解决这个场景里的哪个具体问题。而不是孤零零地记住一个命令的语法,转头就忘。
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. 文件与目录操作:高频命令的细节与坑
文件操作是 Linux 使用频率最高、也是新手最容易出事故的领域。先别急着复制粘贴各种“一键脚本”,把下面这些细节摸透,你会少踩很多坑。
2.1 ls 读到的不只是名字:逐字段拆解输出
很多人看 ls -l 的结果,只看得到文件名和大小,这远远不够。
bash复制ls -l /etc/passwd
# -rw-r--r--. 1 root root 1277 Feb 18 2024 /etc/passwd
这一行的信息量很大,从左到右拆开看:
- 第1位:文件类型。
-是普通文件,d是目录,l是软链接,b/c是块设备/字符设备。 - 第2-10位:权限位,分三组:属主(user)、属组(group)、其他人(other),每组三位分别是读(r)、写(w)、执行(x)。
- 第2列:硬链接数。普通文件一般是1,目录的硬链接数代表其子目录数量加2。
- 第3列:属主。文件归哪个用户所有。
- 第4列:属组。文件归哪个组所有。
- 第5列:文件大小,单位是字节。
- 第6列:最后修改时间。
- 第7列:文件名。
如果你觉得 ls -l 展示的信息还不够细,可以用 stat 命令查看更完整的元数据,包括 i-node 号、访问时间、修改时间、变更时间。
bash复制stat /etc/passwd
实际工作中,我常用的几个 ls 组合:
bash复制ls -lah # 人类可读大小,显示隐藏文件(. 开头)
ls -lt # 按修改时间倒序,找最新文件很快
ls -lS # 按文件大小排序,找大文件用
ls -R # 递归列出子目录,慎用,输出可能很长
2.2 目录穿梭与创建:cd、pwd、mkdir 的实用技巧
cd 是最基础的操作,但有两个小技巧值得记住:
bash复制cd - # 回到上一个目录,在多个路径之间切换非常方便
cd ~ # 回到当前用户的家目录
mkdir 创建目录时,最常用的是 -p 参数,它可以递归创建多级目录:
bash复制mkdir -p /data/logs/nginx
这条命令会自动创建 /data、/data/logs、/data/logs/nginx 三层目录。如果不加 -p,父目录不存在时就会报错。
还有一个冷门但好用的技巧:用花括号展开批量创建目录:
bash复制mkdir -p /data/{logs,backup,scripts}
等价于:
bash复制mkdir -p /data/logs /data/backup /data/scripts
删除目录时,rmdir 只能删空目录,实际用得更少。更多人直接用 rm -rf。但这里我要提醒一句:rm -rf 是 Linux 上最危险的操作,没有之一。很多人因为路径多打了个空格或者少写了个字母,把系统删了、把数据库文件清了、把家目录清空了,这种事每年都能看到。
一个务实的建议:执行 rm -rf 之前,先用 ls 确认路径,再执行 pwd 看一下当前目录。真正稳妥的人,会先 mv 到 /tmp 等确认没问题后再删,相当于一个手动“回收站”。
2.3 复制移动与删除:cp、mv、rm 的行为差异
cp 复制文件是最常见需求,但 cp 有很多细节。最常用的参数是:
bash复制cp -a source destination
-a 等于 -dR --preserve=all,也就是保留软链接关系、递归复制、并保留文件属性(权限、时间戳、属主属组等)。备份目录、迁移文件时用这个最保险。
如果只是想同步两个目录,大多数人会想到 cp -r,但它会覆盖同名文件且保留时间戳、权限方面不如 -a 可靠,所以我会优先推荐 cp -a。
mv 移动文件时有一个坑:当源和目标在同一个文件系统内时,mv 只是修改目录项,速度极快;但如果跨文件系统(比如从 /home 移动到 /data,而它们挂载在不同分区),mv 会先执行复制,再删除源文件,速度会慢不少,而且如果中途空间不够,会留下半个文件。
rm 删除目录或海量小文件时也很讲究。很多人直接 rm -rf /data/logs,但如果日志目录下有上百万个小文件,这个命令可能要跑很久。更快的做法是换一种思路:先 mkdir /tmp/trash,再用 mv /data/logs /tmp/trash/,最后后台 rm -rf /tmp/trash。因为 mv 改目录项的速度远快于逐个文件删除。如果目录本身就是独立的挂载点,更狠的做法是直接重新格式化或删除挂载点再重建目录,几秒就完事。
2.4 查找文件:find 是新手最容易忽略的肌肉记忆
find 是文件查找的核心工具,语法是:
bash复制find [路径] [匹配条件] [处理动作]
最常用的几个匹配条件:
bash复制find /data -name "*.log" # 按文件名匹配
find /data -type f # 按类型:f=文件,d=目录,l=软链接
find /data -mtime +7 # 修改时间超过7天的文件
find /data -size +100M # 大于100MB的文件
find /data -perm -002 # 其他用户可写的文件(安全检查用)
处理动作首选 -exec:
bash复制find /var/log -name "*.log" -mtime +30 -exec rm {} \;
这条命令的含义是:在 /var/log 下找到所有30天前的 .log 文件,然后批量删除。{} 是占位符,代表 find 找到的每一个文件。
-exec 有一个需要注意的点:它会为每个文件单独执行一次后面的命令,如果文件量极大,效率偏低。这时候可以配合管道和 xargs:
bash复制find /var/log -name "*.log" -mtime +30 | xargs rm
xargs 会把前一条命令的输出按块传给后面的命令,批量执行,速度比 -exec 快得多。不过遇到文件名带空格的情况要小心,xargs 默认按空格切分,需要加 -0 参数配合 find -print0 使用,或者直接 find -name "*.log" -mtime +30 -delete,用 -delete 更简洁。
3. 进程与系统状态:运维排查的日常底牌
服务器出问题的时候,能不能快速定位,拼的就是进程和系统状态这一块的基本功。
3.1 ps:看进程的两种姿势
ps 命令有两种风格,很多人傻傻分不清。其实是历史遗留问题:ps aux 是 BSD 风格,ps -ef 是 System V 风格,两者输出的信息大同小异。我习惯用 ps aux,因为它的 CPU 和内存使用率字段(%CPU、%MEM)默认就会显示,看起来很直观。
拿到 ps aux 的输出后,重点看 STAT 这一列,它反映进程当前的状态:
| 状态标识 | 含义 | 说明 |
|---|---|---|
R |
Running | 正在运行或可运行 |
S |
Sleeping | 可中断睡眠,等待某事件 |
D |
Uninterruptible Sleep | 不可中断睡眠,通常在等磁盘 I/O |
Z |
Zombie | 僵尸进程,已结束但父进程未回收 |
T |
Stopped | 已停止,可能是被 Ctrl+Z 挂了 |
如果看到很多 D 状态的进程,说明系统磁盘 I/O 可能有瓶颈;看到很多 Z 僵尸进程,就要检查父进程是不是有 bug 没做好子进程回收。
3.2 top/htop:动态监控的交互操作
top 是经典中的经典,但要真正用好它,需要掌握几个交互快捷键:
- 按
P:按 CPU 使用率排序 - 按
M:按内存使用率排序 - 按
k:输入 PID 后可以发信号终止进程 - 按
1:展开/折叠多核 CPU 信息
很多人看 top 的第一行里有 load average, 误以为它是 CPU 使用率。实际上,load average 是“运行队列平均长度”,反映的是系统整体负载压力。假设你的服务器有 8 个 CPU 核,load average 显示 8.00,意味着运行队列基本满载;如果只有 1 个核但负载到了 8,说明系统已经严重过载。
真正的 CPU 使用率要看 top 第一行里的 %Cpu(s) 那一段,里面有 us(用户态)、sy(内核态)、wa(I/O 等待)等细分指标。其中 wa 长时间过高,说明磁盘 I/O 跟不上,CPU 在空等磁盘,这时候光看 top 不够,还要配合 iostat 确认是不是磁盘瓶颈。
htop 是 top 的增强版,颜色区分、树状结构、鼠标操作都很方便。在 CentOS/RHEL 系上用 dnf install htop,在 Ubuntu 上用 apt install htop 就能装上。如果环境不允许装额外工具,就用 top 也完全够。
3.3 kill 不只是杀进程:信号机制
kill 的命名很有迷惑性,它的真正作用不是“杀死”,而是向进程发送一个信号(signal)。不同的信号,进程收到后的行为完全不同。
bash复制kill -l # 列出所有信号
最常用的是两个:
SIGTERM(15):终止信号。这是kill的默认信号,请求进程优雅退出,让进程有机会清理临时文件、关闭连接、释放资源。杀正常服务时,应该优先用-15。SIGKILL(9):强制杀死。这个信号不会给进程任何做清理工作的机会,由内核直接终止进程。只有在进程完全卡死、-15不起作用时才用-9。
一个常见场景:每次改完 nginx 配置,你想重载配置而不是重启进程:
bash复制nginx -t && nginx -s reload
如果 nginx 进程卡死,再考虑用 kill -9 强杀。强杀后记得检查一下是不是留下了 .pid 文件之类的残留。
pkill 和 killall 是批量操作工具,按进程名匹配:
bash复制pkill -f "java.*OrderService" # 按完整命令行匹配,适合区分同名的不同服务
killall nginx # 杀掉所有名为 nginx 的进程
用 pkill 的时候要特别小心匹配串写得太过宽泛,搞不好会把不相关的进程一起杀了。我见过有人用 pkill -f order 想杀订单服务,结果把包含 order 关键词的日志采集进程全部干掉了。好习惯是先用 pgrep -fa 预览一下要匹配的进程列表,确认无误后再杀。
3.4 systemd 服务管理:进程的“监护人”
现代 Linux 发行版基本都用 systemd 作为 init 系统。运维日常打交道最多的就是 systemctl 命令。
bash复制systemctl status nginx # 查看服务状态
systemctl start nginx # 启动服务
systemctl stop nginx # 停止服务
systemctl restart nginx # 重启服务
systemctl enable nginx # 设置开机自启
systemctl disable nginx # 取消开机自启
systemctl list-units --type=service # 列出所有已加载的服务
服务异常时,第一件事就是看日志:
bash复制journalctl -u nginx --since "10 minutes ago"
journalctl 按单元(unit)过滤日志,再配合 --since、-p(按优先级过滤)能快速定位问题。排查启动失败的服务时,systemctl status 末尾会给出 hints,但更详细的错误信息基本都在 journalctl 里。
4. 权限与用户管理:一不小心就踩雷的领域
权限是 Linux 安全模型的基石,但恰恰是新手踩坑最多的地方。理解权限的底层逻辑,比背几条 chmod 命令重要得多。
4.1 权限位的二进制本质
还记得前面 ls -l 输出的第 2-10 位吗?比如 rwxr-xr--,它的本质是三组二进制的映射关系:
- 第 1 组
rwx:属主权限,对应的二进制是111,十进制7 - 第 2 组
r-x:属组权限,二进制是101,十进制5 - 第 3 组
r--:其他人权限,二进制是100,十进制4
所以 chmod 754 就是把权限设置为 rwxr-xr--。数字写法的计算规则很简单:读=4,写=2,执行=1,三者相加。
很多初学者不理解:为什么目录的执行权限(x)这么关键?因为在一个目录里,x 权限代表能否穿过这个目录进入下一层。如果你只有 r 权限,你可以 ls 看到目录下的文件名;但你想 cd 进去或访问里面的文件,就必须有 x 权限。这就有个经典坑:很多新手给目录配了 644,结果别人能列目录但进不去,怎么也找不到原因。目录至少需要 5(r-x)权限才能正常访问,如果要创建或删除文件,则需要 7(rwx)。
我还想强调一点:chmod 777 这种操作,在真实的服务器环境里应该极力避免。它意味着任何用户都能读写执行这个文件,一旦里面是可执行脚本或者配置文件,风险极大。如果只是想放开写权限,也应该是 chmod 664 或按需最小化授权,而不是一刀切 777。
4.2 属主与属组:chown 的使用时机
创建文件时,文件属主是当前用户,属组是当前用户的主组。但在实际部署中,经常需要把文件的所有权交给某个服务账号。
bash复制chown nginx:nginx /usr/share/nginx/html -R
这条命令把 /usr/share/nginx/html 及其下所有文件的属主和属组都改为 nginx。-R 是递归,注意只对目录用;对单个文件用 -R 没有意义但也不会有副作用。
有个细节要留意:chown 会清掉 setuid/setgid 位(如果文件原本设了的话)。所以在一个需要 setuid 的程序上执行 chown 后,要重新设置这些特殊位。虽然日常很少碰到,但这种“隐藏行为”容易埋坑。
4.3 用户管理:useradd 和 usermod
创建用户是运维的高频操作,比如给新同事开账号,或者在部署应用时创建专用账号。
bash复制useradd -m -s /bin/bash -G wheel deploy
这条命令做了三件事:
-m:创建家目录/home/deploy-s /bin/bash:指定登录 shell-G wheel:把用户加入wheel组,在 RHEL/CentOS 系里这个组成员默认有 sudo 权限
在 Debian/Ubuntu 上,sudo 组的名字是 sudo 而不是 wheel,这个差异值得注意。跨发行版部署时,最稳妥的做法是 usermod -aG sudo deploy 或者先确认系统上的 sudo 组成员配置。
创建完用户后,别忘设置密码:
bash复制passwd deploy
以后想改用户属性,用 usermod:
bash复制usermod -aG docker deploy # 把 deploy 用户加入 docker 组,注意 -a 表示追加
-a(append)这个参数特别容易忘。不加 -a 的话,usermod -G docker deploy 会把用户从原来所在的附加组里全部移除,只保留 docker 组,一不小心就把用户的权限改没了。
删除用户时:
bash复制userdel -r deploy
-r 会一并删除家目录和邮件池。老版本的 userdel 在用户有进程在跑时可能删除不干净,新版更健壮。
4.4 sudo:普通用户干“大事”的门
su 和 sudo 的区别,一句话讲透:su 是切换到目标用户身份,需要目标用户的密码;sudo 是用当前用户的身份,但以 root 权限执行某条命令,认证的是当前用户的密码(或者配置为 NOPASSWD 时不用密码)。
日常建议一律用 sudo,少用 su。原因是 su root 会直接给你一个 root shell,你后续敲的每一条命令都是 root 身份,误操作的概率大幅上升;而 sudo 只在单个命令上临时提权,权限范围可控得多。
配置 sudo 权限通常用 visudo 命令编辑 /etc/sudoers。这个文件有严格的语法,直接 vim /etc/sudoers 改坏会导致 sudo 完全不可用,所以系统才规定要用 visudo,它在保存前会检查语法。
一个最常见的配置:让某个用户免密执行 sudo 命令:
code复制deploy ALL=(ALL) NOPASSWD: ALL
这行配置在自动化脚本里尤其实用,不过它的安全边界也很大,要确保这个账号本身的访问控制足够严密。
5. 网络与磁盘:最容易被忽略的底层能力
文件操作和进程管理玩熟了,很多人卡在网络和磁盘这两块。倒不是多难,而是命令的“新旧交替”让网上的教程变得混乱,让新手不知道该信哪个。
5.1 ip 命令时代的网络排查
如果你还在用 ifconfig、netstat,有些新系统已经默认不装这两个命令了。现代主流的网络排查命令是 ip 和 ss,来自 iproute2 工具包。
查看 IP 地址:
bash复制ip addr show
查看路由表:
bash复制ip route show
ip route add default via 192.168.1.1 dev eth0 # 手动添加默认路由
查看端口监听:
bash复制ss -lntp
ss 比 netstat 快很多,而且信息更全。-l 只看监听的连接,-n 不做域名解析,-t 只看 TCP,-p 显示对应进程。排查“端口被谁占了”这个问题,这条命令是首选。
说到网络连通性,要破除一个误解:ping 通只代表 ICMP 协议可达,并不代表业务端口是通的。经常遇到的情况是,ping 能通,但 curl 访问业务接口超时。问题往往出在防火墙、安全组或服务本身没监听。
测试端口连通性,我推荐用 /dev/tcp 这个 bash 内置特性,不用额外装工具:
bash复制timeout 3 bash -c 'echo >/dev/tcp/192.168.1.10/3306' && echo "port is open" || echo "port is closed"
nc(netcat)也是测端口的利器:
bash复制nc -zv 192.168.1.10 3306
如果 nc 没安装,在 RHEL 系上装的就是 nmap-ncat 包。
5.2 磁盘空间与 inode
服务器磁盘满是个高频故障,但“磁盘满”也分两种:一种是块空间(block)满了,另一种是 inode 满了。前者容易被理解,后者很多新手完全没概念。
df -h 看的是块空间:
bash复制df -h
df -i 看的是 inode 使用情况:
bash复制df -i
inode 相当于文件系统的“档案索引”,每个文件(包括目录)都要占用一个 inode。如果一个分区里创建了大量的小文件,即使块空间还有剩余,inode 也可能先用完,导致系统报 No space left on device。
定位大目录用 du:
bash复制du -sh * | sort -hr | head -20
这条命令列出当前目录下所有子目录/文件的大小,按倒序排列,只看前 20 个。这是磁盘排查的第一步。
真正把磁盘塞爆的,常见三类元凶:
- 大型日志文件:比如 nginx 的
access.log、Java 应用日志,单个可以长到几十 GB。 - Docker 的 overlay 目录:
/var/lib/docker里堆满了容器镜像层和日志,这个目录在长期运行的生产机上是磁盘大户。 - core dump 文件:进程崩溃时生成的核心转储文件,可能非常大,往往被忽略。
查找超过 1GB 的大文件:
bash复制find / -xdev -type f -size +1G -exec ls -lh {} \; 2>/dev/null
-xdev 限制只在当前文件系统内查找,避免跑到 /proc、/sys 这些虚拟文件系统里浪费时间。
5.3 静态 IP 配置入口
配置静态 IP 是 Linux 基础操作里比较靠近系统管理的一环。不同的发行版配置方式差异很大。
RHEL / CentOS / Rocky Linux 系,推荐用 nmcli:
bash复制nmcli con mod ens33 ipv4.addresses 192.168.1.100/24
nmcli con mod ens33 ipv4.gateway 192.168.1.1
nmcli con mod ens33 ipv4.dns "223.5.5.5 8.8.8.8"
nmcli con mod ens33 ipv4.method manual
nmcli con up ens33
改完用 ip addr show 验证。
Ubuntu / Debian 系新版用 netplan,配置文件在 /etc/netplan/ 下,基本格式如下:
yaml复制network:
version: 2
ethernets:
eth0:
dhcp4: false
addresses:
- 192.168.1.100/24
routes:
- to: default
via: 192.168.1.1
nameservers:
addresses: [223.5.5.5, 8.8.8.8]
改完执行:
bash复制sudo netplan apply
配置静态 IP 有个经典坑:走了内网但上不了外网。这通常是因为默认路由没配好或者 DNS 配置错误。排查顺序是:先 ip route show 看默认路由是否存在,再 cat /etc/resolv.conf 看 DNS 是否正常,最后 ping 223.5.5.5(纯 IP)和 ping www.baidu.com(域名)对比,能快速定位是路由问题还是 DNS 问题。
6. 文本处理三剑客:grep、sed、awk 的实战组合
为什么单开一章讲这三个工具?因为在实际排查问题、分析数据时,它们才是真正的效率神器。面试题考它们也是常事。
6.1 grep:过滤的起点
grep 是文本过滤的核心。最常用的就是按模式匹配内容:
bash复制grep "ERROR" /var/log/app.log
grep -E "ERROR|WARN" /var/log/app.log # 扩展正则,匹配多个关键字
grep -r "orderId" /data/services/order/ # 递归搜目录
grep -l "error" /data/logs/*.log # 之列文件名,不列具体行
grep -v "^#" /etc/nginx/nginx.conf # 反向匹配,过滤掉注释行
grep 性能也扛得住,日志文件几个 GB 也能跑。但如果文件真的极大,grep 还是会慢,可以配合 tail 或 --include 限制范围:
bash复制grep "ERROR" /var/log/app.log --include="*.log" -r
一个实用的习惯:先 grep -c 数一数匹配行数,确认不是太多再往终端输出,否则输出几十万行能把终端卡死。
6.2 sed:流编辑器的常用操作
sed 是一个流编辑器,通俗说就是“一边读一遍改”的文本处理工具。我最常用的三个场景是替换、删除、打印指定范围。
替换是 sed 最高频的用法:
bash复制sed -i 's/old_string/new_string/g' config.ini
-i 直接修改文件,g 表示全局替换。改文件前,我习惯先不加 -i 跑一次,把输出看一遍确认符合预期,再加 -i 真正落地。这是防止手工改错配置的最后防线。
删除指定行:
bash复制sed -i '/^#/d' config.ini # 删除所有注释行
sed -i '5,10d' config.ini # 删除第5到第10行
打印指定范围(不加 -n 会输出两次,务必注意):
bash复制sed -n '20,40p' app.log # 只打印第20到40行
sed 可以一次执行多个命令,用 ; 或 -e 分隔:
bash复制sed -i -e 's/foo/bar/g' -e '/^$/d' config.ini
6.3 awk:文本处理中的小语言
awk 的定位已经不是“命令”,而是一门小型的文本处理语言。它默认按空白字符(空格和 Tab)把每一行切分成字段,用 $1、$2 表示第 1 列、第 2 列,$0 表示整行,$NF 表示最后一个字段。
一个最常见的入门例子:想找出监听在 80 端口的进程 PID,可以直接组合 ss 和 awk:
bash复制ss -lntp | awk '$4 ~ /:80$/ {print $6}'
我来拆解一下这条命令:ss -lntp 输出的每一行代表一个连接,$4 是本地地址和端口(比如 0.0.0.0:80),~ 是正则匹配操作符,/:80$/ 表示行尾是 :80,匹配成功后就打印第 6 列(进程信息)。
awk 的经典统计能力也不遑多让:
bash复制ps aux | awk '$3 > 50.0 {print $2, $11, $3}' # 打印CPU使用率超过50%的进程PID、命令和CPU占用
带 BEGIN 和 END 的求和模式:
bash复制awk '{sum += $1} END {print "total:", sum}' data.txt
6.4 综合实战:从 nginx access log 统计访问量
把三个工具组合起来,就能干一件非常典型的事:从 nginx 访问日志里统计访问量 Top 10 的 IP。命令如下:
bash复制awk '{print $1}' /var/log/nginx/access.log | sort | uniq -c | sort -rn | head -10
链路拆开:
awk '{print $1}':取出每行第一个字段,也就是客户端 IP。sort:把 IP 排序,让相同 IP 聚集在一起。uniq -c:统计每个连续重复项的个数。sort -rn:按统计数字倒序排列,-n是按数值排序,-r是倒序。head -10:取前 10 行。
这里有个容易被忽略的点:如果日志文件非常大,比如几十 GB,这条命令直接跑会占用大量内存和 CPU。更稳妥的做法是先按天切分日志再统计,或者用 grep 先过滤出某天的日志:
bash复制grep "2024-06-01" /var/log/nginx/access.log | awk '{print $1}' | sort | uniq -c | sort -rn | head -20
面试中经常在此基础上延伸,比如统计某个 URL 被访问的次数,或者找出返回 5xx 最多的 URL。核心思路都是一样的:先用 grep/awk 把关心字段提取出来,再排序去重统计。理解了这个套路,就能以不变应万变。
7. 实战串联:一次高负载问题排查用到的命令
前面分门别类讲了命令,这一章更贴近现场。我把一次真实的高负载排查过程串起来,让你感受一下这些命令是如何配合使用的,也给你一个可以在面试里直接复述的完整链路。
7.1 接到报警之后的第一组命令
某天收到监控报警,说某台应用服务器负载高。我登录服务器的第一组命令是:
bash复制uptime
uptime 的输出最直接:load average: 20.18, 15.26, 10.02。看到 1 分钟负载 20,5 分钟 15,15 分钟 10,说明负载是刚刚飚上去的,还在上升期,不是已经持续很久的老问题。
接着打开 top,按 P 键按 CPU 使用率排序,马上看到某个 Java 进程的 PID 是 23241,CPU 占了 300% 多,明显异常。一个正常的 Java 应用,即使业务高峰也很少持续 300% 以上,除非发生死循环或者连接数异常爆发。
7.2 从进程到细节:/proc 目录是宝藏
确认 PID 之后,顺着 PID 往下排查:
bash复制ps -fp 23241
这条命令展示进程的完整详情,包括启动时间、启动命令、CPU 累计使用时间。ps -fp 拿不到的信息,可以直接查 /proc/23241/ 目录,这是 Linux 内核暴露给用户的进程信息入口:
bash复制ls -l /proc/23241/cwd
cat /proc/23241/cmdline | tr '\0' ' '
cat /proc/23241/environ | tr '\0' '\n' | grep -E "JAVA_OPTS|APP_ENV"
/proc/23241/cwd 可以看到进程启动时所在的工作目录,往往能直接确认它是从哪个 jar 包启动的。cmdline 和 environ 里的环境变量也能帮助判断运行时配置有没有问题。
接下来我查了对应时间段的日志。假设日志路径是 /data/logs/app.log,先看这个时间段有没有异常堆栈:
bash复制grep "2024-06-01 10:2[0-9]" /data/logs/app.log | grep -A 30 "OutOfMemory\|Deadlock\|ERROR"
由于日志量很大,先按时间范围过滤,再用 -A 30 把关键字后面 30 行一起打出来,避免只看单独一行而错过堆栈上下文。
7.3 确认现场与临时止损
在现场基本确认是高负载异常后,第一要务是止损。我查看了一下这个进程是不是真的不可用,如果确实假死,再用 kill 做处理:
bash复制kill -15 23241
先给 SIGTERM,让 Java 进程有机会做优雅停机,必要时配合等待几秒再查看:
bash复制ps -fp 23241
如果还在,再 kill -9 23241 强制清理。如果是生产服务,标准的做法是直接交给 systemd 重启:
bash复制systemctl restart app-service
重启后用 top 再观察一段时间,确认负载回落到正常水平,load average 从 20 降到个位数,才算处理完成。
处理完之后,我会顺手把这次排查用到的关键命令和日志片段整理到团队的复盘文档里,方便下次遇到类似问题时快速参考。这种事后的记录,比任何教程都值钱,因为它是结合你实际环境沉淀下来的知识。
7.4 把命令练成肌肉记忆
很多人担心没有真实服务器可以练手,其实完全不必。现在一台普通的笔记本就能用 WSL2 或虚拟机跑一个完整的 Linux 环境,几分钟就能搭好,随便折腾。比如你想模拟上面的高负载场景,完全可以开几个 dd 或 md5sum 进程把 CPU 打满,然后亲身走一遍 top 到 ps 到 kill 的完整流程。
另外,个人经验是:别放过那些“看起来很简单”的操作。比如新装完系统,我会习惯性地把 ip addr、df -h、free -h、systemctl status 这些命令挨个敲一遍,确认系统基本状态正常。这个习惯让我对服务器“正常的样子”非常敏感,一旦有异常,能更快地意识到“哪里不对劲”。
面试备考也一样,不要死背命令选项,而是把前面的排查链路完整讲清楚,再配合说出每个命令为什么要这样用、输出里哪一列是关键,面试官一般都会认可你是真正用过的,而不是临时背的。
写在最后:先动手,再总结
这篇文章从文件操作、进程管理、用户权限到网络磁盘、文本处理,再到完整的排查链路,基本覆盖了 Linux 基础命令的核心体系。但我最想强调的一点是:看一百遍不如敲一遍。不要攒着“等有时间再练”,Linux 这种东西是动手驱动的,你只需要一台虚拟机或者一个云服务器,照着文中的场景一个个跑一遍,很快就会发现这些命令之间的配合会越来越顺手。等到你遇到问题时脑子里能自动浮现出“该用哪条命令、输出应该长什么样”,Linux 基础这关就算真正过了。后续再往网络排查、性能优化、脚本化运维这些方向深入时,你会发现今天打下的地基全是值得的。
