【Linux】fd_重定向本质

hello~ 很高兴见到大家! 这次带来的是Linux系统中关于基础 IO这部分的一些知识点,如果对你有所帮助的话,可否留下你宝贵的三连呢?
个 人 主 页 : 默|笙


文章目录

  • 一、理解重定向本质
      • [1.1 linux分配文件描述符遵循最小可用原则- - -分配规则](#1.1 linux分配文件描述符遵循最小可用原则- - -分配规则)
      • [1.2 IO函数只认文件描述符,不认特定的文件](#1.2 IO函数只认文件描述符,不认特定的文件)
      • [1.3 dup2系统调用](#1.3 dup2系统调用)
  • 二、初步认识一切皆文件

一、理解重定向本质

1.1 linux分配文件描述符遵循最小可用原则- - -分配规则

  1. 在之前的学习中,我们知道每一个进程运行之后,都会默认打开三个文件,分别是标准输入流,标准输出流和标准错误流,它们分别对应文件描述符0、1、2。而进程新打开的文件则会分配从3开始依次往后的文件描述符。
cpp 复制代码
 10   int fda = open("log.txt1", O_WRONLY | O_CREAT | O_TRUNC, 0666);
 11   int fdb = open("log.txt2", O_WRONLY | O_CREAT | O_TRUNC, 0666);
 12   int fdc = open("log.txt3", O_WRONLY | O_CREAT | O_TRUNC, 0666);
 13   printf("fda: %d\n", fda);
 14   printf("fdb: %d\n", fdb);
 15   printf("fdc: %d\n", fdc); 
  1. 如果我们人为将这三个默认打开的文件关闭再打开一个新的文件log.txt会怎么样--->关闭标准输入流文件,那么文件描述符为0的位置就会空出来,这个时候3就不是最小且可以分配的文件描述符了,也就是说,log.txt的文件描述符会是0,而不是3。可以通过下面的代码进行验证:
cpp 复制代码
  9   close(0);                                                                                                                              
 10   int fp = open("log.txt", O_WRONLY | O_CREAT | O_TRUNC, 0666);
 11   printf("fp: %d\n", fp);

1.2 IO函数只认文件描述符,不认特定的文件

  1. C语言里面stdin、stdout和stderr都是对文件描述符fd的抽象封装,这也就意味着这三个流它们是不认识这些文件描述符所对应的文件的。一般stdin对应键盘文件,stdout和stderr对应显示器文件。如果将这些fd对应的文件替换掉,是不是就能够实现从其他文件进行输入输出了呢?是的。我们可以用下面这段代码进行验证:
cpp 复制代码
 10   close(1);
 11   int fp = open("log.txt", O_WRONLY | O_CREAT | O_TRUNC);
 12   printf("fp: %d\n", fp);        
  1. 这里可以看到,如果我们把标准输出流关闭之后,printf要打印的内容在test执行之后没有显示在显示器上,而是打印到了log.txt文件里面,这是因为printf这个io函数它只认文件描述符1,它会把内容打印到文件描述符1对应的文件里面。在把标准输入流关闭打开一个新文件log.txt之后,文件描述符1就归log.txt这个文件了,printf要打印的内容自然就会打印到文件log.txt里面,而非显示器文件了。这就是为什么我们执行test看不到打印的内容而查看log.txt文件能够看到打印内容的原因。
  1. 我们通过关闭原来的输入输出流然后打开新的文件来代替要进行IO操作的显示器,键盘文件来实现对不同的文件输入输出。不过,现在一般是先打开新文件,然后将这个新文件覆盖掉原来的输入输出流对应文件。替换原输入输出流(键盘 / 显示器)对应的文件描述符(0/1/2)来达到对其他文件的IO操作,这就是重定向的本质
  2. 这里替换标准输入流对应文件也是一样,它不会再从键盘读取数据而是从文件描述符0对应的文件里面读取数据。
cpp 复制代码
 10   close(0);
 11   int fp = open("log.txt", O_RDONLY);                                                                                                    
 12   printf("fp: %d\n", fp);
 13   char s[10];
 14   scanf("%s", s);
 15   printf("%s\n", s);
  1. 事先我往已经存在的文件 log.txt 输入了一串字符helloworld,然后将文件描述符0对应的文件改为log.txt,之后用scanf读取log.txt文件内容再打印到显示器上,如果我们不改变文件描述符0对应文件,那么它应该从键盘读取数据,改变之后自然就从log.txt文件里面读取数据了。

1.3 dup2系统调用

  1. dup2这个接口就是专门用来改变文件描述符的,它的原理是进行覆盖,即用oldfd对应的文件覆盖newfd原本的绑定关系。比如上面我们用 log.txt代替了文件描述符0/1对应的文件,那么log.txt对应的文件描述符就是oldfd,而文件描述符0/1就是newfd。
  2. 有了这个函数,就不用通过关闭再打开文件进行替换操作,而是直接进行覆盖。
    10.进行程序替换是不会影响到进程已经打开的文件的。

二、初步认识一切皆文件

  1. 我们知道Linux系统里面一切皆文件,那么硬件在Linux系统里面也会是一个文件。OS要对这些硬件文件进行管理,一定也是先描述再组织,也就是把硬件的属性等其他内容打包成一个结构体struct_file。
  2. 对每个硬件进行操作,其实无非两种,输入和输出操作即IO操作。但是每一个硬件设备它们的访问方式都各不相同,比如键盘是输入,它的输出操作没有意义,显示器则与之相反。每一个硬件设备都有自己的输入和输出操作(驱动方法),要让OS对这些硬件以及其他文件进行统一操作,就需要对struct_file进行改造,加入operations模块绑定对应专属的IO操作,这样就实现了对不同的硬件进行统一操作。它类似于c++里面的多态。

今天的分享就到此结束啦,如果对读者朋友们有所帮助的话,可否留下宝贵的三连呢~~
让我们共同努力, 一起走下去!

相关推荐
甲鱼92919 小时前
MySQL 实战手记:日志管理与主从复制搭建全指南
运维
Johny_Zhao1 天前
OpenClaw安装部署教程
linux·人工智能·ai·云计算·系统运维·openclaw
YuMiao2 天前
gstatic连接问题导致Google Gemini / Studio页面乱码或图标缺失问题
服务器·网络协议
chlk1233 天前
Linux文件权限完全图解:读懂 ls -l 和 chmod 755 背后的秘密
linux·操作系统
舒一笑3 天前
Ubuntu系统安装CodeX出现问题
linux·后端
改一下配置文件3 天前
Ubuntu24.04安装NVIDIA驱动完整指南(含Secure Boot解决方案)
linux
碳基沙盒3 天前
OpenClaw 多 Agent 配置实战指南
运维
深紫色的三北六号3 天前
Linux 服务器磁盘扩容与目录迁移:rsync + bind mount 实现服务无感迁移(无需修改配置)
linux·扩容·服务迁移
SudosuBash3 天前
[CS:APP 3e] 关于对 第 12 章 读/写者的一点思考和题解 (作业 12.19,12.20,12.21)
linux·并发·操作系统(os)
哈基咪怎么可能是AI4 天前
为什么我就想要「线性历史 + Signed Commits」GitHub 却把我当猴耍 🤬🎙️
linux·github