后端工程师的代码最终跑在 Linux 服务器上,而服务器没有图形界面、没有鼠标,只有一个终端。凌晨三点收到报警,你能依靠的只有命令行。命令行熟练度,直接决定你是五分钟定位问题,还是五小时抓瞎。
好消息是,日常 90% 的场景只需要不到 20 个命令。本篇不罗列命令大全,只讲真正高频的,并且每个都配真实的使用场景。建议在本地终端(macOS 的 Terminal 或 Windows 的 WSL)边看边敲——只看不敲,本篇的价值会直接打对折。
先看大局:机器现在怎么样
登上服务器的第一件事,永远是看整体状态,就像医生先看体温和心率。
top
top 是实时仪表盘,重点看三行:
- load average:系统负载,三个数字分别是 1/5/15 分钟平均值。经验法则:持续超过 CPU 核数就说明有任务在排队。
- %Cpu(s):
us(用户程序占用)高说明你的服务在忙;wa(IO 等待)高说明磁盘或网络是瓶颈,CPU 在干等。 - MiB Mem:看
free(空闲)而不是used——Linux 会主动用空闲内存做缓存,used高不等于内存不够。
top 界面里按 P 按 CPU 排序、按 M 按内存排序、按 1 展开每个核、按 q 退出。更喜欢彩色界面的话可以装 htop,操作逻辑一样。
配套的两个快速命令:
df -h # 磁盘使用情况,-h 用人类可读的 G/M 显示
free -h # 内存使用情况
磁盘写满是最常见的低级事故——日志不停写,某天磁盘 100%,数据库无法写入,服务全体报错。df -h 应该成为你登机器的条件反射。
进程与端口:我的程序怎么了
场景一:找到那个吃 CPU 的进程。
ps aux --sort=-%cpu | head -10
ps aux 列出所有进程,--sort=-%cpu 按 CPU 降序排,head -10 只看前 10 个。找到你的服务进程,记下 PID(进程号)。想精确找某个服务:
ps aux | grep node
pgrep -fl node # 更简洁的写法
场景二:端口被谁占了? 启动服务时报 EADDRINUSE(地址已被占用),用这两个命令查:
ss -tlnp | grep 3000 # 谁在用 3000 端口(t=TCP l=监听 n=数字端口 p=进程)
lsof -i :3000 # 等价的另一种写法,macOS 上常用
ss 是 netstat 的现代替代品,更快,输出里直接带进程名和 PID。macOS 没有 ss,用 lsof -i :3000。
场景三:杀掉失控的进程。
kill 12345 # 礼貌地请求 PID 12345 退出(发 SIGTERM)
kill -9 12345 # 强制杀死(SIGKILL),不给它收拾残局的机会
永远先 kill 再 kill -9。kill -9 会跳过进程的清理逻辑,正在写的文件可能损坏、连接可能没正常关闭——那是最后手段,不是默认手段。

