【Linux】基础IO(三):文件描述符与重定向

【Linux】基础IO(三):文件描述符重定向

这是Linux基础IO系列的第三篇,我们重点来理解文件描述符(File Descriptor,简称fd)以及Shell中非常常用的重定向机制。

一、什么是文件描述符(fd)?

在Linux中,一切皆文件(文件、目录、管道、socket、设备……)。
内核为了统一管理这些“文件”,给每个进程维护了一张打开文件描述符表(本质是一个数组)。

每个打开的文件(或类文件资源)都会在这个表中占一个位置,下标就是一个非负整数,这个整数就叫文件描述符(fd)。

每个进程启动时,系统自动为它打开三个特殊的文件描述符:

文件描述符名称含义默认指向简称
0STDIN_FILENO标准输入键盘stdin
1STDOUT_FILENO标准输出显示器(终端)stdout
2STDERR_FILENO标准错误输出显示器(终端)stderr

这三个几乎所有程序都会用到,所以被约定俗成地固定下来。

后面的fd(3、4、5……)由进程自己打开文件时从最小可用的数字开始分配。

二、文件描述符表(进程视角示意图)

当一个进程刚被创建时,内核为它准备的文件描述符表大概长这样:

进程的文件描述符表
下标(fd)    指向的内容
0   ────►  键盘(/dev/tty)
1   ────►  显示器(/dev/tty)
2   ────►  显示器(/dev/tty)
3   ────►  (未使用)
4   ────►  (未使用)
...

当我们执行 ls > a.txt 时,Shell 会:

  1. 打开文件 a.txt → 得到一个新的fd(通常是3)
  2. 把原来的 1 号fd 指向改为指向 a.txt
  3. 执行 ls,它向1号fd写数据 → 最终写入 a.txt

三、Shell 中的重定向操作符

操作符含义示例说明
>标准输出重定向(覆盖)ls > list.txt清空文件 → 写入
>>标准输出重定向(追加)date >> log.txt追加到文件末尾
<标准输入重定向wc -l < access.log从文件读取输入
2>标准错误重定向(覆盖)gcc main.c 2> error.log只把错误信息写入文件
2>>标准错误重定向(追加)make 2>> build.log错误追加到日志
&>>&标准输出 + 标准错误 一起重定向command &> all.log旧写法,部分Shell支持
command > file 2>&1最经典的“输出和错误都重定向”写法./test.sh > out.log 2>&1先重定向1,再让2指向1的位置
command 2>&1 > file错误写法!常见面试陷阱错误信息仍然输出到屏幕

经典写法顺序问题(非常重要!)

# 正确:错误和正常输出都进文件
./script.sh > log.txt 2>&1

# 错误示范:只有正常输出进文件,错误仍然在屏幕
./script.sh 2>&1 > log.txt

为什么?因为重定向是从左到右顺序执行的:

  • 先执行 2>&1 → 2 指向了当时的 1(屏幕)
  • 再执行 > log.txt → 只改变了 1 指向文件,2 仍然指向屏幕

四、常见的重定向组合示例

  1. 只想要正常输出,丢弃错误
make > build.log 2> /dev/null
# 或
make > build.log 2>/dev/null
  1. 正常输出和错误都保存,但分开
./test.sh > stdout.log 2> stderr.log
  1. 正常和错误都保存到同一个文件(推荐写法)
./test.sh > all.log 2>&1
# 更现代的写法(bash 4+)
./test.sh &> all.log
  1. 同时输入和输出重定向
bc < calc.txt > result.txt
  1. Here Document(多行输入)
cat > config.yaml << 'EOF'
server:
  port: 8080
  host: 0.0.0.0
EOF

五、文件描述符复制与关闭(进阶)

Shell 支持显式操作任意fd:

# 把 3 号fd指向文件
exec 3> debug.log

# 向 3 号fd写东西
echo "debug info" >&3

# 关闭 3 号fd
exec 3>&-

经典用法:临时保存原来的stdin/stdout

exec 3<&0          # 备份原来的stdin到3
exec 0< data.txt   # 把stdin重定向到文件
read line          # 从文件读
exec 0<&3          # 恢复原来的stdin
exec 3<&-          # 关闭备份的fd

六、总结:一句话理解重定向

Shell的重定向,本质上就是在子进程执行命令前,修改它的文件描述符表,让某个fd指向别的文件(或管道、设备)。

记住这个本质,你就能理解几乎所有重定向的写法和顺序问题。

下一讲我们会进入更底层的系统调用层面:open/read/write/close/dup/dup2,真正看清楚重定向在内核里是怎么实现的。

有任何疑问欢迎留言~

文章已创建 4455

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

相关文章

开始在上面输入您的搜索词,然后按回车进行搜索。按ESC取消。

返回顶部