跳转到内容

Linux 标准输入与输出

在 Linux 中,所有的输入和输出操作通过**文件描述符(fd)**来标识。标准输入、标准输出以及标准错误是进程启动时自动打开的三个默认文件描述符,是 Shell 脚本和系统编程中最基础的 I/O 机制。理解重定向机制有助于灵活控制命令的输入来源和输出去向。

名称 英文缩写 文件描述符 默认对应设备 作用
标准输入 stdin 0 键盘 接收用户输入(如命令的参数、交互输入)
标准输出 stdout 1 终端(屏幕) 输出进程的正常结果
标准错误输出 stderr 2 终端(屏幕) 输出进程的错误信息

每一个进程打开时都会自动获取 3 个文件描述符 0、1、2,分别对应标准输入、标准输出、标准错误。如果要打开其他的文件,则文件描述符必须从 3 开始标识。对于人为打开的描述符,建议使用 9 以内的描述符,超过 9 的描述符可能已经被系统内部分配给其他进程。

Linux 有一些与标准输入、标准输出、标准错误相关的特殊文件:

  • /dev/fd/0、/dev/fd/1、/dev/fd/2
  • /dev/stdin、/dev/stdout、/dev/stderr

/dev/fd/{0,1,2}

查看 /dev/fd 下的内容:

Terminal window
$ ls -l /dev/fd/
total 0
lrwx------ 1 bdathe bdathe 64 Jul 29 09:31 0 -> /dev/pts/0
lrwx------ 1 bdathe bdathe 64 Jul 29 09:31 1 -> /dev/pts/0
lrwx------ 1 bdathe bdathe 64 Jul 29 09:31 2 -> /dev/pts/0
lr-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}

Terminal window
$ ls -l /dev/std*
lrwxrwxrwx 1 root root 15 Jul 27 14:11 /dev/stderr -> /proc/self/fd/2
lrwxrwxrwx 1 root root 15 Jul 27 14:11 /dev/stdin -> /proc/self/fd/0
lrwxrwxrwx 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 更贴近底层逻辑。

在 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< file
  • command 1> file
  • command 1>> file
  • command 0< file1 1> file2

数字和重定向符号之间不要空格!

如果需要重定向标准错误(2),需手动填写描述符编号:

  • command 2> file
  • command 2>> file

& 符号

在重定向语境下,& 后面紧跟一个数字表示该进程中对应的文件描述符:

  • &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=3
    cat <&3 # 从 fd=3 读取数据(即 input.txt)并输出到 stdout
  • [n]>&word:将文件描述符 n 的输出目标设置为 word 对应的文件或描述符(n 省略时默认为 1)

    Terminal window
    exec 3>&1 # 创建 fd=3 并复制自 fd=1
    echo "World" >&3 # 输出到终端

重定向顺序

  • >file 2>&1:先将 fd=1 重定向到 file,再将 fd=2 指向 fd=1 当前的目标(即 file)。最终标准输出和标准错误都写入 file

    重定向顺序1.png

  • 2>&1 >file:先将 fd=2 指向 fd=1 当前的目标(即 /dev/stdout),再将 fd=1 重定向到 file。最终标准错误输出到终端,标准输出写入 file。

    重定向顺序2.png

  • 查看文件描述符的使用情况: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
Terminal window
# 基本重定向
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.txt
echo "log message" >&3
exec 3>&- # 关闭 fd=3