cmd1 | cmd2把 cmd1 的标准输出接给 cmd2 的标准输入。
约 1207 字大约 4 分钟
2026-05-14
Linux 的命令大多只做一件小事:grep 只过滤,sort 只排序,wc 只计数。它们之所以能解决复杂问题,靠的是管道和重定向——把一个命令的输出接到另一个命令的输入,或者接进文件。这是命令行"组合的艺术",也是日志排查的基本功。
掌握管道 | 和重定向 > >> 2>,理解数据流如何在命令之间、命令和文件之间流动,把小命令拼成处理流水线。
cmd1 | cmd2把 cmd1 的标准输出接给 cmd2 的标准输入。
cmd > file把标准输出写进文件,文件原有内容被清空。
cmd >> file把标准输出追加到文件末尾,不清空。
cmd > file 2>&1把标准输出和标准错误都写进同一个文件。
管道符 | 的作用只有一句话:把左边命令的 stdout,接成右边命令的 stdin。于是一连串小命令就能层层加工同一份数据:
grep "ERROR" app.log | awk '{print $5}' | sort | uniq -c | sort -rn这条命令读起来就是一句话:从日志里挑出错误行 → 取第 5 列 → 排序 → 统计每种出现几次 → 按次数从多到少排。每一段都只做一件事,组合起来就是一个"错误类型排行榜"。
写长管道有个好习惯:从左往右一段一段加。先跑 grep "ERROR" app.log,看输出对不对;再加 | awk ...,再看;不要一次写完再调试。
管道连接的是命令,重定向连接的是命令和文件:
| 写法 | 含义 |
|---|---|
cmd > file | stdout 写入 file,覆盖原内容 |
cmd >> file | stdout 追加到 file 末尾 |
cmd < file | 把 file 当作 stdin 喂给 cmd |
cmd 2> file | stderr 写入 file |
cmd > file 2>&1 | stdout 和 stderr 都写入 file |
cmd > /dev/null 2>&1 | 输出和错误全部丢弃 |
2>&1 容易写错顺序。它的意思是"把 2 号流指向 1 号流当前的去处",所以必须放在 > file 之后。写成 cmd 2>&1 > file,stderr 还是会留在屏幕上,因为执行 2>&1 时 stdout 还指着屏幕。
正常结果走 stdout(1),错误和诊断走 stderr(2)。这条区分在重定向时特别重要:
find / -name "*.conf" > result.txt # 结果进文件,但权限报错还刷屏
find / -name "*.conf" > result.txt 2>/dev/null # 结果进文件,报错丢弃跑大范围搜索时,第二种写法能让你专注看结果,不被一堆 "Permission denied" 淹没。
重定向 > 会把输出"吞进"文件,屏幕上什么都看不到。如果你既想存日志又想实时盯着,用 tee:
./deploy.sh 2>&1 | tee deploy.log # 屏幕和文件同时输出
./deploy.sh 2>&1 | tee -a deploy.log # -a 表示追加tee 像水管上的三通,数据一路去屏幕、一路进文件。
> 在命令运行前就清空文件
cmd > important.log 这一步,Shell 在启动 cmd 之前就把 important.log 清空了。哪怕 cmd 立刻失败,文件也已经没了。一个经典翻车是 grep foo file > file——还没读就被清空,结果是空文件。需要原地过滤请写中间文件,或用 sponge(moreutils)。担心误覆盖可以开 set -o noclobber。
| 误区 | 更稳妥的做法 |
|---|---|
| 以为管道能把错误信息也传下去 | 管道只接 stdout;要带上错误用 `2>&1 |
2>&1 放在 > file 前面 | 顺序必须是 > file 2>&1,否则 stderr 仍在屏幕 |
用 > 想"原地处理"同一个文件 | cmd file > file 会先清空文件;先写临时文件再替换 |
| 长管道一次写完才调试 | 从左到右逐段追加,每加一段先确认输出 |
版权归属:Shuo Liu