← 完全使用手册

与 Shell 对话 · 流水线与重定向

棱镜2026.6.3  ·  日志

这是《与 Shell 对话》系列的第三篇。前两篇你学会了操作文件和搜索内容——每个命令都是独立使用的。但终端的真正威力来自把命令串起来。一篇的核心是两个符号:|(管道)和 >(重定向)。

上一篇:看与找——信息的读取与搜索  ·  下一篇:面向系统的操作

🔑 关键词索引

关键词一句话说明
标准输入(stdin)编号 0,命令默认的输入来源——通常是你的键盘
标准输出(stdout)编号 1,命令的正常输出目的地——通常是屏幕
标准错误(stderr)编号 2,命令的错误信息通道——也默认去屏幕,但可以单独处理
重定向 >把命令的输出从屏幕转到文件里——ls > 清单.txt 会把结果存下来
追加 >>> 一样,但不覆盖已有内容,而是追加到文件末尾
管道 |把左边命令的输出接到右边命令的输入——A | B,A 的结果变成 B 的处理对象
/dev/nullUnix 的"黑洞"——任何扔进去的东西都会消失,用于丢弃不需要的输出
sort排序——sort -h 按人类可读数字排序,sort -n 按数值排序
uniq去重——去掉相邻的重复行,通常和 sort 配合使用
teeT 型管道——把输出同时送到屏幕和文件,像三通水管
xargs把管道送来的内容转换成命令的参数——"从流水线上拿起每个零件,交给下一个机器处理"

一、标准流——被忽视的核心概念

在你输入一个命令并按回车之后,Shell 会创建三个"通道",连接你的命令和外界:

键盘 ──→ [stdin (0)] ──→ 命令 ──→ [stdout (1)] ──→ 屏幕 命令 ──→ [stderr (2)] ──→ 屏幕
通道编号默认来源/去向拿它做什么
标准输入(stdin)0你的键盘命令读入的数据
标准输出(stdout)1屏幕命令的正常输出
标准错误(stderr)2屏幕命令的错误信息

说人话就是:每个命令都有两个"出口"(正常结果和错误消息),默认都送到屏幕让你看到。而当你学会了重定向和管道,你就可以改变这些通道的方向——把结果存到文件里、把错误丢弃掉、把输出喂给另一个命令。

为什么编号重要?因为重定向时你会在符号前面写编号:2>&1 的意思是"把 2 号通道(stderr)塞进 1 号通道(stdout)"。不写编号时默认操作的是 stdout。

理解标准流是打通终端任督二脉的关键。它解释了为什么 ls 不存在的文件 的错误消息和正常输出走的是不同的管子——这也是为什么你可以把正常结果保存到文件,同时让错误还在屏幕上显示的底层原因。

二、重定向——让输出去该去的地方

2.1 把输出存到文件:>

ls -la ~/Desktop > 桌面清单.txt    # 将 ls 的输出存入文件(不显示在屏幕)
cat 桌面清单.txt                    # 验证——文件里确实有内容

> 的意思是:把 stdout 从"屏幕"转向"文件"。

⚠️ > 会覆盖文件的已有内容。 如果文件原来有内容,使用 > 后原有内容会丢失。

echo "第一行" > 测试.txt    # 创建文件,写入"第一行"
echo "第二行" > 测试.txt    # 覆盖!现在文件里只有"第二行",第一行没了

这里的 echo 命令很简单——它把后面跟着的文字打印到屏幕。echo "第一行" 会输出「第一行」三个字。配上重定向 >,文字就不去屏幕、直接存入文件了。可以把 echo 理解为后续所有重定向和管道练习的「人工输入源」。

2.2 追加到文件末尾:>>

echo "第一行" >> 测试.txt    # 写入"第一行"
echo "第二行" >> 测试.txt    # 追加!文件现在有两行

>>> 的唯一区别:>> 不覆盖,追加到末尾。想保留历史记录时用它。

2.3 处理错误消息:2>2>&1

ls 存在的文件 不存在的文件 > 结果.txt
    # stdout 去了文件,stderr 仍然在屏幕上显示

