人人都会AI编程

13.3 输入输出与重定向

更新时间:2026-07-12

在 Linux 系统里,每个正在运行的程序都会自动打开三个标准数据流,它们是程序与外界通信的基础通道:

  • 标准输入(stdin),文件描述符为 0。默认来自键盘输入,程序从这里读取数据。
  • 标准输出(stdout),文件描述符为 1。默认输出到终端屏幕,程序把正常结果写到这里。
  • 标准错误(stderr),文件描述符为 2。同样默认输出到屏幕,但专门用于显示报错和诊断信息,和标准输出分开。

理解了这三个流向,就能通过“重定向”灵活控制数据的来源和去向。重定向的威力在于:不需要修改程序本身,就可以让同一个命令从文件读取输入、将结果保存到文件、丢弃错误信息,或者把正常输出和错误输出分别处理。

1. 输出重定向:把结果存下来

最常见的需求是将命令的输出保存到文件中,而不是让它一闪而过。重定向符号 > 用于覆盖写入,>> 用于追加写入。

echo "Hello, Linux" > greeting.txt   # 把输出写入文件(覆盖原内容)
date >> log.txt                       # 把当前时间追加到 log.txt 末尾

如果只使用 >,目标文件原本的内容会被完全清空再写入新内容,使用时需格外小心。很多 Shell(如 Bash)提供了 set -o noclobber 来防止意外覆盖已存在的文件,此时追加写入会更安全。

有时会看到类似 > file 的写法,前面没有命令,这会产生一个空文件(或清空已有文件),相当于 touch 的一种简写。

2. 输入重定向:把文件内容喂给命令

很多命令默认从键盘接收输入,但当数据已经保存在文件里时,可以使用 < 让命令直接从文件读取。

wc -l < data.txt          # 统计 data.txt 的行数,不显示文件名
sort < unsorted.txt       # 对文件内容排序并输出

用输入重定向的好处是命令完全不知道数据的源头是文件还是键盘,因此脚本可以不加修改地处理文件输入。另外,一些命令(如 tr)必须通过输入重定向提供数据,因为它们本身不接受文件名作为参数。

3. 标准错误重定向:分离正常输出和报错

默认情况下,标准输出和标准错误都会打印到屏幕上,混在一起。如果想把它们分开,就需要用到 2> 专门重定向标准错误。

ls /nonexistent_dir > out.txt 2> err.txt

这行命令尝试列出一个不存在的目录。正常输出(本来就没有)会进入 out.txt,而错误信息“No such file or directory”会记入 err.txt

常见的组合还包括:

  • command 2>&1:将标准错误合并到标准输出,让它们走同一个流。这对于 grep 过滤或者一并保存非常有用。
  make 2>&1 | tee build.log        # 编译并同时看到输出和保存日志
  
  • command &> file:将标准输出和标准错误都重定向到同一个文件(相当于 > file 2>&1),简洁且不易写错。

4. 管道:将一个命令的输出变成另一个命令的输入

管道符 | 是命令行组合的灵魂。它把前一个命令的标准输出直接连接到后一个命令的标准输入,无需经过中间文件。

ps aux | grep nginx          # 从所有进程中筛选包含 nginx 的行
cat access.log | awk '{print $1}' | sort | uniq -c | sort -rn | head

管道会只传递标准输出,标准错误不受影响,直接输出到终端,这常常是预期行为:你不想让报错信息也混入下游的处理流程。

5. 实用技巧与注意事项

  • 避免不必要的 catcat file | grep pattern 可以简写为 grep pattern file,后者让 grep 直接打开文件,省去一次进程间通信。
  • 临时丢弃输出command > /dev/null 将标准输出丢入黑洞,常用于脚本中只关心命令是否成功,不关心输出内容。
  • 同时写入文件和屏幕command | tee file.txt 将输出一份保存到文件,另一份继续显示在终端。加上 -a 选项可以追加写入。
  • 重定向顺序很重要command 2>&1 > filecommand > file 2>&1 不一样。前者先把 stderr 复制到当时的 stdout(终端),再把 stdout 改到文件,导致 stderr 仍显示在屏幕上;后者才正确地将两者都写入文件。通常推荐使用 &> file 避免这个陷阱。

掌握标准流和重定向之后,你就拥有了像搭积木一样构建数据处理流水线的能力。大多数时候,Linux 的高效并非来自记忆一大堆复杂参数,而是来自将这些简单的数据流控制手段灵活应用到实际任务中。