Linux 标准输入与输出
在 Linux 中,所有的输入和输出操作通过**文件描述符(fd)**来标识。标准输入、标准输出以及标准错误是进程启动时自动打开的三个默认文件描述符,是 Shell 脚本和系统编程中最基础的 I/O 机制。理解重定向机制有助于灵活控制命令的输入来源和输出去向。
| 名称 | 英文缩写 | 文件描述符 | 默认对应设备 | 作用 |
|---|---|---|---|---|
| 标准输入 | stdin | 0 | 键盘 | 接收用户输入(如命令的参数、交互输入) |
| 标准输出 | stdout | 1 | 终端(屏幕) | 输出进程的正常结果 |
| 标准错误输出 | stderr | 2 | 终端(屏幕) | 输出进程的错误信息 |
每一个进程打开时都会自动获取 3 个文件描述符 0、1、2,分别对应标准输入、标准输出、标准错误。如果要打开其他的文件,则文件描述符必须从 3 开始标识。对于人为打开的描述符,建议使用 9 以内的描述符,超过 9 的描述符可能已经被系统内部分配给其他进程。
输入输出文件接口
Section titled “输入输出文件接口”Linux 有一些与标准输入、标准输出、标准错误相关的特殊文件:
/dev/fd/0、/dev/fd/1、/dev/fd/2/dev/stdin、/dev/stdout、/dev/stderr
/dev/fd/{0,1,2}
查看 /dev/fd 下的内容:
$ ls -l /dev/fd/total 0lrwx------ 1 bdathe bdathe 64 Jul 29 09:31 0 -> /dev/pts/0lrwx------ 1 bdathe bdathe 64 Jul 29 09:31 1 -> /dev/pts/0lrwx------ 1 bdathe bdathe 64 Jul 29 09:31 2 -> /dev/pts/0lr-x------ 1 bdathe bdathe 64 Jul 29 09:31 3 -> /proc/50003/fd/dev/pts/0是伪终端设备,用于与终端交互0、1、2都是符号链接(仅对当前进程有效),指向/dev/pts/0
进程 A 的标准输出(
1)可能指向/dev/pts/0,即将输出显示到终端; 进程 B 可能将标准输出(1)重定向到文件/tmp/output.txt,此时/dev/fd/1对进程 B 来说就指向/tmp/output.txt。
3是一个额外的文件描述符,指向/proc/50003/fd,它是进程50003的文件描述符目录
/dev/{stdin,stdout,stderr}
$ ls -l /dev/std*lrwxrwxrwx 1 root root 15 Jul 27 14:11 /dev/stderr -> /proc/self/fd/2lrwxrwxrwx 1 root root 15 Jul 27 14:11 /dev/stdin -> /proc/self/fd/0lrwxrwxrwx 1 root root 15 Jul 27 14:11 /dev/stdout -> /proc/self/fd/1在 Linux 系统中,/proc/self 表示当前进程自身,/proc/self/fd 目录包含了当前进程打开的所有文件描述符的符号链接。
两者的区别
/dev/stdout是符号链接文件,物理上指向当前标准输出的目标(例如终端、管道或文件),若进程重定向了标准输出,/dev/stdout会跟随指向重定向的目标/dev/fd/1是文件描述符的直接映射,无论标准输出是否被重定向,它始终对应进程的文件描述符1
核心差异:
/dev/stdout是标准输出的符号链接(语义层),/dev/fd/1是文件描述符 1 的映射(句柄层)。日常场景中二者可互换,但stdout语义更清晰、兼容性更强;fd/1更贴近底层逻辑。
基本 I/O 重定向
Section titled “基本 I/O 重定向”在 Linux 中一切皆文件,默认的 I/O 文件是 /proc/self/fd/{0,1,2},重定向就是把默认的输入/输出文件换成别的文件。
重定向符号:<、>、>>
| 命令 | 说明 |
|---|---|
command < file |
将标准输入重定向至 file,使命令从文件中读取输入 |
command > file |
将标准输出重定向至 file,覆盖文件内容 |
command >> file |
将标准输出追加重定向至 file |
command < file1 > file2 |
标准输入从 file1 读取,标准输出写入 file2 |
上面的命令都是简写,完整写法:
command 0< filecommand 1> filecommand 1>> filecommand 0< file1 1> file2数字和重定向符号之间不要空格!
如果需要重定向标准错误(
2),需手动填写描述符编号:
command 2> filecommand 2>> file
高级 I/O 重定向
Section titled “高级 I/O 重定向”& 符号
在重定向语境下,& 后面紧跟一个数字表示该进程中对应的文件描述符:
&0表示标准输入文件描述符&1表示标准输出文件描述符&2表示标准错误文件描述符
exec 命令
exec 是 Shell 的内建命令,不启动新的子进程,而是直接在当前 Shell 进程中执行指定的命令,或用于重定向文件描述符。
| 语法 | 说明 |
|---|---|
exec [n]< file |
将文件 file 关联到文件描述符 n(读取),缺省为 0 |
exec [n]> file |
将文件 file 关联到文件描述符 n(写入),缺省为 1 |
exec [n]<> file |
将文件 file 关联到文件描述符 n(双向读写) |
exec [n]<&digit |
复制描述符 digit 的输入流到描述符 n,缺省为 0 |
exec [n]>&digit |
复制描述符 digit 的输出流到描述符 n,缺省为 1 |
exec n>&- |
关闭文件描述符 n 的输出流 |
exec n<&- |
关闭文件描述符 n 的输入流 |
文件描述符的复制
使用 & 将一个文件描述符复制到另一个作为副本:
-
[n]<&word:将文件描述符n的输入源设置为word对应的文件或描述符(n省略时默认为 0)Terminal window exec 3< input.txt # 打开 input.txt 并关联到 fd=3cat <&3 # 从 fd=3 读取数据(即 input.txt)并输出到 stdout -
[n]>&word:将文件描述符n的输出目标设置为word对应的文件或描述符(n省略时默认为 1)Terminal window exec 3>&1 # 创建 fd=3 并复制自 fd=1echo "World" >&3 # 输出到终端
重定向顺序
-
>file 2>&1:先将fd=1重定向到file,再将fd=2指向fd=1当前的目标(即file)。最终标准输出和标准错误都写入file
-
2>&1 >file:先将fd=2指向fd=1当前的目标(即/dev/stdout),再将fd=1重定向到file。最终标准错误输出到终端,标准输出写入file。
-
查看文件描述符的使用情况:
ls /proc/self/fd/ -
丢弃输出:
Terminal window command > /dev/null 2>&1 # 将 stdout 和 stderr 都重定向到 /dev/null -
合并标准输出和错误:
Terminal window command > output.txt 2>&1 # 将 stdout 和 stderr 都写入 output.txt
# 基本重定向echo "hello" > output.txt # 覆盖写入echo "world" >> output.txt # 追加写入sort < unsorted.txt > sorted.txt # 从文件读取并输出到文件
# 分离标准输出和标准错误command > stdout.log 2> stderr.log
# 丢弃所有输出command > /dev/null 2>&1
# 使用 exec 打开自定义文件描述符exec 3> mylog.txtecho "log message" >&3exec 3>&- # 关闭 fd=3