ls 存在的文件 不存在的文件 > 结果.txt 2> 错误.txt
    # stdout → 结果.txt,stderr → 错误.txt,屏幕干干净净

ls 存在的文件 不存在的文件 &> 全部.txt
    # stdout 和 stderr 合并进同一个文件(&> 是简写)

ls 存在的文件 不存在的文件 > 全部.txt 2>&1
    # 更传统的写法:先把 stdout 指向文件,再把 stderr 指向 stdout

初学时最常用的组合是 2>/dev/null——把错误消息丢进黑洞:

grep -r "某个关键词" ~/Desktop 2>/dev/null
    # 搜索桌面上的文件,忽略所有"权限不够"之类的错误提示

/dev/null 是 Unix 里的一个特殊文件。任何写入它的内容都会被系统丢弃,读它则什么也读不到。它的用途就是"我不在乎这个输出,别给我看"。在搜索时屏蔽大量权限错误是最常见的用法。

2.4 重定向速查表

写法含义
命令 > 文件stdout → 文件(覆盖)
命令 >> 文件stdout → 文件(追加)
命令 2> 文件stderr → 文件(覆盖)
命令 &> 文件stdout + stderr → 同一文件
命令 > 文件 2>&1同上,传统写法
命令 2>/dev/null丢弃 stderr(只看正常输出)
命令 > /dev/null 2>&1丢弃所有输出(全静默模式)

三、管道——终端的组合性

重定向是在命令和文件之间搬运数据。管道是在命令和命令之间搬运数据:

命令A ──→ | ──→ 命令B ──→ 屏幕
命令A | 命令B    # 命令A 的输出 = 命令B 的输入

管道的哲学:每个命令只做一件事,但你可以自由组合它们。 ls 只管列文件,wc 只管数行数——但 ls | wc -l 就变成了"数一数有多少文件"。

前两篇里你已经用过几次管道了(ls | lesshistory | grep)。现在是时候正式理解它:

# 简单管道:两个命令
ls ~/Desktop | wc -l            # 桌面上有多少项目?
grep -r "TODO" ~/Desktop | wc -l  # 桌面文件里有多少个 TODO?

# 三级管道:三个命令串起来
ls -la ~/Desktop | grep "^-" | wc -l  # 桌面上的文件(不含文件夹)有多少个?
#          ls 列出来  →  grep 只保留文件行  →  wc 数一数
# 注意 grep "^-" 中的 ^ 是行首(第二篇学过的正则),- 是字面量。
# ls -la 输出中普通文件的第一个字符是 -,所以 "^-" 匹配以 - 开头的行。

# 四级管道:串四个命令
history | grep "ssh" | grep -v "scp" | head -10
# 历史记录 → 只保留带 ssh 的 → 去掉带 scp 的 → 只看前 10 条

这就是"Unix 哲学"在终端里的具体体现:每个命令做好一件事,然后用管道组合成新的工具。 你不需要一个叫"统计桌面文件数量"的程序——你把 lswc 用管道连起来就行了。你自己"发明"了这个工具。

四、经典管线实战

以下是你在日常使用中最常遇到的管道组合。每个都是 命令1 | 命令2 | 命令3... 的结构。

4.1 数东西——ls | wc -l

# 数文件
ls ~/Desktop | wc -l                # 桌面上有多少项目
ls ~/Downloads | wc -l             # 下载文件夹里有多少文件
find ~/Desktop -name "*.md" | wc -l  # 桌面上有多少 Markdown 文件

这是最简单的管道组合,但你每天都会用到。如果发现结果比预期多了一个——那是因为 ls | wc -l 可能会受到换行符的影响。不用担心,这个误差很小。

4.2 在命令历史中搜索——history | grep

history | grep "ssh"              # 之前用过的所有 ssh 命令
history | grep "pmset"            # 之前用过的电源管理命令
history | grep "brew install"     # 用 Homebrew 装过哪些东西

history 命令列出你用过的所有命令记录。和 grep 组合后,你可以在历史中快速找到"我记得我上周敲过一条很长的命令,但我忘了是什么"——这是终端使用中最实用的场景之一。

