当前位置:首页>Linux>Linux 中的 stdin、stdout 和 stderr 是什么

Linux 中的 stdin、stdout 和 stderr 是什么

  • 2026-09-02 21:42:06
Linux 中的 stdin、stdout 和 stderr 是什么

当在 Linux 中执行一条命令时,你输入的文字、命令输出的结果、以及报错信息,都是通过一组程序启动前就准备好的连接来传输的。这些连接就是标准输入(standard input)、标准输出(standard output)和标准错误(standard error),通常简称为 stdin、stdout 和 stderr。

Shell 可以在不修改程序本身的情况下,将这些数据流连接到终端、文件、管道或其他目标。本文将介绍这三个标准流的作用、为什么它们对应的文件描述符是 0、1 和 2,以及如何使用 shell 重定向来改变它们的去向。

1. 三个标准流

一个进程在启动时,通常会从父进程继承三个已打开的文件描述符。当你在交互式 shell 中执行命令时,shell 默认会将这三个描述符都连接到当前终端:

数据流文件描述符用途交互式默认连接
stdin
0
程序读取的输入
终端输入
stdout
1
程序的正常输出
终端显示
stderr
2
错误和诊断信息
终端显示

把 stdin 简单理解为“键盘”是一种方便的说法,但实际上程序是从终端设备读取数据的。终端负责处理键盘输入并将其传递给程序。在脚本或管道中,stdin 也可能来自文件或其他命令。

文件描述符的数字很重要,因为 shell 的重定向语法就用到了它们。stdout 和 stderr 默认都会显示在终端上,所以它们看起来像是一个数据流,但实际上是相互独立的。脚本可以将正常结果保存到一个文件中,同时将错误信息发送到其他地方。

2. 分别查看 stdout 和 stderr

下面两条命令分别输出一条普通信息和一条警告信息:

printf'%s\n'"backup complete"
printf'%s\n'"warning: archive not found" >&2

输出结果:

backup complete
warning: archive not found

两行内容都显示在同一个终端上,但它们走的是不同的数据流。第一条 printf 写入的是 stdout。第二条命令中的 >&2 重定向将其输出发送到了 stderr,这样脚本就可以报告诊断信息,而不会把这些信息混入其他命令需要处理的数据中。

3. 改变数据流的去向

Shell 在启动命令之前就会设置好重定向。程序本身并不需要关心这些文件描述符指向的是终端、文件还是管道,它只是照常读写。

> 操作符将 stdout 重定向到文件,如果文件不存在则创建,存在则覆盖其内容:

ls /etc > files.txt

终端上不会显示任何内容,因为目录列表已经被写入了 files.txt。由于没有指定描述符编号时 > 默认操作的是 stdout,所以 > files.txt 和 1> files.txt 的效果是一样的。

stderr 默认仍然连接到终端,除非你对描述符 2 也做了重定向。下面这条命令同时访问一个存在的路径和一个不存在的路径:

ls /etc /nonexistent > files.txt

输出结果:

ls: cannot access '/nonexistent': No such file or directory

成功的目录列表被写入了 files.txt,而错误信息仍然显示在终端上,因为它走的是 stderr。要单独捕获错误信息,可以重定向描述符 2:

ls /etc /nonexistent > files.txt 2> errors.txt

现在,正常结果保存在 files.txt 中,诊断信息保存在 errors.txt 中。

如果想把两个数据流都保存到同一个文件中,可以使用可移植的 shell 语法:先重定向 stdout,再将 stderr 复制到 stdout 的目标位置:

command > output.log 2>&1

这里的 2>&1 表示让文件描述符 2 指向文件描述符 1 当前的目标位置。重定向是从左到右依次处理的,所以调换顺序会产生不同的结果。关于如何合并、追加、管道传递和丢弃输出,可以参考 Bash 中如何将 stderr 重定向到 stdout。

输入重定向的方向则相反。< 操作符将文件连接到 stdin:

sort < names.txt

这里 sort 从 names.txt 读取数据,而不是从终端读取。许多命令也接受文件名作为参数,但输入重定向适用于任何设计为从 stdin 读取数据的命令。

4. 管道如何使用这些数据流

管道(|)将前一个命令的 stdout 连接到后一个命令的 stdin,这样数据就可以在程序之间传递,而无需借助临时文件:

ls /etc | grep conf

ls 的 stdout 成为了 grep 的 stdin。普通管道传递的是 stdout,而不是 stderr,所以 ls 产生的错误信息仍然会显示在终端上,而不会传给 grep。关于更长的管道链、错误处理以及 pipefail 选项,可以参考 Linux 管道使用指南。如果想在终端显示输出的同时保存到文件,可以使用 tee 命令。

5. 快速参考

如需可打印的快速参考,请查看 Bash 速查表。

描述符或语法作用
0
stdin
1
stdout
2
stderr
command < file
从文件读取 stdin
command > file
将 stdout 写入文件(覆盖)
command >> file
将 stdout 追加到文件
command 2> file
将 stderr 写入文件
command > file 2>&1
将 stdout 和 stderr 写入同一个文件
command 2>/dev/null
丢弃 stderr
cmd1 | cmd2
将 cmd1 的 stdout 连接到 cmd2 的 stdin

6. 总结

当命令的输出跑到了你意料之外的地方时,先确认它使用的是文件描述符 0、1 还是 2,然后从左到右阅读它的重定向规则。养成这个习惯后,理解 shell 管道和日志命令就会变得轻松许多。

最新文章

随机文章