linux文件——重定向原理——dup、重定向与execl、VFS
前言:本篇讲解linux下的重定向相关内容。 在本篇中, 博主将会带着友友们一边实验, 一边探索底层原理。 通过本篇的学习, 友友们将会了解到重定向是如何实现的, 重定向的本质是什么, 重定向和进程替换之间的关系等等, 本篇内容将会丰富我们对于进程的理解。
ps:由于本节内容涉及到文件fd,所以本节内容适合了解文件fd的友友们进行观看。
目录
文件描述符的分配规则
重定向的本质
dup
dup2的使用——输出重定向
dup2的使用——输入重定向
自定义shell实现重定向指令
文件的重定向和进程替换
重定向的参数
如何理解计算机下“一切皆文件”
文件描述符的分配规则
想要知道文件描述符的分配规则, 我们需要使用一个实验来测试出来。 下面我们开始进行这个实验:
在这个实验中, 我们会用到wrrite, open函数, 如下图为man手册:
其中, open函数需要包含头文件sys/types.h、sys/stat.h、fcntl.h
write函数需要包含unistd.h头文件
然后, 我们的代码如下:
需要用到的头文件:
下面是我们的代码:
这个程序运行后, 就是如下结果:
图中打印fd, 然后将hello linux的内容打印到log.txt文件中, 再输出log.txt的内容, 就如同上图
上图的fd打印为3, 我们知道, 0, 1, 2对应的是stdin, stdout, stderr。所以新文件fd就到了3号fd。
接下来, 就开始测试文件描述符的分配规则。
从0号小标开始, 寻找最小的没有使用的数组位置,它的下标就是新文件的文件描述符。
我们从上图可以看出, 文件描述符是3。 而0, 1, 2都被占用了。 我们就可以考虑——对于文件来说, 文件描述符都是从小到大创建的。
那么我们为了验证这个猜想, 就可以消除0号下标的指向。 那么0号就空出来了。 这个时候我们再创建的文件就是被映射在了0号下标处。
下面是测试代码:
然后打印出来的fd如下:
上面的结果就是说, 消除了0号fd位置的指针, 当我们再打开一个文件的时候就可以将这个文件指针放入0号位置。
我们再关闭1号fd进行测试:
然后运行结果:
![]()
没有打印出内容的原因是因为1号是显示器文件, 关闭后就不会再向显示器中打印了。
关闭2再测试一下
然后运行结果:
清除2号指针后, 然后打开文件, 2号就会保存新打开的文件指针。 然后打开的fd就变成了2, 打印出来的是2, 同样符合我们的假设。
- 那么现在就可以下结论了——文件描述符对应的分配规则是什么? 从0下标开始, 寻找最小的没有使用的数组位置, 它的下标新文件的文件描述符。
重定向的本质
我们在上面探究文件描述符的分配规则的时候, 知道了1号文件描述符被清空后, 再新打开的文件的文件指针就会保存到1号文件描述符中。 ——这个过程起始就是重定向。
下面重新捋一下这个过程, 对于上面这个过程, 我们的进程本来有一个文件描述符表:

然后我们将1号fd指向显示器的文件的指针收回, 然后创建新文件log.txt, 将log.txt的struct_files的地址放到1号文件的fd处。

我们看下面的具体代码:
上面这个1号fd转化到过程, 也就是上面黄框框的代码段。 对于操作系统来说, 他知不知道fd的指向发生了变化呢? 答案是不知道!!对于操作系统来说, 他不管fd下面做了什么, 他只认fd。 所以, 如果还向1里面写东西, 那么就是本来向显示器文件里面写东西转化为向log.txt文件里面写东西。 而这个过程就是重定向。
那么我们如果想要向其他文件里面写东西, 是不是就需要将这个文件的指针覆盖到1号fd里面? ——这就是重定向。 重定向只需要将想要重定向到文件的指针覆盖到1号所在的fd里面!!
dup
上面我们讲道理重定向的底层原理。 但是整个代码很长——需要一开始关闭1号fd文件描述符指针, 然后将新打开文件的文件描述符指针放到1号文件中。 实际上, 系统就是提供了一种fd覆盖的接口——dup系列, 下面是man手册:
上面有三个dup系列函数, 常用的是dup2. 下面我们具体查看一下dup2的用法:
第一个参数名为newfd, 对应上面的1号fd, 第二个参数名是oldfd, 对应上面的新打开的文件。 也就是说将oldfd里面的内容拷贝到newfd里面。
dup2的使用——输出重定向
dup2可以直接将数组中的一个fd覆盖到另一个数组fd。 我们dup2的第一个参数是新打开的文件fd, 第二个参数是要拷贝到的fd的位置。
如下为代码:
运行结果如下:
我们也可以把清空写改成追加写:
运行结果如下:
dup2的使用——输入重定向

