
玩命令行这事儿说起来挺有意思。我见过不少朋友ls、cd、grep用得贼溜单个命令敲得飞起可真要处理点复杂活儿就开始一段一段地手忙脚乱。其实很多时候并不是你不会某个命令而是没把命令“串”起来用。这就像炒菜盐、酱油、醋都是好东西但单放一种永远成不了鱼香肉丝得靠组合、靠火候。Linux 命令也一样真正的效率提升来自于那些不起眼的“组合拳”。这篇东西我的目标很明确不聊那些你一搜就能搜到的命令大全专门聊聊“怎么把命令组合起来”。我会把我日常干活儿里最常用、最提效的几种组合玩法拆开揉碎了讲包括背后的原理、我踩过的坑以及一些能直接抄作业的写法。不管你是刚接触 Linux 的萌新还是干了好几年的运维老手相信都能从中抠出点东西来。1. 组合之前先搞懂这三件事命令组合不是什么高深莫测的黑魔法它建立在几个非常基础的能力之上。咱们先把地基打牢后面玩起来才不虚。1.1 管道符把命令“接”起来的水管拿管道符|来说它是 Linux 组合命令的灵魂。它的作用简单粗暴把左边命令的输出当作右边命令的输入。你可以把它理解成一根水管把两个程序连接起来让数据像水流一样从左边流到右边。没有管道的时候你要先跑一条命令把结果存到一个临时文件里再跑第二条命令去读这个文件最后还得手动清理。有了管道就是命令A | 命令B一行事儿中间省掉的不仅是敲键盘的时间更是那份“管理临时文件”的操心劲儿。打个比方你想看系统里到底跑了多少跟 nginx 相关的进程。没管道的话得先ps -ef /tmp/ps.txt然后grep nginx /tmp/ps.txt看完还得rm /tmp/ps.txt。有管道的话一行ps -ef | grep nginx直接搞定。简洁、优雅还不会弄脏你的磁盘。1.2 重定向把数据“送”到该去的地方重定向主要靠三个符号、和。是把命令的输出“覆盖”写进一个文件则是“追加”到文件末尾是把文件内容作为命令的输入。管道和重定向的区别在于管道传递的是“流”是内存中的数据交接重定向打交道的是“文件”是把数据落到磁盘上。二者经常会配合使用比如你希望把处理好的结果保存下来就可以在管道链条的末端加上 result.txt。注意这个符号有点“暴力”它会二话不说把原文件内容清空再写入。如果原文件很重要建议用追加或者先备份。1.3 命令替换让命令“嵌套”起来命令替换的语法是$(命令)或反引号 。它允许你在一条命令里嵌入另一条命令的执行结果。这就像俄罗斯套娃一个命令的结果直接变成另一个命令的参数。比如你想看看今天日志文件到底新增了多少行可以先date %F拿到今天的日期然后cat access.log | grep $(date %F) | wc -l。这里$(date %F)会先算出今天的日期再把日期当作 grep 的搜索模式。这比起你自己先去查日期再手动输进去不知道高到哪里去了。有了管道、重定向、命令替换这三板斧你就有了玩转组合命令的底气。咱们接下来进入正题看看实操里这些底层的“水”和“管子”能拼出什么花样。2. 日常高频组合实战这里我不会给你整那些花架子全部是我自己在排查问题、统计数据、处理文本时反复用了无数遍的组合。每一个都会拆开讲保证你看完能直接用。2.1 定位与过滤大海捞针的“精确定位术”大多数时候我们面对的不是命令不够用而是输出太多看不过来。这时候“生成输出 - 过滤关键词 - 高亮展示 - 定位上下文”这条链路就是你最需要的。场景一看日志排出最耗时的接口我们后端服务打印的 access log 里最后一段数字是耗时单位毫秒。你想知道哪些接口最慢排除掉耗时小于 500 毫秒的然后按耗时从大到小排最后把前三名揪出来标准写法是cat access.log | awk {print $7, $NF} | sort -k2 -rn | head -n 3这条命令有点长拆开看都是老朋友awk {print $7, $NF}只挑出第 7 列一般是接口路径和最后一列$NF 代表最后一列也就是耗时。这一步是“瘦身”把日志里无关紧要的 IP、时间戳全甩掉。sort -k2 -rn-k2指定用第二列排序-r是降序从大到小-n是按数值类型排而不是按字典顺序。这个-n很关键不然 100 会排在 20 前面你就得哭。head -n 3只要前三行也就是最慢的三个接口。这套组合是我用得最频繁的没有之一。它就是典型的“生成 - 过滤 - 排序 - 取前 N 条”流水线思维。场景二找进程 PID 并干掉它这可以说是 Linux 日常的“家常菜”了。你发现服务器负载很高一查是那个可恶的php-cgi进程干的打算把它全杀了。千万别用pkill -9 php-cgi这么粗鲁的方式万一误杀了一批还在正常处理请求的进程呢先看清楚再动手ps -ef | grep php-cgi | grep -v grep | awk {print $2} | xargs kill拆解一下ps -ef | grep php-cgi先找出所有包含 php-cgi 的行。grep -v grep注意这步因为你刚才那个 grep 命令本身也是一个进程也会被 ps 列出来如果不把它过滤掉你会看到一个“奇怪的”php-cgi 进程。这是无数新手踩过的坑必须过滤掉自己。awk {print $2}筛选出第二列也就是 PID。xargs kill把上一段管道传过来的 PID 列表逐一作为参数交给 kill 去执行。小窍门如果你特别确定要强杀可以在 kill 后面加-9但在生产环境里我强烈建议先用不带-9的方式发一个 SIGTERM 信号给进程一个善后和清理的机会。只有它实在赖着不走的时候再考虑 SIGKILL。2.2 统计与分析把数据“卷”出价值这个板块专门送给做运维和数据分析的朋友。日志在手天下我有前提是你得会“榨”出有价值的信息。场景一统计 NGINX 日志里的独立 IP 数面试和日常工作都常考的一道题统计一天里有多少个不同的 IP 访问过你的网站awk {print $1} access.log | sort -u | wc -lawk把第一列IP抠出来sort -u排序并去掉重复项wc -l数行数。要统计 Top 10 访问来源 IP则是awk {print $1} access.log | sort | uniq -c | sort -rn | head -n 10这里不再是sort -u而是用uniq -c来“数次数”然后按次数倒序。注意uniq -c统计的是相邻重复行所以必须先sort这顺序错一步结果就是错的。场景二统计每个 HTTP 状态码出现的次数想快速了解网站的健康状况看状态码分布是最直观的awk {print $9} access.log | sort | uniq -c | sort -rn假设 $9 是状态码列这条命令立刻告诉你 200 有多少、404 有多少、500 有多少。如果 500 一大片恭喜你该去翻后端日志了。提示不同日志格式的列位置不一样用这条命令前先随意awk {print $0} access.log | head -n 2看一眼列结构。另外sort -rn这个组合里的-n千万别省不然“9”会跑到“100”后面数字排序会变成字典序排整个统计就没意义了。2.3 网络排查快速定位通不通、卡在哪网络问题特别是那种“用户说访问慢但又不是完全不通”的玄学问题特别消耗精力。Linux 里跟网络相关的命令不少但组合着用能帮你更快定位到“卡在哪个环节”。场景一检查端口通不通这是最基础、也最常被问到的。热词里也有“telnet 命令怎么用”和“telnet ip 端口命令怎么看通不通”。实际上在大多数现代发行版里telnet 可能都没装。我通常用ncnetcat来干这事儿nc -zv -w 5 192.168.1.100 3306-z表示“只扫描看端口是否开放不发送数据”。-v是 verbose把结果打出来。-w 5意思是超时时间 5 秒避免因为目标主机 or 网络问题让你在那儿干等半天。如果输出了类似Connection to 192.168.1.100 3306 port [tcp/mysql] succeeded!说明端口通着。如果提示Connection refused说明端口没监听服务可能没起来。如果直接卡住直到超时那大概率是防火墙拦了或者 IP 根本不可达。这里nc和telnet起到的作用是一样的但nc用起来更干净还方便在脚本里做判断。场景二追踪路由找到卡顿点当你觉得网络“慢”用ping只能证明通不通看不出哪一跳慢。这时候用mtr -r -c 10 8.8.8.8mtr可以理解成traceroute和ping的结合体-r是 report 模式一次性输出所有数据-c 10是发 10 个包统计。它会显示从你本机到目标 IP 经过的每一跳路由以及每一跳的丢包率和延迟。如果发现某一跳丢包率特别高或者延迟剧增那问题大概率就在那一段链路上。这比单纯用ping或者traceroute要直观得多。心得现在的云服务器普遍都带安全组很多“端口不通”的问题其实不是机器上服务没起而是安全组、iptables 规则挡了。用nc测不通的时候先别急着怀疑服务先去控制台看看安全组策略能帮你省去好多无谓的折腾。3. 批量操作与自动化组合如果说上面那些是“单点突破”那这章就是“集团作战”。当你要处理一批文件、一堆服务器或者一堆进程时组合命令的威力才真正展现出来。3.1 循环与批处理用 for 循环搞定“海量”任务一个非常高频的需求清理服务器上 30 天前的日志文件。手动一个个删等你删完日志可能已经把磁盘塞满了。这里我推荐用循环加查找的组合。当然直接用find一行就能解决但我们来看看更灵活的“循环思路”。场景一清理过期日志for i in $(find /var/log/nginx -name *.log -mtime 30); do rm -f $i; done略微解释下这个脚本的逻辑$(find /var/log/nginx -name *.log -mtime 30)用命令替换把查找到的 30 天前的日志文件路径作为一个列表。for i in ...遍历这个列表把每一个文件路径赋给变量i。do rm -f $i; done循环体对每个变量做删除操作。当然你完全可以用一行更简洁的find /var/log/nginx -name *.log -mtime 30 -exec rm -f {} \;这两者本质是一样的。但for循环胜在“灵活”你可以想象成——找到了列表之后你想干点啥都行比如先压缩再删除或者边删除边echo打印日志甚至把这批文件scp到一个备份机器上循环比-exec更容易扩展。场景二批量压缩日志有时候我不想直接删想先压缩留档for i in $(find /var/log/nginx -name *.log -mtime 7); do tar -czf $i.tar.gz $i rm -f $i; done表示只有在前一条命令成功执行退出码为0后才执行后面的命令。这样能保证压缩成功之后再删源文件避免压缩失败文件却没了的惨案。这种做法我给它起了个名字叫“先打包、再归档、后清理”虽然土但在脚本自动化里特别踏实。3.2 文本处理“瑞士军刀”sed 与 awk 的组合很多朋友一看到sed和awk就头大觉得语法反人类。但它们是处理文本的“倚天剑屠龙刀”。我之前看到热搜词里有“sed 命令”也有“git 命令”。合理使用sed能极大地提升工作效率。下面聊几个既基础又高级的真实场景。场景一批量替换配置文件里的内容你的应用从测试环境搬到生产环境IP 变了。以前你可能用 vim 打开文件一个个找一个个改。如果这个配置分散在一百个文件里呢find ./conf/ -type f -name *.xml | xargs sed -i s/192.168.1.10/10.0.0.10/g这条命令用管道把find结果喂给xargs然后xargs把每个文件路径作为参数传给sed。sed -i是直接修改文件s/旧IP/新IP/g是全局替换。一次搞定一百个文件加个-i操作前一定记得先备份一下你的目标目录。注意sed -i是直接修改原文件的没有备份的话一失手成千古恨。稳妥的做法是先cp config.xml config.xml.bak或者干脆用sed -i.bak这样会自动生成带 .bak 后缀的备份文件再从容替换。场景二给日志文件按时间切片假设你的 Spring Boot 应用把日志都打到了一个app.log里现在你想把某个时间点之后的日志单独存下来分析。sed -n /2024-08-01 10:00:00/,$p app.log after_10am.log-n是“不打印所有行”/pattern/,$p的意思是“从匹配到这个模式的那一行开始一直到文件末尾$打印出来p”。这个组合在日志切片里非常常用能帮你快速定位到事故发生后的日志数据。场景三提取 git 提交记录里的邮箱这可以算是git和文本处理的结合。你作为一个项目负责人想统计团队里每个成员的提交次数git log --prettyformat:%ae | sort | uniq -c | sort -rngit log --prettyformat:%ae能只输出作者邮箱后面接上我们前面提到的sort | uniq -c | sort -rn流水线一个清晰的“代码贡献排行榜”就出来了。这就是跨命令组合的威力git 管输出sort 和 uniq 管分析。3.3 让命令“等一下”用 sleep 与循环做定时任务有时候你不想用 crontab 去写定时任务就想在当前终端里隔一阵子看一下某个服务的状态。你可以这样写while true; do uptime; sleep 2; done按下CtrlC之前它会每 2 秒刷新一次系统负载。这个组合看起来简单但在做压测或跑批处理任务的时候实时观察系统状态非常方便。你也可以把它写成“观测 20 次后自动停”for i in $(seq 1 20); do uptime; sleep 5; done拉长时间间隔配合uptime、free、df -h这些命令你就能在终端里自己搭一个简单版的“监控大盘”。4. 进程管理与服务状态排查这个板块的重点是回答“我的服务怎么挂了”以及“它到底在干嘛”。热词里那些 K8s、Docker 相关的命令咱们不聊太深但要说清楚如何用组合命令快速定位问题。4.1 找端口对应的进程最常见的排查场景是你知道某个端口比如 8080被占用了想看看是谁占的。很多人会说netstat -tunlp | grep 8080。这个组合本身没什么问题但“知其然更要知其所以然”。netstat -tunlp参数含义是-t显示 TCP、-u显示 UDP、-n以数字显示地址和端口、-l仅显示监听端口、-p显示 PID 和程序名。后面接grep 8080就能精确过滤。这比单独跑netstat然后在一堆输出里翻眼睛强太多了。如果你发现系统里没有netstat有些精简版系统只装ss命令那么用ss -tunlp | grep 8080效果类似而且ss命令本身更快、更现代。这也是组合命令的另一个妙用底层工具换了但你的“组合思维”不需要变。4.2 按 CPU 或内存排序找“元凶”服务器最近特别卡负载也高你想知道是哪个进程吃掉了资源。不用装那些重型监控工具靠系统自带的命令组合起来就能看ps aux --sort-%cpu | head -n 10这条命令打印出所有进程并按 CPU 占用率降序排列然后取前十。同理想看内存占用最大的是谁ps aux --sort-%mem | head -n 10如果觉得这种写法记不住也可以用古早一点的经典写法top -b -n 1 -o %CPU | head -n 20-b是批处理模式-n 1表示只跑一次-o %CPU指按 CPU 排序。这种适合在脚本里用因为top -b是文本输出可以被管道或重定向接住方便你导出或加入报警逻辑。4.3 docker 与 containerd 常见排查组合有虚拟机有容器排查链路就更长了。我以前遇到容器起不来的问题会按下面这个顺序查docker ps -a | grep my_service docker logs --tail 200 -f my_service docker inspect my_service | jq .[0].State.Statusdocker ps -a看容器当前状态Exited 还是 Runningdocker logs看应用日志docker inspect是查看容器的详细配置。这三条命令组合起来基本能覆盖“容器没起来”这件事的 90% 排查路径。如果你使用的是 containerd比如有些 K8s 节点直接用ctr命令套路其实是一样的只能想办法找到“日志输出”和“进程状态”这两样东西。5. 我踩过的坑与速查手册讲了这么多组合拳最后聊几个我实际踩过、或者说见过别人踩的真实“坑”。这些坑如果你没见过很容易被绕进去白折腾一两个小时。这一节更像一个避错清单加速查本。5.1 常见坑一管道命令“吃”掉了原始错误信息这一点我非常想强调。管道虽然方便但是有个副作用——它会把前一个命令的错误输出stderr直接“吞掉”或原样输出。有时候你明明在管道链里加了grep结果发现啥也没匹配到但单独去跑前半段命令却看到一大片错误。比如你运行curl -s http://example.com | grep title如果curl本身报了错比如 404这个错误信息是打在 stderr 上的|管道默认只传递 stdout所以 grep 会静静地筛选一个空串。你看到的现象就是“没有任何输出”但根本不知道 curl 已经跪了。为了避免这种问题我习惯把21加上curl -s http://example.com 21 | grep title这样 stderr 和 stdout 就能一起流入管道错误信息不会凭空消失。这个细节有时候能救命。5.2 常见坑二uniq必须先排序uniq命令是一个特别容易出错的小坑。它的逻辑是“删除连续的重复行”注意是“连续”。如果文件里相同的内容不相邻uniq根本没能力把它们识别出来。printf apple\nbanana\napple\n | uniq -c你猜结果是什么它统计出来是三个不同的项目尽管 apple 出现了两次。因为 apple 之间夹着一个 banana它只负责处理相邻的。正确做法是printf apple\nbanana\napple\n | sort | uniq -c先sort让相同的行排到一起再uniq -c才得到正确计数。我见过太多人在统计日志时因为这个顺序问题得出了错误结论还以为是日志数据不全。5.3 常见坑三xargs 遇到空格和特殊字符xargs也不是万能的。当你找到的文件路径或者参数里包含空格比如一个目录名是My Documentsxargs默认会把空格当作分隔符硬生生把一个“长项”拆成两个“短项”导致命令执行失败。解决办法是尽量让find和xargs都支持“空字符”分隔。Linux 下是-print0和-0搭配find . -name *.txt -print0 | xargs -0 rm -f-print0意思是输出时不换行而是用空字符null分隔xargs -0则告诉 xargs 也按空字符识别。这样文件名里的空格就安全了。虽然这个场景有点进阶但一旦遇到一次文件名带空格的情况你就会回来感谢这个命令。5.4 速查表直接抄作业最后我把上面讲到的核心组合整理成一个小表方便你贴到笔记软件里随时查。这里面的命令我可以说都经过生产环境验证你按着用基本不会出大问题。目标场景组合命令核心动作拆解查 Top 消耗 CPU 的进程ps aux --sort-%cpu | head -n 10按 CPU 降序 取前 10统计访问量 Top 10 IPawk {print $1} access.log | sort | uniq -c | sort -rn | head -n 10去字段 - 排序 - 去重计数 - 按数降序 - 取前 10按关键字过滤并看上下文grep -n ERROR app.log | tail -n 50精确匹配 只看最后 50 条命中的行带行号批量解压当前目录 tar.gzfor i in *.tar.gz; do tar -xzf $i; done遍历所有匹配文件 调 tar查看端口对应进程netstat -tunlp | grep 8080或ss -tunlp | grep 8080列出监听端口及 PID 过滤定期观测服务器负载while true; do uptime; sleep 3; done死循环 睡眠间隔统计代码行数忽略空行cat app.py | grep -v ^\s*$ | wc -l排除纯空白行 统计行号按时间截取日志段落sed -n /2024-08-01 10:00/,/2024-08-01 10:30/p app.log匹配开始行 匹配结束行查看某个目录下最大的文件du -sh * | sort -rh | head -n 5估算目录占用 按人类可读大小降序找 PID 并强杀慎用ps -ef | grep python | grep -v grep | awk {print $2} | xargs -r kill -9过滤进程 - 剔除自身 - 拿 PID - kill最后一个kill -9我在前面也强调过了这里再啰嗦一句能不带-9尽量别带除非你对那个进程的底细非常清楚。xargs -r的作用是“如果前一条命令没有输出就不执行 kill”这能防止误杀。关于 Linux 命令的组合玩法细节实在太多但我始终觉得最重要的不是背下来某条命令而是培养一种“流水线”处理的直觉第一步生成数据第二步过滤或转换第三步排序或统计最后一步取结果。这套思维打通之后你会发现命令行给我们带来的效率提升是任何图形界面工具都很难比拟的。多在自己平时的工作里试试把顺手的三五条命令拼在一起慢慢你也会整理出属于自己的“独家组合拳”。