Linux 管道到底怎么用?几个实战例子讲明白
刚学 Linux 那会儿,我看别人敲命令,一长串竖线连着,屏幕上哗哗往下滚日志,觉得特别唬人。后来才明白,管道这东西说白了就一句话:把前一个命令吐出来的东西,直接塞进后一个命令的嘴里。就这么简单。我第一次真正用上它,是服务器磁盘报警,我要在一堆日志里找出哪个 IP 访问最频繁。手动翻?几万行,翻到明年。后来用了一条管道命令,三秒钟出结果,从那以后我就离不开了。
管道的核心就一句话
语法上就是一个竖线符号 |,左边是生产者,右边是消费者。左边命令的标准输出,不再打到屏幕上,而是变成右边命令的标准输入。注意是标准输出,标准错误默认不走管道,所以有些命令报错你还是能看到一堆红字飘过去,别以为是管道坏了。

举个最日常的例子。我想看服务器上有没有 nginx 进程:ps aux | grep nginx。ps 把所有进程列出来,grep 从里面挑出带 nginx 的行。如果不用管道,你得先 ps 到文件里,再 grep 那个文件,多两步。管道把这些中间文件全省了。

再往下叠就更有意思了。查日志里有多少条 500 错误:cat access.log | grep " 500 " | wc -l。三层,读文件、筛行、数数,一条命令搞定。我第一次看到这个写法的时候,心里想的是:原来命令行还能这么拼。

几个我天天在用的组合
- 统计访问量最高的 IP:
awk '{ print $1}' access.log | sort | uniq -c | sort -rn | head -20,五层管道,从原始日志直接出排行榜 - 找出占内存最大的进程:
ps aux | sort -k4 -rn | head -5,排查机器卡顿的第一招 - 看目录里最大的文件:
du -sh * | sort -rh | head -10,磁盘满了就靠它 - 实时盯错误日志:
tail -f app.log | grep -i error,调试的时候挂在一个窗口里不用管
这些命令我基本是肌肉记忆了。真正让我少走弯路的,是下面这几个坑。
我踩过的三个坑
第一个坑是 cd不管用。有次我写 ls | cd /tmp,敲完发现目录压根没切。原因很简单,管道右边是在子 shell 里跑的,子 shell 里 cd 了,退出来对当前 shell 毫无影响。这个坑我当时查了半小时才想通。
第二个坑是实时日志看不到。用 tail -f接 grep,按理说应该一行行往外冒,结果等了半天啥都没有,一按 Ctrl+C 哗啦全出来了。这是缓冲搞的鬼,管道那头不是终端,程序就攒够一块才吐。解决办法是给命令加上行缓冲,比如 grep 用 --line-buffered,或者前面套一层 stdbuf -oL。
第三个坑是退出码。管道整条命令的返回值,默认取的是最后一个命令的。前面某个环节失败了,你可能完全不知道。写脚本的时候我一般会加上 set -o pipefail,任何一个环节出错整条就算失败,这样才不会埋雷。
还有一点,管道不是万能的。数据量特别大的时候,多个进程串起来跑,上下文切换的开销也不小。如果只是简单筛选,有时候 awk 一条命令比接三四个管道更快。我自己的判断标准是:能一条 awk 解决的,就别硬拆成管道链,可读性也差。
想练手的话,别背命令。找个真实的日志文件,先想清楚"我要什么结果",再倒推每一步该干什么,一层一层往上接。管道这东西,用着用着就顺手了。