ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

Linux命令实战:场景化排查链路与常用工具详解

Linux命令实战:场景化排查链路与常用工具详解 上周帮一个朋友排查服务器问题他指着终端问我明明照着网上的教程敲了 top为什么显示的东西跟教程完全不一样我一看原来他系统里的 top 被某个优化脚本用 alias 换掉了。这个场景我见过太多次。很多人学 Linux 常见命令把参数表背得滚瓜烂熟结果一到真实环境连“该先敲哪条命令”都判断不了。真正有价值的不是记住一百条命令而是掌握一套排查链路文件找不到先找哪条、负载高先看什么、端口不通先测哪一步。这篇文章我想按场景把最常用的 Linux 命令拆开讲一遍包括我踩过的坑和现在还在用的习惯。适合刚接触 Linux 的新手也适合那些零零散散用过很多命令、却总在关键时刻卡壳的运维和开发。1. 先建立正确的命令学习框架按场景而不是按清单1.1 先分清“查询类命令”和“变更类命令”我见过不少新手把 Linux 命令当成单词表背今天记十个明天记十个遇到具体问题依然无从下手。根子在于没有给命令分类。所有命令按用途其实只有两大类一类是查询信息只读不改另一类是做变更一次失误可能造成不可逆后果。查询类命令的代表是 ls、df、du、ps、ss、grep、cat它们的作用是回答“现在到底是什么状态”。变更类命令的代表是 rm、mv、cp、mkfs、useradd它们的作用是“把系统改成另一个状态”。学习时我建议先把查询类命令练熟因为绝大多数排查场景第一步都是看清楚现状变更类命令则要养成交叉确认的习惯尤其指向生产环境时先想三秒再回车。比如最常见的文件查找很多人上来就 find / -name xxx结果因为权限问题刷出一屏 Permission denied。正确做法是先用 df -h 看磁盘是不是满了再用 du -sh /home/* 定位哪个目录胀得最快最后才用 find 精确定位文件位置。这就是场景化思维不是背命令而是知道在哪个环节该用哪条命令。1.2 记不住参数时别硬记先看 help很多人痛苦于命令参数太多。我的习惯是先跑命令 --help或man 命令把最常用的几个参数用起来等遇到新需求再去查。别指望一次性记全命令的常用参数就那么几个真正高频的甚至不到 20%。比如 tar 命令你只需要记住两个组合打包tar -czvf file.tar.gz /path解包tar -xzvf file.tar.gz用多了自然就理解 -c 是创建、-x 是解压、-z 是 gzip 压缩、-v 是显示过程、-f 是文件名。这套逻辑通了换成 -jbzip2也只是改一个字母的事。等需要排除文件时再查--exclude参数查一次就记住了。提示凡是涉及删除、覆盖、格式化的命令回车前一定先看一眼当前路径和参数。我在生产环境看到过的重大事故几乎全是“我以为路径对”造成的。2. 文件与目录操作最容易混淆和翻车的几个点2.1 ls -l 输出里那串权限位到底怎么看ls -l 是大多数人接触的第一条命令但普及一下输出格式还是有必要的。以-rw-r--r--为例第一个字符表示文件类型-是普通文件d是目录l是符号链接。后面九个字符分三组每组三个分别对应属主、属组、其他用户的权限。rwx 分别代表读、写、执行每一位都有数字映射r4w2x1。所以 rwx 相加等于 7rw- 等于 6r-- 等于 4。这就是为什么大家都在说 644、755、600本质是三个权限组的数字和。实际排错时权限位最常见的坑是“明明有文件却读不了”。遇到这种情况不要先怀疑文件损坏先 ls -l 看属主和权限再id看当前用户属于哪些组。很多时候只是文件属主不对一条chown user:group file就解决了。2.2 find 的 -exec 和 -delete 是高危组合find 本身是查询命令但一旦配上 -exec 或 -delete 就变成了变更命令。典型的翻车例子find / -name *.log -exec rm {} \;这条命令的本意是删除所有日志文件但万一路径写错比如把 / 写成了 /etc后果极其严重。我的习惯是所有带删除动作的 find 都分成两步走第一步先用不带动作的 find 把结果列出来亲眼确认路径和文件范围没问题第二步再执行删除。如果你实在需要一条命令搞定也可以用-ok代替-exec它会在每个文件执行前询问一次虽然繁琐但安全。还有一个细节find 的-name匹配的是文件名不是完整路径想按完整路径匹配要用-path。查找按时间或大小过滤用-mtime修改天数和-size文件大小例如find /data -type f -size 100M可以快速找到超过 100MB 的大文件。2.3 tar 打包解包路径和排除项才容易翻车tar 参数本身不难真正容易翻车的是路径处理。当你执行tar -czvf bak.tar.gz /home/user时解包后得到的是一个完整的 /home/user 路径如果你希望解包后去掉前面的目录层级需要进入目标目录再打包cd /home/user tar -czvf /backup/bak.tar.gz .这样解包时文件会相对当前目录展开。另一个常用场景是备份时排除某个目录比如排掉 node_modulestar -czvf project.tar.gz --excludenode_modules /data/project注意 exclude 参数必须放在源路径前面否则不生效。顺手再提一个容易混淆的点如果你看到 .tar.gz 就认为必须用 z其实 tar 有自动识别压缩格式的能力现代版本执行tar -xvf file.tar.gz也能解开但指定参数更保险。2.4 cp、mv、rm 的三个日常坑先说 cp。复制目录必须加 -r否则报错“omitting directory”这是新手高频报错。如果需要保留权限和时间戳用cp -a。mv 有两个容易被忽略的场景跨文件系统移动时mv 会变成“复制到目标 删除源”大目录会慢本质上不是普通改名另一个是 mv 目标位置已有同名文件时默认直接覆盖加上-b可以生成备份文件。rm 是所有人必须敬畏的命令。rm -rf *在错误的目录下执行是什么后果行业里已经流传了太多事故。我的建议是交互式删除用rm -i危险目录用rm -i -r并且在脚本里永远用变量保护路径。比如写成rm -rf ${TARGET_DIR}/变量为空时至少不会把根目录干穿。3. 文本处理三剑客grep、sed、awk 的实战组合3.1 grep 过滤时最容易被引号坑grep 的常见用法是过滤日志和排查进程。比如查 Java 进程ps aux | grep java但这条命令经常会把 grep 自己那条进程也列出来因为命令行里包含了“java”这个关键字。很多人因此学会了grep -v grep这没错但更干净的做法是用pgrep -f java或者直接ps aux | grep [j]ava。正则表达式是 grep 的重点。简单理解不加 -E 时用基础正则^匹配开头$匹配结尾.匹配任意单字符*表示重复前一个字符。加 -E 后可以使用扩展正则比如一个或多个、?零个或一个、|或。实际排错时建议把要匹配的内容用单引号包起来避免 shell 先解释掉特殊字符。比如grep 2024-06-01 12:.*ERROR /var/log/app.log这里的星号和点号都应该传给 grep而不是被 shell 当通配符展开。如果要在多个文件里搜加上 -r 递归加上 -n 显示行号。时间紧的时候我会直接用grep -n --colorauto颜色高亮能省很多眼力。3.2 sed 的增删改查三分钟记住核心语法sed 是个流编辑器很多人一听到就头大其实日常高频就三件事打印、替换、删除。打印第 2 到第 5 行sed -n 2,5p /etc/passwd不加 -n 会把所有行都输出一遍加 -n 才只输出被匹配的行这是新手最容易忽略的点。替换字符串是最常用的场景比如把配置文件里的端口从 8080 改成 9090sed -i s/8080/9090/g conf.properties-i 表示直接修改文件强烈建议写-i.bak这样原文件会备份成 conf.properties.bak改坏了还能还原。删除匹配某个模式的行sed -i /^#/d conf.properties这条命令会把所有以 # 开头的注释行删掉。sed 的应用面很广但日常记住这三组基本够用。遇到复杂场景先做一次不带 -i 的试探确认输出符合预期再落地。3.3 awk 按列处理-F 分隔符才是精髓awk 的核心思想是“按列处理”。默认按空白字符拆分第一列是$1第二列是$2整行是$0。比如查看哪些用户使用 bash 登录可以从 /etc/passwd 中筛选awk -F: $7 /bin/bash {print $1} /etc/passwd-F: 表示用冒号作为分隔符。awk 的语法其实是一套小型语言包含条件、循环、统计但日常使用最多的是“条件 print”。比如统计某个日志中 ERROR 出现的次数awk /ERROR/ {count} END {print count} app.log这里的 END 表示最后执行一次count 是 awk 内部的变量。有了 grep、sed、awk 三个工具很多日志分析不再需要打开编辑器手工处理。组合使用例子先 grep 出关键字再 awk 取特定列再 sort 和 uniq -c 统计数量这是文本分析最常见的一条链条。4. 系统监控命令top、ps、free、history 的进阶解读4.1 top 界面怎么看别被 wa 和 si 吓到top 是 Linux 运维的“仪表盘”但新手经常被一堆数字淹没。我最常看的是几块第一行 load average1 分钟、5 分钟、15 分钟平均负载第二行进程数和运行数第三行 CPU 状态里的 us用户态、sy系统态、wa等待 IO以及内存行的可用量。很多人在负载高时第一反应是“CPU 爆了”其实 wa 高往往意味着磁盘 IO 才是瓶颈比如有人在大量写日志或者做全量备份CPU 反而闲着。遇到这种情况应该用 iostat 或 iotop 进一步确认而不是盲目加 CPU。top 里按 P 按 CPU 排序按 M 按内存排序。非交互式查看可以用top -bn1这条命令只输出一次完整状态然后退出适合写进脚本。“top 命令被改变”也是真实会遇到的坑。如果你发现 top 的输出格式或行为明显不对先检查是不是被 alias 了type top alias top如果确认被 alias 指向了别的程序用unalias top解除然后再检查 PATH 里有没有可疑目录。类似手段也适用于所有基础命令养成有事查 alias 的习惯能少走很多弯路。4.2 ps aux 和 ps -ef 的区别查看进程ps aux和ps -ef都能用区别在于输出格式。ps aux的列是 USER、PID、%CPU、%MEM、VSZ、RSS、STAT、START、TIME、COMMAND方便看资源占用ps -ef的列是 UID、PID、PPID、C、STIME、TTY、TIME、CMD方便看父子进程关系。日常排查我习惯用ps aux再结合 awk 按内存或 CPU 排序。比如查看内存占用最高的前五个进程ps aux --sort-%mem | head -5进程状态列 STAT 也要会看R 是运行S 是睡眠D 是不可中断的 IO 等待Z 是僵尸进程。看到 Z 不用慌僵尸进程是子进程结束后父进程没回收一般不影响系统运行但数量多了需要排查父进程。D 状态持续太久才更值得警惕通常和存储设备有关。4.3 free、df、du 联手定位资源瓶颈free 是看内存的最常用的是free -h。Linux 的内存管理经常让新人大惑不解明明程序没占多少内存used 却很高。其实那一大块是 buff/cache属于可回收的缓存真到内存紧张时系统会释放。判断内存够不够重点看 available 列而不是 used 列。内存不够时常见现象是 swap 被大量使用可以用free里的 Swap 行确认。df 看磁盘分区使用率df -h按人类可读方式显示。还有一个容易被忽略的是 inode 耗尽df -i显示 inode 使用率就算磁盘容量还有剩余inode 用完了同样无法新建文件常见于大量小文件堆积的目录。定位哪个目录文件多用 dudu -sh /var/log/* du -sh /home/* 2/dev/null直接列出各目录占用一层层往下找很快就能锁定吃磁盘的元凶。4.4 history 的隐藏功能history 不只是敲过的命令记录。它有很多实用小技巧history n只看最近 n 条!!执行上一条命令!$取上一条命令的最后一个参数!ps执行最近一条以 ps 开头的命令。记录时间戳可以设置 HISTTIMEFORMATexport HISTTIMEFORMAT%F %T 在 .bashrc 里加上这行以后每条历史命令都会显示执行时间排查问题时特别有用。如果因为安全需要想临时不让某条命令进历史可以在命令前加空格需要设置 HISTCONTROLignorespace。清空当前会话历史用history -c清空历史文件用history -w后手动清理文件。这些都是细节但细节往往决定排查效率。5. 网络排查命令从 ping 到 curl 的完整链路5.1 ping 不通不一定是网络故障网络排查第一条命令通常是 ping。但 ping 用的是 ICMP 协议很多生产环境出于安全考虑会禁掉 ICMP所以 ping 不通不代表端口不通。正确步骤是分层检查先ping 127.0.0.1确认本机协议栈正常再 ping 网关确认链路和二层通不通再 ping 目标 IP 确认三层可达性最后用 telnet 或 nc 测目标端口确认四层服务正常。ping 加-c可以指定次数比如ping -c 4 8.8.8.8不要习惯性 CtrlC 终止。一个常见的误判服务器能通外网但域名解析不了这种时候 ping 域名不通、ping IP 却通问题就出在 DNS 上应该查/etc/resolv.conf和dig。5.2 telnet 测端口为什么不过时telnet 被很多文章说成“老古董”但它在排查端口连通性时依然好用。命令极简telnet 192.168.1.10 3306如果端口通界面上会出现 Connected 字样如果不通会一直卡住最后超时或者直接提示 Connection refused。测试完成后按 Ctrl] 进入 telnet 提示符再输 quit 退出很多人不知道这点以为界面卡死了。如果服务器没装 telnet可以用nc -zv 192.168.1.10 3306达到同样的效果。再扩展一下如果你需要连续测试一批主机和端口可以写个 for 循环配合 nc。像交换机查光模块状态H3C 设备会用display transceiver diagnosis看光衰和温度这类命令属于厂商设备而非 Linux 系统命令但排查链路的思想是相通的先测链路通不通再测端口收发光是否正常。5.3 ss 和 netstat看端口占用和连接状态端口被占用是开发环境最常见的报错之一。查看某个端口有没有被监听ss -lntp | grep 8080 netstat -tlnp 2/dev/null | grep 8080两个命令都可以。ss 性能更好输出也清晰netstat 老牌但在很多新系统里不再默认安装。-t 是 TCP-l 是监听状态-n 是数字显示端口-p 是显示进程信息。如果你想知道一个端口为什么 TIME_WAIT 堆积netstat -an | awk /TIME_WAIT/ {print $6} | sort | uniq -c可以统计状态数量连接状态是理解网络问题的重要入口。如果 ss/netstat 都没有可以用cat /proc/net/tcp硬核查看但可读性较差新手不建议。日常先把 ss 学会就够用了。5.4 curl 做接口自测curl 是排查 HTTP 接口问题的利器。最基本的用法curl -I https://example.com curl -v https://example.com/api/health-I 只返回响应头-v 显示详细请求和响应过程包括 DNS 解析、TCP 连接、TLS 握手、HTTP 状态码。接口如果返回 503基本可以判断是服务端应用问题而不是网络问题。测试 POST 接口curl -X POST -H Content-Type: application/json -d {name:test} http://127.0.0.1:8080/api/user如果担心响应太长加-w \n%{http_code}\n直接输出状态码。curl 的用法远不止这些但日常自测接口、看响应头、模拟请求记住这几个参数完全够用。6. 用户权限与软件安装命令背后的权限模型6.1 useradd 忘加 -m 的后果新建用户是 Linux 运维的基本操作。很多新手执行 useradd test 后发现一个诡异现象用户建好了但 /home 下没有 test 目录。原因很简单useradd 在绝大多数发行版上默认不创建家目录需要显式加 -museradd -m -s /bin/bash test-s 指定登录 shell建议设成 /bin/bash否则默认可能是 sh交互体验很别扭。创建完用户后顺手设置密码passwd test删除用户时想连带删掉家目录和邮件池用userdel -r test。查看用户信息可以看 /etc/passwd 文件getent passwd test一行里的七个字段依次是用户名、密码占位、UID、GID、注释、家目录、登录 shell。理解了这些字段用户相关问题的排查思路就清晰了。6.2 chmod 数字权限计算chmod 是修改文件权限的命令数字模式最常见。前面说过 r4、w2、x1那么 7 就是全权限5 就是读加执行。为什么普通文件推荐 644目录推荐 755因为目录如果没有执行权限就无法进入所以目录至少需要 5如果目录要让其他用户可写就需要 7。实际例子chmod 755 /data/www chmod 644 /data/www/index.html修改目录下所有文件需要加 -Rchmod -R 755 /data/www。但这里有个小坑-R 对所有文件统一设置权限会把那些本来不该有执行权限的普通文件也加上了 x存在安全隐患。更精细的做法是用find /data/www -type d -exec chmod 755 {} \;和find /data/www -type f -exec chmod 644 {} \;分开设置。修改属主和属组用 chownchown -R www:www /data/www用户和组之间用冒号分隔这点经常有人写错。6.3 sudo 与 su 的区别sudo 和 su 都涉及权限提升但用法完全不同。su 是切换用户su - user可以切换成另一个用户并获得其完整环境sudo 是临时用某个权限执行单条命令不切换身份。生产环境我更推荐 sudo因为它有审计日志可以追溯到具体是谁执行了命令。配置 sudo 权限用 visudo。常见的授权行user ALL(ALL) NOPASSWD: /bin/systemctl restart nginx这条表示 user 可以在所有主机上以任意用户身份执行 systemctl restart nginx 而不用输密码。如果没有 NOPASSWD使用 sudo 时会要求输入自己的密码注意不是要求输入 root 的密码。如果一条 sudo 命令卡住不动多半是在等待输入密码但终端没显示输入框检查一下是不是 TTY 问题。6.4 软件源的 update 与 upgradeDebian/Ubuntu 系用 apt 安装软件时新手最容易混淆 update 和 upgrade。update 是更新软件源索引告诉系统有哪些新版本可装upgrade 才是真正升级已安装的包。所以换源之后必须先 update 再 upgrade。换源本质上就是修改/etc/apt/sources.list或/etc/apt/sources.list.d/下的文件。以 Debian 为例系统代号为 trixie 时直接把源地址 http://deb.debian.org 改成镜像站地址写完执行apt update验证。如果提示缺少公钥用apt-key相关方式导入但新版系统更推荐复制 keyring 文件。RHEL/CentOS 系则用 yum 或 dnf报错“没有 rpm 命令”时不用惊讶rpm 是底层包工具通常不会单独出现在 PATH 里直接用 yum install 即可。注意不管用 apt 还是 yum升级生产环境的包之前先确认它是否影响正在运行的服务。依赖被自动升级导致的服务异常是我见过最多的一类“升级事故”。7. Shell 脚本与效率工具管道、位置参数、vim 与 git7.1 管道和重定向的三个易错场景管道符|是把前一条命令的标准输出接到后一条命令的标准输入但很多人忽略了“标准输出”这个限定。如果程序把错误信息写到 stderr管道是接不到的表现出来就是管道后面没数据。此时需要先重定向find /data -name *.log 2/dev/null | head -52/dev/null 把错误信息丢弃标准输出才能正常进管道。有时候你想同时看到输出并存档用 teecommand | tee output.log这样屏幕还会显示文件里也有记录。还有一个常见陷阱管道和重定向的优先级。echo hello file | wc -l这一行里重定向和管道同时存在时行为不符合直觉建议不要混写拆成两行更清晰。7.2 shift 是怎么吞掉参数以及 $ 与 $* 的区别写脚本时位置参数是$1、$2、$3这样一路排下去的。shift的作用是让每个位置参数向左移动一位$2变成$1$3变成$2。最常见的用法是写一个带命令行参数的脚本while [ $# -gt 0 ]; do echo 处理参数: $1 shift done每轮循环取走$1然后 shift 把后面的参数顶上来直到所有参数处理完。这里$#表示参数个数。还有一个经典区别$和$*。不加双引号时两者行为相似一旦加上双引号$会把每个参数当成独立的个体而$*会把所有参数合并成一个字符串。写脚本遍历参数时请用$否则参数里带空格就会裂开。7.3 xargs 并行执行任务xargs 可以把前一条命令的输出变成后一条命令的参数。一个实用场景是批量清理日志find /var/log -name *.log -mtime 7 | xargs rm -f但更值得说的是并行能力比如你有 8 个 URL 要并发探测seq 1 8 | xargs -I {} -P 4 echo 任务 {}-P 4 表示同时跑 4 个进程。这个技巧在批量压测、批量拉取数据、批量检测端口时能大幅缩短时间。需要注意xargs 默认遇到文件名字里有空格时会有问题建议配合-0参数和find -print0使用以空字符作为分隔符。7.4 vim 三种模式的实际用法vim 是绕不开的文本编辑工具。新手第一反应是“连退出都不会”所以至少要掌握三个东西按 i 进入插入模式开始打字按 Esc 回到普通模式输入:wq保存退出。如果只是想退出不保存用:q!。更进一步普通模式下的几个操作非常提效dd删除当前行yy复制当前行p粘贴u撤销。搜索用/关键字按 n 跳下一个。在写代码或改配置时想跳转行号输入:行号。这些够应付绝大多数场景。vim 的可配置性很强建议刚开始不要折腾插件先把原生操作练到不打断思路再考虑扩展。7.5 git 日常命令链git 是开发必用的版本管理工具但本文只讲日常命令链。核心流程是 status 查看变更diff 查看具体改动add 暂存commit 提交push 推送git status git diff git add . git commit -m fix: 修复登录超时问题 git push origin main回滚代码也是常见操作git reset --hard HEAD~1会放弃最近一次提交git revert HEAD则生成一个反向提交。生产环境我强烈建议用 revert 而不是 reset因为 reset 会改写历史多人协作下容易造成混乱。查看提交历史用git log --oneline --graphgit 不需要把所有命令都学会掌握这套循环就能开始日常开发遇到解决不了的冲突再针对性搜索。7.6 bash -x 调试脚本脚本报错是最痛苦的时候之一但 bash 自带了调试利器。执行脚本时加 -xbash -x script.sh它会逐行展开命令并显示实际执行内容行首用标记。这样你能清楚看到每一步到底执行了什么、变量被展开成了什么值。如果想在脚本内部只看某一段的调试信息可以临时打开set -x # 要调试的片段 set x还有一个常用保护是set -e它表示脚本中任何一条命令返回非零退出码就立即停止避免错误累积到最后才爆发。新写的脚本顶部建议加上set -e但要注意它也有副作用有些命令正常执行会返回非零比如 grep 没匹配到内容这时需要临时用if语句包裹。我个人在实际操作中最深的体会是Linux 命令学得好不好不是看你背了多少参数而是看遇到问题时头脑里有没有一张“排查地图”。文件相关想 find、du、df文本处理想 grep、sed、awk系统状态想 top、ps、free网络连通想 ping、telnet、ss、curl。把这几个场景串起来很多故障不用百度也能一步步定位。最后再分享一个小技巧每学一条新命令不要停在“看过”至少想一个自己工作里会用到的场景然后在测试环境练一次。命令这个事手感比记忆力可靠得多。
返回列表