先创建一个数组进行拷贝拷贝, 然后向显示器中读取, 如果读取, 那么打印读取的内容。
此时是向键盘中读取:

我们使用dup2, 将新打开的文件覆盖到0号fd。 就是输入重定向, 将新打开的文件的数据打印:
如图就是将新打开文件的数据打印到inbuffer。 再将inbuffer的数据打印。 我们在log.txt里面写上aaaaaaaa

下面是打印内容:

自定义shell实现重定向指令
如何自己实现>, >>, < 指令
要自己实现>, >>, <指令, 我们就要拿出我们之前写的自定义shell的代码了。
在代码中, 我们需要先新定义几个宏——NONE代表没有重定向, IN_RDIR代表输入重定向, OUT_RDIR代表输入输出重定向, APPEND_RDIR代表追加重定向。
也要定义两个新的变量——rdirfilename指向重定向文件的首地址, rdir代表重定向的标志。
如下图宏定义:
新创建的变量:
在交互函数里面分析是否有重定向, check_rdir就是重定向判断的函数:
下图是check_rdir的实现:
然后我们再在执行普通命令的板块里面创建一个新的代码块。 也就是当id == 0的时候, 判断此时的rdir的状态, 如果是NONE才是exec, 正常加载执行逻辑。 如下是代码:
然后我们还要在每次输入指令的时候都给rdir和rdirfilename做初始化:

运行出结果之后:

文件的重定向和进程替换
现在有一个问题, 就是在重定向的时候, 我们修改了fd。 然后加载了子进程, 为什么这样做是正确的呢?——要解决这个问题, 就要拿起进程的知识了, 如下图:

在上面的图里面, PCB和文件管理, 是内核数据结构; 而虚拟地址空间, 物理内存, 页表, 是进程数据结构, 这两个是结偶关系。 而对于物理内存, 程序和代码加载替换掉物理内存, 页表重新映射物理内存。 这个过程, 在内核数据结构里, 并不关心。

所以, 文件的重定向和进程替换之间互不影响!!!
重定向的参数
我们使用重定向, 可能遇到下图这种只有一部分数据重定向到了新文件, 但是还有一部分直接打印到了显示器的情况:


上面描述的问题就是重定向了一部分, 但是还有一部分没有重定向, 这是因为对于重定向来说, 默认是将打印到显示器的数据重定向到文件中。
- 想要将两部分——stdout、stderr两个部分的数据都进行重定向, 就需要使用参数fd, 使用方式如下: fd > 文件。
如下图使用:
这两种方法我们要谈的是第二种方法:./newfile.exe 1 > both.log 2>&1, 这里面2>&1的意思就是说, 将1fd的内容拷贝到2fd里面去。 而1已经重定向到了both.log, 所以, 将1的内容拷贝到2fd里面去后。 本应该打印到2fd里面的内容也会被打印到文件中。
如何理解计算机下“一切皆文件”
对于计算机来说, 所有的操作计算机的动作, 都是以进程的方式进行操作的。所有访问文件的操作, 最终都是用进程的方式访问文件的。
计算机上所有应用的所有操作, 最终都会被系统解释成进程。 目前, 所有对文件的操作, 全部都依赖进程的操作。
而且, 我们知道, 对于冯诺依曼体系结构来说, 底层大部分都是外设!!!如下图:
上面就是一个一个打开文件后创建的结构体, 下面就是底层硬件。
- 对于上面图中的底层设备, 每一个外设的读写方法都是不一样的, 也就是他们的struct file是不一样的。 所以这个时候每一个struct file里面都有一个指针指向struct operation_func类型的结构体。
如下图:
那么, 未来操作系统为了进行文件操作, 就会先创建一个进程:
然后, 操作系统又专门给我们定义了系统调用:

