Linux 中的 stdin、stdout 和 stderr 是什么?

AI 概述
本文讲解Linux进程三大标准流:0标准输入、1标准输出、2标准错误,二者默认均输出终端但相互独立。介绍Shell各类重定向语法,可单独/合并捕获正常输出与报错,支持文件读取输入、追加写入、丢弃日志;管道仅转发stdout至下一条命令stdin。配套常用重定向速查表,理清重定向从左至右执行逻辑,便于处理命令输出分流、日志保存等运维场景。
目录
文章目录隐藏
  1. 一、三个标准流
  2. 二、分别查看 stdout 和 stderr
  3. 三、改变数据流的去向
  4. 四、管道如何使用这些数据流
  5. 五、快速参考
  6. 六、总结

Linux 中的 stdin、stdout 和 stderr 是什么?

当在 Linux 中执行一条命令时,你输入的文字、命令输出的结果、以及报错信息,都是通过一组程序启动前就准备好的连接来传输的。这些连接就是标准输入(standard input)、标准输出(standard output)和标准错误(standard error),通常简称为 stdin、stdout 和 stderr。Shell 可以在不修改程序本身的情况下,将这些数据流连接到终端、文件、管道或其他目标。本文将介绍这三个标准流的作用、为什么它们对应的文件描述符是 0、1 和 2,以及如何使用 shell 重定向来改变它们的去向。

一、三个标准流

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

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

把 stdin 简单理解为“键盘”是一种方便的说法,但实际上程序是从终端设备读取数据的。终端负责处理键盘输入并将其传递给程序。在脚本或管道中,stdin 也可能来自文件或其他命令。文件描述符的数字很重要,因为 shell 的重定向语法就用到了它们。stdout 和 stderr 默认都会显示在终端上,所以它们看起来像是一个数据流,但实际上是相互独立的。脚本可以将正常结果保存到一个文件中,同时将错误信息发送到其他地方。

二、分别查看 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,这样脚本就可以报告诊断信息,而不会把这些信息混入其他命令需要处理的数据中。

三、改变数据流的去向

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 读取数据的命令。

四、管道如何使用这些数据流

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

ls /etc | grep conf

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

五、快速参考

如需可打印的快速参考,请查看 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

六、总结

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

以上关于Linux 中的 stdin、stdout 和 stderr 是什么?的文章就介绍到这了,更多相关内容请搜索码云笔记以前的文章或继续浏览下面的相关文章,希望大家以后多多支持码云笔记。

「点点赞赏,手留余香」

23

给作者打赏,鼓励TA抓紧创作!

微信微信 支付宝支付宝

还没有人赞赏,快来当第一个赞赏的人吧!

声明:本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如若内容造成侵权/违法违规/事实不符,请将相关资料发送至 admin@mybj123.com 进行投诉反馈,一经查实,立即处理!
重要:如软件存在付费、会员、充值等,均属软件开发者或所属公司行为,与本站无关,网友需自行判断
码云笔记 » Linux 中的 stdin、stdout 和 stderr 是什么?

发表回复