日志排查三件套:tail、grep、awk
线上排障 70% 的时间在看日志。三个命令组合起来威力巨大。
tail:实时追踪日志流。
tail -f /var/log/app/error.log # 持续滚动显示新写入的日志
tail -n 500 app.log | less # 先看最后 500 行
tail -f 是排障的第一反应:复现问题的同时盯着日志滚动,错误往往在滚动中自己跳出来。
grep:从海量日志里捞出你要的行。
grep "ERROR" app.log # 所有错误行
grep -i "timeout" app.log # 忽略大小写
grep -C 5 "ERROR" app.log # 错误行前后各 5 行上下文(最重要!)
grep -c "ERROR" app.log # 只数有多少条
grep "ERROR" app.log | grep "userId=42" # 管道串联:错误里再筛特定用户
只看错误行往往看不懂原因,-C 5 看上下文才是关键——真正的线索常常在报错前几行的警告里。
awk:把日志当表格处理。 假设日志每行是 时间 级别 耗时 消息 这样的结构:
awk '{print $1, $3}' app.log # 打印第 1、3 列
awk '$3 > 1000' app.log # 耗时超过 1000ms 的行
awk '{print $2}' app.log | sort | uniq -c | sort -rn | head # 各级别日志数量统计
最后那条是经典组合拳:取第 2 列 → 排序 → 去重计数 → 按数量倒序 → 看前 10。三十秒内你就能回答“今天哪类报错最多”。
一套实战排障套路:报警说接口超时 → 先 top 看机器整体 → ss -tlnp 确认进程活着且端口在听 → tail -f error.log 复现请求看实时报错 → grep -C 5 挖上下文 → 如果是偶发问题,用 awk 统计错误的时间分布规律。这个顺序能解决大部分线上问题。
文件、权限与磁盘
服务器上另一类高频问题是权限和空间。看懂 ls -l 的输出是第一步:
ls -l app.js
# -rw-r--r-- 1 deploy admin 4096 Aug 6 10:00 app.js
开头十位是权限:第 1 位是文件类型(- 文件、d 目录),后九位分三组——属主、属组、其他人,每组 rwx 分别代表读、写、执行。上面的 rw-r--r-- 表示属主可读写,其他人只读。改权限:
chmod +x deploy.sh # 给脚本加执行权限
chmod 600 ~/.ssh/id_rsa # 私钥只允许属主读写(SSH 强制要求)
数字模式里 4=读、2=写、1=执行,600 就是属主 4+2、其他全 0。服务起不来、报 Permission denied 时,先 ls -l 看看权限和属主对不对——尤其是以 root 身份拷了文件、却用普通用户跑服务的场景。
磁盘排查两个命令:
du -sh /var/log/* | sort -rh | head # 哪个日志目录最占空间
find /var/log -name "*.log" -mtime +7 -delete # 删除 7 天前的日志
du 定位“谁吃掉了磁盘”,find 负责清理。带 -delete 的命令先在测试目录里跑一遍再上生产。
后台运行与环境变量
本地开发时 Ctrl+C 关掉程序很自然,但服务器上你关掉 SSH 窗口,前台进程也会被杀掉。让程序在后台常驻的入门写法:
nohup node server.js > app.log 2>&1 &
拆解一下:nohup 让进程忽略挂断信号(SSH 断开不死),> app.log 2>&1 把标准输出和标准错误都写进日志文件,最后的 & 放到后台运行。这只是入门方案——生产环境应该用 systemd 或 PM2 这类进程管理器,它们能在程序崩溃后自动重启,nohup 不会。
环境变量是配置注入的标准方式,密钥、数据库地址都不该写死在代码里:
export DATABASE_URL="postgres://localhost:5432/shop" # 设置(仅当前终端有效)
echo $DATABASE_URL # 查看
env | grep DATABASE # 列出相关变量
临时对单个命令生效可以写在命令前面:NODE_ENV=production node server.js。要永久生效就写进 ~/.bashrc(或 zsh 的 ~/.zshrc),改完执行 source ~/.bashrc 立即加载。
vim 保命操作
在服务器上改配置只能用终端编辑器,vim 几乎每台机器都有。你不需要精通,只需要保命四招:
vim app.conf
- 按
i进入编辑模式(左下角出现-- INSERT --),这时才能打字 - 按
Esc退回普通模式 - 普通模式下输入
:wq回车:保存并退出 - 普通模式下输入
:q!回车:不保存强制退出(改错了就用这招)
再加两个实用的:普通模式下按 G 跳文件末尾、gg 回首行,/关键词 回车搜索。记住黄金法则:任何时候慌了就连按 Esc,然后 :q! 全身而退。
SSH 与文件传输
SSH:远程登录的标准姿势。
ssh user@192.168.1.100 # 密码登录
ssh -p 2222 user@host # 非默认端口
生产环境应该用密钥登录:本地 ssh-keygen 生成密钥对,把公钥(~/.ssh/id_rsa.pub 的内容)追加到服务器的 ~/.ssh/authorized_keys,之后免密登录。记得把服务器的密码登录关掉(/etc/ssh/sshd_config 里 PasswordAuthentication no),这是最基本的加固。
scp 与 rsync:传文件。
scp app.tar.gz user@host:/opt/apps/ # 本地传到服务器
scp user@host:/var/log/app.log ./ # 从服务器拉回来
rsync -avz --progress dist/ user@host:/var/www/ # 同步整个目录
rsync 比 scp 聪明:-a 保留权限和时间戳、-v 显示过程、-z 压缩传输,而且只传有变化的文件,中断后重跑能续传。部署静态资源、备份日志,都用 rsync。
管道与重定向:命令行真正的超能力
前面反复出现的 | 和 >,才是命令行区别于图形界面的本质。|(管道)把前一个命令的输出交给后一个命令当输入,> 把输出写进文件(>> 是追加)。这意味着每个命令只需做好一件事,靠组合就能完成复杂任务:
history | grep ssh # 找以前敲过的 ssh 命令
tail -n 1000 app.log | grep ERROR | wc -l # 最近 1000 行里有多少错误
ps aux | grep node | grep -v grep | awk '{print $2}' # 只取 node 进程的 PID
最后一条里的 grep -v grep 是个经典细节:-v 反向过滤,把 grep 自己的进程从结果里剔除。当你发现自己在图形界面上反复点来点去做机械操作时,停下来想想——那件事多半能用一行管道命令完成。
顺带一提 Ctrl+R:在终端里按下它可以反向搜索历史命令,比你一遍遍按上箭头翻找快十倍,是命令行老手使用频率最高的快捷键之一。
再补一个长任务保命技巧:tmux。在服务器上跑耗时操作(数据迁移、大文件压缩)时,如果 SSH 断了,前台任务就完了。tmux 创建一个独立于 SSH 连接的会话:tmux 进入会话后正常跑命令,按 Ctrl+B 再按 D 脱离会话,任务在后台继续;下次登录用 tmux attach 回到原来的会话,屏幕上的内容分毫未动。
常见误区
- 误区一:上来就
kill -9。 强杀会跳过清理逻辑,可能导致数据损坏。先礼貌kill,等几秒不行再升级。 - 误区二:看到
used内存高就以为内存泄漏。 Linux 会把空闲内存用作磁盘缓存,判断内存压力要看free -h里的available列。 - 误区三:只看报错那一行日志。 错误的根因几乎总在上下文里,养成
grep -C 5的习惯。 - 误区四:在生产服务器上边查边学。 把本篇命令在本地练到形成肌肉记忆再去碰生产;生产上敲命令前多想一秒,尤其是带
rm、kill、重定向>的。 - 误区五:什么都用
sudo。 遇到权限问题就sudo一把梭,结果文件属主全变成 root,普通用户的服务再也读写不了,制造出新问题。正确做法是先ls -l看清属主和权限,用chown/chmod精准修复,而不是用sudo绕过。
小结
后端工程师的 Linux 日常可以浓缩为:top 看大局,ps/ss/lsof 管进程和端口,tail -f + grep -C + awk 三件套排查日志,ls -l/chmod/du/find 搞定权限与磁盘,nohup 和环境变量管住进程与配置,vim 会 i/Esc/:wq/:q! 四招保命,ssh 登录、rsync 传文件。命令不多,但每个都要练熟——线上故障时你的手速就是止损速度。
至此,你已经有了路线图(第 1 篇)、看透了网络(第 2 篇)、握住了日常武器(本篇)。下一篇我们深入代码运行的机器内部,以 Node.js 为例吃透语言运行时——为什么你的异步代码是那样的执行顺序,事件循环到底在循环什么。
系列导航:上一篇《网络基础抓包级理解:HTTP、TCP/IP 与 DNS》(/content/backend-expert-02-network) · 下一篇《吃透语言运行时:以 Node.js 事件循环为例》(/content/backend-expert-04-nodejs-runtime)
