No history yet

流控制与文件描述符

理解文件描述符

在 Unix-like 系统中,每个进程启动时都会自动获得三个标准的数据流。这些不是抽象概念,而是具体的通信渠道,通过一种称为 (File Descriptors) 的机制来管理。它们是简单的整数,充当进程与内核之间文件、管道或设备的“门票”。

  • 0 (标准输入, stdin): 进程从中读取数据。默认连接到键盘。
  • 1 (标准输出, stdout): 进程向其写入正常输出。默认连接到终端屏幕。
  • 2 (标准错误, stderr): 进程向其写入错误信息。默认也连接到终端屏幕。

这种分离至关重要。将正常输出 (stdout) 与错误信息 (stderr) 分开,允许我们独立地处理它们。例如,你可以将程序的运行日志保存到一个文件中,同时仍然在屏幕上看到错误信息,以便立即采取行动。这种设计是 Unix 哲学的基础,它将设备、套接字和进程间通信都抽象为文件式的数据流。

将文件描述符想象成三个管道:一个用于进水 (stdin),一个用于出净水 (stdout),一个用于排出废水 (stderr)。你可以将这些管道连接到任何地方。

高级重定向

重定向就是改变这些标准流的目的地。虽然 > (覆盖写入) 和 >> (追加写入) 是基础,但真正的威力在于精确控制每个文件描述符。

# 将 stdout 重定向到 output.log
ls -l > output.log

# 将 stderr 重定向到 error.log
# 假设 my_program 产生了一个错误
my_program 2> error.log

一个常见的需求是同时捕获 stdout 和 stderr。有两种主要方法,它们的语法和执行逻辑略有不同。

command > file 2>&1 这个命令链是按顺序执行的。首先,> 将 stdout (FD 1) 重定向到 file。然后,2>&1 将 stderr (FD 2) 重定向到 stdout (FD 1) 当前指向的位置,也就是 file。顺序很重要,如果写成 2>&1 > file,它会先将 stderr 指向原始的 stdout (终端),然后才将 stdout 重定向到文件,结果就是错误信息仍然会显示在屏幕上。

较新版本的 Bash 提供了一个更简洁的语法 &> 来实现同样的效果。它将 stdout 和 stderr 合并,并一同重定向。

# &> 是 2>&1 的简写形式
command &> output_and_errors.log

在某些场景下,你可能只关心其中一个流,而想完全忽略另一个。/dev/null 是一个特殊的虚拟设备文件,它会丢弃所有写入它的数据。这在编写脚本时特别有用,可以避免不必要的输出污染日志或终端。

# 只保留错误信息,丢弃所有正常输出
command 1>/dev/null

# 只保留正常输出,丢弃所有错误信息
command 2>/dev/null

管道与 tee 命令

管道符 | 是 Bash 中强大的工具,它将一个命令的 stdout 连接到另一个命令的 stdin。这是一个原子操作,创建了一个从左到右的单向数据流。重要的是,管道只传递 stdout,默认情况下会忽略 stderr。

# ls 的输出成为 grep 的输入
ls -l | grep ".txt"

# 如果 ls 产生错误 (例如目录不存在), 错误信息会直接显示在终端
# 它不会被管道传递给 grep
ls non_existent_dir | grep ".txt"

如果你希望管道同时处理 stdout 和 stderr,可以先用 2>&1 将它们合并。

# 合并 stdoutstderr, 然后一起通过管道传递
my_program 2>&1 | less

有时,你既想在屏幕上看到输出,又想将其保存到文件中。这时候 tee 命令就派上用场了。它从 stdin 读取数据,然后将其同时写入 stdout 和一个或多个文件,就像管道中的一个 T 形接头。

# `ping` 的输出会显示在屏幕上,并且同时被写入 ping_log.txt
# -a 选项表示追加内容,而不是覆盖
ping google.com | tee -a ping_log.txt
Quiz Questions 1/5

在 Unix-like 系统中,哪个文件描述符代表标准错误 (stderr)?

Quiz Questions 2/5

哪个命令可以正确地将一个脚本 script.sh 的标准输出 (stdout) 和标准错误 (stderr) 都重定向并覆盖写入到 output.log 文件中?

这些技术构成了在 Bash 中进行复杂数据处理和脚本编程的基石。熟练掌握它们,你就能构建出更健壮、更可预测的命令行工作流。