4.3 排序——du | sort -h

sort 命令按字母或数字排序行:

du -sh ~/Desktop/*                # 看桌面上一级各项目的大小
du -sh ~/Desktop/* | sort -h       # 按大小从小到大排列(-h 理解 K/M/G)
du -sh ~/Desktop/* | sort -hr      # 按大小从大到小排列(-r 是倒序)

# 显示最大的 5 个
du -sh ~/Desktop/* | sort -hr | head -5

# 找最大的文件——在整个用户文件夹里
du -sh ~/* | sort -hr | head -10

sort 的常用选项:

选项含义场景
sort -n按数值排序数字排序而不是字典序(10 会排在 2 后面)
sort -h按人类可读数字排序理解 1K、2M、3G 这样的单位
sort -r倒序排列最大的在前
sort -t, -k2按逗号分隔的第二列排序处理表格数据时

4.4 去重——sort | uniq

uniq 去掉相邻的重复行。但实际数据中重复行往往不相邻,所以先 sortuniq 是标准组合:

# 先用 echo 和重定向创建一个样本文件(刚学的技能!)
echo "成功" >> 操作日志.txt
echo "成功" >> 操作日志.txt
echo "失败" >> 操作日志.txt
echo "成功" >> 操作日志.txt

# 现在看看这个文件
cat 操作日志.txt

# 去重
sort 操作日志.txt | uniq            # 去重后的结果
sort 操作日志.txt | uniq -c          # 每种状态出现了几次
sort 操作日志.txt | uniq -d          # 只显示重复的行

# 清理
rm 操作日志.txt

一个更实用的例子——找出桌面上所有文件的扩展名并统计频率:

ls -la ~/Desktop | grep "^-" | awk '{print $NF}' | grep -o '\.[^.]*$' | sort | uniq -c | sort -rn

这很长——但它的意思是:列出桌面文件 → 只看文件(不是文件夹)→ 提取最后一列(文件名)→ 只保留扩展名 → 排序 → 统计每种多少个 → 按数量倒序。你不需要记住它,只需要知道管道可以这样一层层组合。

4.5 分页查看长输出——| less

任何输出太长时,送到 less 里翻页查看:

history | less                     # 命令历史太长,翻页看
ls -laR ~/Desktop | less            # 递归列出桌面所有文件,翻页看
find ~ -name "*.md" | less          # 找到所有 .md 文件,翻页看

在 less 里的操作和第二篇学的一模一样:空格翻页,/ 搜索,q 退出。

这五种管线模式——数、搜、排、去重、翻页——覆盖了日常终端使用中 90% 的管道场景。不用背,用的时候回来查。敲多了自然就记住了。

五、tee 与 xargs——两个特别的管道搭档

5.1 tee——既看又存

tee 的名字来自 T 型三通水管——它把输出同时送到两个地方:屏幕 和 文件。

ls ~/Desktop | tee 桌面清单.txt
    # 结果同时在屏幕上显示,又存进了文件

ls ~/Desktop | tee -a 桌面清单.txt
    # -a 追加模式(不覆盖已有内容)

# 实际场景:你想看 find 的结果,又想把它存下来
find ~/Desktop -name "*.md" | tee markdown文件清单.txt | wc -l
    # 结果:屏幕显示文件列表,清单存到了文件,wc 数了数量

tee 的实际使用场景:你正在跑一个重要命令,输出很长,你想一边看结果一边把它存下来。或者你想在管道中间"偷看一眼"当前的数据流长什么样。

5.2 xargs——从流水线到参数

前面所有管道的组合中,右边的命令(如 wcgrepsort)都接受从 stdin 读数据。但有些命令不接受 stdin——它们只接受参数。xargs 就是中间的桥梁:它把左边送来的每一行数据,转换成右边命令的参数。

# find 找到文件,xargs 把文件名作为参数传给 rm
find ~/Desktop -name "*.tmp" | xargs rm
# 等价于:rm 文件1.tmp 文件2.tmp 文件3.tmp ...

# 更安全的做法——先看看 xargs 会做什么
find ~/Desktop -name "*.tmp" | xargs echo
# xargs echo 会列出所有找到的文件——不会删除,只是打印

# 一个实用的例子——统计多个文件的总行数
find ~/Desktop -name "*.md" | xargs wc -l
# wc -l 可以接受多个文件参数,xargs 帮它把所有文件名传过去

xargs 的常用选项:

选项含义示例
-n 1每次只传一个参数xargs -n 1 echo——每行单独处理
-p执行前询问确认xargs -p rm——安全的 rm
-0用空字符分隔(配合 find -print0)处理文件名中有空格的情况

xargs 配合 find -deleterm 时特别危险——因为你要删除的文件列表来自另一个命令的输出,你无法预判它会找到什么。永远先用 | xargs echo 看看 xargs 会拼出什么命令,确认无误后再去掉 echo。 这是一个让你在终端里安全活到老的习惯。

六、综合练习——用管道搭建你的第一个"工具"

这个练习和之前不同——它没有目录结构要创建,直接用你电脑上的真实文件。每一个任务都是一个你可以重复使用的"工具"。

任务一:桌面速查表

用一条命令查看桌面上的所有项目,统计数量,同时把清单保存到文件。

👆 查看参考命令
ls ~/Desktop | tee ~/Desktop/桌面清单.txt | wc -l

任务二:找大文件

在桌面上找出最大的 5 个项目。

👆 查看参考命令
du -sh ~/Desktop/* | sort -hr | head -5

任务三:搜索并统计

在桌面的 .md 文件中搜索"终端"这个词,统计出现了多少次(注意区分大小写)。

👆 查看参考命令
grep -rin "终端" ~/Desktop/领域 | wc -l
# 看看具体哪些文件包含
grep -rl "终端" ~/Desktop/领域

任务四:命令历史分析

查看你最常用的 10 条命令是什么。

这一步需要用到 awk——一个文本处理工具,它的作用是提取每一行的第 2 列(即命令的名字,因为 history 的输出格式是"编号 命令 参数")。你不会 awk 完全没关系——这里只需要看懂管道的链条结构就行:

👆 查看参考命令
history | awk '{print $2}' | sort | uniq -c | sort -rn | head -10
# 解读这个管道的每一段:
# history       → 列出所有命令记录
# awk '{print}' → 只保留"命令名字"那一列(去掉编号和参数)
# sort          → 排序,让相同的命令排在一起
# uniq -c       → 去重,同时统计每种命令出现多少次
# sort -rn      → 按数字倒序排列(最常用的排最前)
# head -10      → 只看前 10 条

任务五:多重过滤

在 ~/.zshrc 中找到所有不是注释、也不是空行的有效配置行,统计有多少行。

👆 查看参考命令
grep -v "^#" ~/.zshrc | grep -v "^$" | wc -l
# 先去注释行,再去空行,然后数剩下的

到这里,你已经可以用终端做一件很"新潮"的事了——你不再依赖专门的应用来统计数据、分析文件和查看系统。一条几十个字的命令,就能完成一个专用小工具的工作。这就是管道的魔力。

📌 本篇核心命令速查

符号/命令作用最常用法
>重定向 stdout 到文件(覆盖)命令 > 文件
>>重定向 stdout 到文件(追加)命令 >> 文件
2>重定向 stderr 到文件命令 2> 错误文件
&>重定向 stdout + stderr 到同一文件命令 &> 文件
2>/dev/null丢弃错误消息grep -r ... 2>/dev/null
|管道——前一个命令的输出 → 后一个命令的输入A | B | C
sort排序sort -h(人类可读) sort -n(数值) sort -r(倒序)
uniq去重(需先 sort)sort 文件 \| uniq -c(统计)
tee同时输出到屏幕和文件命令 | tee 文件 tee -a(追加)
xargs将 stdin 转为命令参数find ... | xargs 命令 xargs -p(确认模式)

待延伸线索


← 上一篇:看与找 下一篇:面向系统的操作 →