所以, 操作系统就实现了在上层统一使用read, write接口, 然后在下层根据文件的不同, 找到不同的write, read方法。
所以, 一切皆文件——就是操作系统在文件层面上封装一层struct file结构体对象, 然后, 根据这个对象里面的指针找到对应文件的write, read。 而这里的write, read同样是一层封装各种各样读写方法的结构体。 而真正的各种设备的读写方法如何实现, 我们并不关心!!!
从struct file往上, 就是用户!是给我们看到的, 我们看到的, 就是struct file。 看到的就是——一切皆文件!!!
所以, 在linux中, 在struct file这一层, 被称作VFS——virtual file system虚拟文件系统。
- 以后, 当我们的进程再想实现open, write这些接口的时候, 就会先找到struct file。 然后struct file就回去找到自己里面的operation_func, 至于operation里面是什么情况, struct file并不关心。 而这, 就是多态。 这里面的一层一层的指针的包含关系, 就叫做继承!!
以上, 就是本节的全部内容, 下面是博主整理的个人笔记:





相关文章:
linux文件——重定向原理——dup、重定向与execl、VFS
前言:本篇讲解linux下的重定向相关内容。 在本篇中, 博主将会带着友友们一边实验, 一边探索底层原理。 通过本篇的学习, 友友们将会了解到重定向是如何实现的, 重定向的本质是什么, 重定向和进程替换之间的…...
【STM32 FreeRTOS】任务
使用 RTOS 的实时应用程序可以被构建为一组独立的任务。每个任务在自己的上下文中执行,不依赖于系统内的其他任务或 RTOS 调度器本身。在任何时间点,应用程序中只能执行一个任务,实时 RTOS 调度器负责决定所要执行的任务。因此, R…...
Java面试--框架--Spring MVC
Spring MVC 目录 Spring MVC1.spring mvc简介2.spring mvc实现原理2.1核心组件2.2工作流程 3.RESTful 风格4.Cookie,Session4.1 会话4.2 保存会话的两种技术 5.拦截器5.1过滤器、监听器、拦截器的对比5.2 过滤器的实现5.3 拦截器基本概念5.4 拦截器的实现 1.spring …...
土壤水分监测系统的工作原理
TH-TS200土壤水分监测系统是一种在地球科学、农学等领域广泛应用的分析仪器,它主要用于监测土壤中的水分含量,为农业生产、水资源管理、环境保护等提供重要数据支持。通常包括数据采集器、土壤水分传感器、土壤温度传感器(部分系统配备)、计算机软件以及…...
k8s学习--如何控制pod调度的位置
文章目录 一、Pod 调度基础二、通过节点选择器 (Node Selector) 控制调度三、使用节点亲和性 (Node Affinity)四、使用污点和容忍 (Taints and Tolerations)五、Pod 反亲和性 (Pod Anti-Affinity) 总结 在 Kubernetes (K8s)中,Pod 是应用运行的最小单位࿰…...
基于mysqldump的MySQL数据库异地备份方案(含完整脚本和解释)
MySQL数据库异地备份方案 0 文档描述 本文描述了一个数据库异地备份方案,以下脚本代码都是在线上应用的本文以CentOS7为例,其他系统请自行查询安装命令如果评论有需求,我就对应系统做一下文档 1 基本原理 1.1 流程 原理本身很简单&#…...
C语言中10个字符串函数详解
目录 1.strlen 2.strcpy 3.strcat 4.strcmp 5.strncpy 6.strncat 7.strncmp 8.strstr 9.strtok 10.strerror 1.strlen 基本结构:size_t strlen(const char *str);功能:用于计算字符串的长度;字符串已经 0作为结束标志…...
flume系列之:查询多个flume agent组是否有topic重复接入情况
flume系列之:查询多个flume agent组是否有topic重复接入情况 一、查询zk节点下的flume agent组二、获取采集的topic三、获取重复接入的topic,支持设置重复接入白名单四、执行流程五、完整代码一、查询zk节点下的flume agent组 def get_flumeAgent_zkPath(zkRootPaths):for z…...
Windows自动化1️⃣环境搭建WinAppDriver
对于技术选型: 我尝试了, pywinauto, WinAppDriver,CukeTest 担心CukeTest可能会收费, 尝试pywinauto,在元素点击,搜索时, 遇到不可用情况; WinAppDriver是微软家的,大厂开源, 就它了! 步骤一:安装WinAppDriver 进入WinAppDriver下载页面(https://githu…...
云服务器Docker内部署服务后,端口无法访问?
云服务器Docker内部署服务后,端口无法访问,可以按照以下思路进行排查: 以【docker run --name my-nginx -d -p 9395:80 nginx】举例: 查看Docker映射是否正确,可使用docker ps命令查看。Docker是否设置端口映射&#…...
Unity将摄像机视角保存成Json文件方便读取使用
系列文章目录 unity工具 文章目录 系列文章目录👉前言👉一、设置环境👉二、代码如下👉三、使用方法 👉四、下次外部调用json里面的摄像机位置的时候如下代码方法👉壁纸分享👉总结 👉…...
git是什么/基本指令
git作用 去中心化, 分布式版本控制器 新增术语:仓库区, 工作区, 暂存区 具体见下板书 常用git命令 git clone 仓库网址 git status 查看仓库状态 git add newfile 临时添加到git仓库 git commit -m 正式添加git仓库 g…...
Linux 中的同步机制
代码基于:Kernel 6.6 临界资源:指哪些在同一时刻只允许被一个线程访问的软件或硬件资源。这种资源的特点是,如果有线程正在使用,其他进程必须等待直到该线程释放资源。 临界区:指在每个线程中访问临界资源的那段代码。…...
Day17 枚举、typedef、位运算、堆空间的学习
目录 枚举 typedef 位运算 堆上的空间 枚举 一个一个列举出来,是指将变量的值一一列举出来,变量的值只限于列举出来的值的范围内。 作用: 1、为了提高代码的可读性 2、提高代码的安全性 枚举类型 基本语法: enum 枚举名 { …...
Python爬虫与数据分析:中国大学排名的深度挖掘
前言 👉 小编已经为大家准备好了完整的代码和完整的Python学习资料,朋友们如果需要可以扫描下方CSDN官方认证二维码或者点击链接免费领取【保证100%免费】 一、选题背景 高考作为中国学生生涯中最为重要的事,在高考之后,选择一所…...
微软开源库 Detours 详细介绍与使用实例分享
目录 1、Detours概述 2、Detours功能特性 3、Detours工作原理 4、Detours应用场景 5、Detours兼容性 6、Detours具体使用方法 7、Detours使用实例 - 使用Detours拦截系统库中的UnhandledExceptionFilter接口,实现对程序异常的拦截 C软件异常排查从入门到精通…...
js中的getElementById的使用方法
在JavaScript中,document.getElementById()是一种用于通过元素的id属性获取DOM元素的方法。它的作用是返回与指定id匹配的HTML元素。 使用document.getElementById()可以通过元素的id属性直接获取该元素的引用,然后可以使用该引用对元素进行各种操作。例…...
设计模式 - 桥接模式
💝💝💝首先,欢迎各位来到我的博客!本文深入理解设计模式原理、应用技巧、强调实战操作,提供代码示例和解决方案,适合有一定编程基础并希望提升设计能力的开发者,帮助读者快速掌握并灵活运用设计模式。 💝💝💝如有需要请大家订阅我的专栏【设计模式】哟!我会定…...
LeetCode530 二叉搜索树的最小绝对差
前言 题目: 530. 二叉搜索树的最小绝对差 文档: 代码随想录——二叉搜索树的最小绝对差 编程语言: C 解题状态: 成功解决! 思路 注意题目中的二叉搜索树,这个条件暗示每个节点的左子节点肯定小于该节点&am…...
【STM32 FreeRTOS】信号量与互斥锁
二值信号量 二值信号量的本质是一个队列长度为1的队列,该队列就只有空和满两种情况,这就是二值。 二值信号量通常用于互斥访问或任务同步,与互斥信号量比较类似,但是二值信号量有可能会导致优先级翻转的问题,所以二值…...
19c补丁后oracle属主变化,导致不能识别磁盘组
补丁后服务器重启,数据库再次无法启动 ORA01017: invalid username/password; logon denied Oracle 19c 在打上 19.23 或以上补丁版本后,存在与用户组权限相关的问题。具体表现为,Oracle 实例的运行用户(oracle)和集…...
stm32G473的flash模式是单bank还是双bank?
今天突然有人stm32G473的flash模式是单bank还是双bank?由于时间太久,我真忘记了。搜搜发现,还真有人和我一样。见下面的链接:https://shequ.stmicroelectronics.cn/forum.php?modviewthread&tid644563 根据STM32G4系列参考手…...
springboot 百货中心供应链管理系统小程序
一、前言 随着我国经济迅速发展,人们对手机的需求越来越大,各种手机软件也都在被广泛应用,但是对于手机进行数据信息管理,对于手机的各种软件也是备受用户的喜爱,百货中心供应链管理系统被用户普遍使用,为方…...
css实现圆环展示百分比,根据值动态展示所占比例
代码如下 <view class""><view class"circle-chart"><view v-if"!!num" class"pie-item" :style"{background: conic-gradient(var(--one-color) 0%,#E9E6F1 ${num}%),}"></view><view v-else …...
CMake基础:构建流程详解
目录 1.CMake构建过程的基本流程 2.CMake构建的具体步骤 2.1.创建构建目录 2.2.使用 CMake 生成构建文件 2.3.编译和构建 2.4.清理构建文件 2.5.重新配置和构建 3.跨平台构建示例 4.工具链与交叉编译 5.CMake构建后的项目结构解析 5.1.CMake构建后的目录结构 5.2.构…...
第25节 Node.js 断言测试
Node.js的assert模块主要用于编写程序的单元测试时使用,通过断言可以提早发现和排查出错误。 稳定性: 5 - 锁定 这个模块可用于应用的单元测试,通过 require(assert) 可以使用这个模块。 assert.fail(actual, expected, message, operator) 使用参数…...
【算法训练营Day07】字符串part1
文章目录 反转字符串反转字符串II替换数字 反转字符串 题目链接:344. 反转字符串 双指针法,两个指针的元素直接调转即可 class Solution {public void reverseString(char[] s) {int head 0;int end s.length - 1;while(head < end) {char temp …...
鸿蒙中用HarmonyOS SDK应用服务 HarmonyOS5开发一个医院查看报告小程序
一、开发环境准备 工具安装: 下载安装DevEco Studio 4.0(支持HarmonyOS 5)配置HarmonyOS SDK 5.0确保Node.js版本≥14 项目初始化: ohpm init harmony/hospital-report-app 二、核心功能模块实现 1. 报告列表…...
令牌桶 滑动窗口->限流 分布式信号量->限并发的原理 lua脚本分析介绍
文章目录 前言限流限制并发的实际理解限流令牌桶代码实现结果分析令牌桶lua的模拟实现原理总结: 滑动窗口代码实现结果分析lua脚本原理解析 限并发分布式信号量代码实现结果分析lua脚本实现原理 双注解去实现限流 并发结果分析: 实际业务去理解体会统一注…...
解决本地部署 SmolVLM2 大语言模型运行 flash-attn 报错
出现的问题 安装 flash-attn 会一直卡在 build 那一步或者运行报错 解决办法 是因为你安装的 flash-attn 版本没有对应上,所以报错,到 https://github.com/Dao-AILab/flash-attention/releases 下载对应版本,cu、torch、cp 的版本一定要对…...


























