【基础IO】-4-再谈重定向
再谈重定向1、实验中的有趣现象2、重新理解重定向3、直接完成重定向的系统调用——dup4、完善自主shell——加入重定向操作1、实验中的有趣现象还记得我们验证文件描述符fd分配规则的实验吗我们当时是关闭了0号文件流stdin然后新建文件发现新建文件的fd是0。假如我们关闭fd 1的文件呢#includestdio.h#includeunistd.h#includesys/types.h#includesys/stat.h#includefcntl.hintmain(){close(1);// 关闭stdoutintfdopen(log.txt,O_CREAT|O_WRONLY,0666);printf(log.txt: %d\n,fd);fflush(stdout);close(fd);return0;}本该写入到屏幕上的信息却写入到了新建的log.txt中——这不就是输出重定向吗所以我们通过关闭fd 1的文件再新建文件然后用printf企图向标准输出流中做写入结果内容写入到了文件log.txt从而间接地完成了输出重定向的工作。2、重新理解重定向操作系统是只认文件描述符fd的文件操作相关的系统调用几乎都需要fd的参与。标准输出流stdout底层封装的文件描述符fd是fd 1。未来我们想要对标准输出流做写入默认是写入到文件描述符为fd 1的文件中的。现在关闭了fd 1的文件即关闭了stdout标准输出流。然后我们新建文件log.txt打开log.txt返回的文件描述符就是fd 1。而想要继续向标准输出流做写入的时候由于操作系统只认fd 1的文件流为标准输出流所以就会去打开文件表fd_array中找下标为1的文件结果找到了log.txt。以上就是输出重定向的全过程。输出重定向的本质是做标准输出的时候进程只会写入到文件描述符fd 1的文件当中默认情况下是stdout标准输出流(打开文件表)fd_array中下标为 1 的文件由stdout变为了用户指定的文件。同理追加输出重定向的本质与输出重定向的非常相似。它们的唯一的区别是输出重定向会清空历史内容追加输出重定向不会清空只会在文件内容的末尾继续写入。类似的输入重定向的本质是做标准读取的时候进程只会读取文件描述符fd 0的文件默认情况下是stdin标准输入流(打开文件表)fd_array中下标为 1 的文件由stdin变为了用户指定的文件。3、直接完成重定向的系统调用——dup重定向操作本质上是(打开文件表)fd_array中file*指针的交换即文件描述符fd作为fd_array数组的下标对应的file*指针的交换。如果我们采用上面的“关闭文件再打开”的方式显得比较麻烦。Linux为我们提供了一个操作系统——dup。intdup2(intoldfd,intnewfd);系统调用dup的作用是关闭当前newfd指向的文件将oldfd上的file*指针拷贝给newfd。所以输出重定向可以这样用dup实现#includestdio.h#includeunistd.h#includesys/types.h#includesys/stat.h#includefcntl.hintmain(intargc,char*argv[]){intfdopen(log.txt,O_CREAT|O_WRONLY|O_TRUNC,0666);// 不追加是O_TRUNC(清空)dup2(fd,1);printf(%s\n,argv[1]);close(fd);return0;}追加输出重定向可以这样用dup实现#includestdio.h#includeunistd.h#includesys/types.h#includesys/stat.h#includefcntl.hintmain(intargc,char*argv[]){intfdopen(log.txt,O_CREAT|O_WRONLY|O_APPEND,0666);// 追加是O_APPENDdup2(fd,1);printf(%s\n,argv[1]);close(fd);return0;}输入重定向可以这样用dup实现#includestdio.h#includeunistd.h#includesys/types.h#includesys/stat.h#includefcntl.hintmain(){intfdopen(log.txt,O_RDONLY,0666);dup2(fd,0);inta0;floatf0.0f;charc0;scanf(%d %f %c,a,f,c);printf(%d %f %c\n,a,f,c);close(fd);return0;}学会使用dup之后我们就可以继续完善我们自主实现的shell即加上重定向操作。4、完善自主shell——加入重定向操作注意我们当前加入的重定向操作是只针对普通命令即需要bash创建子进程执行的命令的重定向操作。往自主shell中加入重定向操作需要经过以下两个步骤完善执行命令函数Execute。定义全局的标识符redir_type表示重定向操作的具体选项不重定向#define NONE_REDIR 0输入重定向#define IN_REDIR 1输出重定向#define OUT_REDIR 2追加输出重定向#define NONE_REDIR 3以后在Execute中检测redir_type发生的变化若redir_type 0不做任何操作若redir_type 1检测到需要做输入重定向stdin流换成指定文件流dup2(fd, 0)若redir_type 2检测到需要做输出重定向stdout流换成指定文件流dup2(fd, 1)若redir_type 3检测到需要做追加输出重定向stdout流换成指定文件流dup2(fd, 1)添加函数Redir对从用户方读取的命令字符串做预处理看看字符串中有没有 以设置redir_type定义全局的重定向文件名redir_filename提取字符串中重定向操作符右侧的文件名写入redir_filename// Execute中创建子进程的部分elseif(0id){intfd0;if(IN_REDIRredir_type){fdopen(redir_filename,O_RDONLY);dup2(fd,0);}elseif(OUT_REDIRredir_type){fdopen(redir_filename,O_CREAT|O_WRONLY|O_TRUNC,0666);dup2(fd,1);}elseif(APP_REDIRredir_type){fdopen(redir_filename,O_CREAT|O_WRONLY|O_APPEND,0666);dup2(fd,1);}else{// do nothing}execvp(argv[0],argv);exit(12);}voidBash(){staticchar*env[256];_environenv;LoadEnv();while(1){PrintPrompt();GetCommandLine();if(0strlen(commandline))continue;Redir();// 获取用户输入后先对可能包含的重定向操作做处理再分析命令ParseCommandLine();if(CheckBuildinAndExecute())continue;Execute();}}staticvoidRedir(){char*startcommandline;char*endcommandline[strlen(commandline)1];// 左闭右开while(start!end){if(*start){if(*(start1)){redir_typeAPP_REDIR;*start\0;start2;}else{redir_typeOUT_REDIR;*start\0;start;}Clear_Left_Space(start);// 宏替换的技巧1. 直接写不利于观察。2. 写成函数要传二级指针// 过滤空格找到重定向的文件名redir_filenamestart;break;}elseif(*start){redir_typeIN_REDIR;*start\0;start;Clear_Left_Space(start);redir_filenamestart;break;}else{start;}}}处理重定向操作的函数Redir就很有讲究。首先是寻找重定向操作符设置redir_type。定义char*指针start遍历输入字符串遇到就是输入重定向遇到如果start下一位也是那么就是追加输出重定向否则就只是输出重定向设置完redir_type之后我们可以将重定向操作符改写成\0这样做是对用户输入字符串做“切割”切出操作符之前的命令(这样后续在解析函数ParseCommandLine中strtok遇到\0就会停下)。再然后就要提取redir_filename。我们可以使start跳过操作符继续向后找文件名。而操作符之后可能直接就是文件名也可能是许多前导空格所以我们需要做一个循环操作过滤掉空格直接写循环吗太冗余了代码看起来不太简洁。而且这个循环操作以后可能还要用外部设计成一个函数吗那就要传递二级指针才不会因为传值拷贝而不能对start进行修改这里就涉及到一个编程技巧将此处的循环操作设计成一个宏(替换)。#defineClear_Left_Space(pos)do{\while(isspace(*pos))\pos;\}while(0)宏的本质就是替换代码在预处理阶段就会用这段循环操作替换Clear_Left_Space同时do{}while(0)中套while循环可以防止宏函数直接跟;造成的实际循环未执行的情况发生。当start找到了一个非空的字符意味着找到了文件名。就可以设置redir_filename。添加重定向操作还有一个重要的一点一定要在下一次输入命令之前重置redir_type redir_filename不然会发生意想不到的问题。代码演示

相关新闻

线圈天线设计实战:从电感计算到匹配调试的完整经验

线圈天线设计实战:从电感计算到匹配调试的完整经验

简介:这是面向无线通信、广播、雷达等领域工程师与学习者的线圈天线设计综合资料包,聚焦天线原理、线圈参数、微波仿真、阻抗匹配、频率选择性、材料选型与工程环境等核心问题,帮助读者系统掌握设计方法与排错思路。压缩包共3个文件&#xff…

2026/10/17 14:30:15 阅读更多 →
永磁同步电机直接转矩控制(DTC)的Simulink建模与调参实战

永磁同步电机直接转矩控制(DTC)的Simulink建模与调参实战

简介:面向永磁同步电机控制方向的研究生、工程师与仿真爱好者,这份MATLAB/Simulink完整仿真模型聚焦改进型直接转矩控制(DTC)方法,可用于理解电磁转矩与磁链滞环控制的核心逻辑,并在此基础上完成参数整定与…

2026/10/17 14:29:14 阅读更多 →
2025算法变革元年:LFM模型与低参数量部署的行业落地指南

2025算法变革元年:LFM模型与低参数量部署的行业落地指南

简介:这份《2024网信自主创新调研报告》PDF面向关注AI技术演进的科技从业者、研究人员及企业管理者,聚焦非Transformer架构与算法变革趋势。报告系统梳理了LFM(Liquid Foundation Model)等新型模型的兴起,以及DeepSeek…

2026/10/17 14:29:14 阅读更多 →

最新新闻

HTML游戏代码包本地部署指南:从白屏到中文汉化全流程

HTML游戏代码包本地部署指南:从白屏到中文汉化全流程

简介:《Degrees of Lewdity》中文版安装指南代码包,是一份面向中文玩家与入门开发者的本地化配置参考。它围绕这款文本冒险游戏的汉化安装,系统梳理了从环境准备、仓库克隆、依赖安装到Mod加载器配置的完整链路,适合想亲手复现中文…

2026/10/17 15:16:52 阅读更多 →
Unity如何自动找到并调用Start/Update?内部机制解析

Unity如何自动找到并调用Start/Update?内部机制解析

有人问了一个看起来特基础、仔细想又说不清的问题:Unity引擎到底是怎么知道某个MonoBehaviour子类里有Start方法,然后在正确时机自动调用的?刚入门的同学觉得这事挺玄学——脚本里写了个Start,引擎就跟约定好了一样,在…

2026/10/17 15:16:52 阅读更多 →
Unity五子棋人机对战实战:AI落子算法与坐标换算全解析

Unity五子棋人机对战实战:AI落子算法与坐标换算全解析

做五子棋练手,是Unity入门中期特别合适的项目。棋盘、落子交互、回合管理、胜负判定、AI决策,一套流程下来什么关键环节都覆盖了,难度又比象棋围棋低不少,不会一上来就被搜索树和评估函数劝退。这篇就把Unity人机五子棋从零到能玩…

2026/10/17 15:16:52 阅读更多 →
LayaAir 2-Cmd与VSCode环境协同配置指南

LayaAir 2-Cmd与VSCode环境协同配置指南

1. 为什么“LayaAir 2-Cmd VSCode”组合容易让人反复重装环境LayaAir 2.x 是国内某跨平台游戏引擎团队在2019年前后主推的轻量级H5/小程序/小游戏开发框架,其核心设计目标是让前端开发者能用熟悉的TypeScript和Web开发思维快速产出可多端发布的2D内容。而LayaAir 2…

2026/10/17 15:16:52 阅读更多 →
从零实现一个Android简单计算器:布局、逻辑与状态管理详解

从零实现一个Android简单计算器:布局、逻辑与状态管理详解

不少刚接触Android开发的朋友,想找个能顺手练完整个基础链路的项目,第一反应多半是“做个计算器”。它没有复杂的网络请求,也不需要设计数据库表,但要真正把一个能用的计算器做出来,你需要把界面布局、按钮事件、状态切…

2026/10/17 15:16:52 阅读更多 →
Python爬虫技术

Python爬虫技术

前言 「爬虫技术」听起来像一个独立学科,拆开看其实就是三件事:发出 HTTP 请求拿到响应、从响应里抽出结构化数据、把数据存下来并决定下一次抓哪里。Python 之所以成了爬虫的主流语言,不是语言本身有什么魔法,而是标准库把这三件…

2026/10/17 15:15:52 阅读更多 →

日新闻

DeepSeek选型与部署:V3/R1、Ollama、API全攻略

DeepSeek选型与部署:V3/R1、Ollama、API全攻略

简介:《DeepSeek使用方法.pdf》是一份面向DeepSeek入门及进阶用户的完整使用指南,重点围绕V3与R1两款模型的能力差异与适用场景展开,帮助读者根据任务类型与成本选择合适的模型。资源共1个PDF文件,压缩包大小约311KB,篇…

2026/10/17 0:00:25 阅读更多 →
200+Deepseek润色指令拆解:从底层原理到场景落地的完整指南

200+Deepseek润色指令拆解:从底层原理到场景落地的完整指南

简介:这是一份聚焦DeepSeek提示词优化的《200Deepseek润色指令》PDF文档,共收录两百余条可直接套用的润色指令,涵盖语法修正、风格统一、逻辑梳理、表达精炼等维度,并针对商务写作、学术论文、广告文案等场景给出差异化建议。文档…

2026/10/17 0:00:25 阅读更多 →
OpenCV轮廓法物体计数系统:轻量、可控、可落地的工业级实现

OpenCV轮廓法物体计数系统:轻量、可控、可落地的工业级实现

简介:本资源是一份基于OpenCV的本科课程设计完整报告,面向计算机视觉初学者、图像处理学习者及高校通信/信息类专业学生,解决物体智能计数与检测结果结构化记录的实际问题。项目覆盖图像预处理、轮廓检测、边界框绘制、轨迹栏交互式参数调节、…

2026/10/17 0:00:25 阅读更多 →

周新闻

流感时间序列预测实战:ARIMA/LSTM全流程拆解与避坑指南

流感时间序列预测实战:ARIMA/LSTM全流程拆解与避坑指南

简介:基于 ARIMA、LSTM、Transformer 等模型的流感时间序列预测 Python 源码,面向计算机相关专业课程设计与期末大作业学生,以及项目实战学习者。内容覆盖预处理、平稳性检验、定阶、残差分析、多模型对比预测的完整时序建模流程,…

2026/10/16 21:35:51 阅读更多 →
影刀RPA新手教程:键盘模拟输入实战——输入文本与模拟按键的区别

影刀RPA新手教程:键盘模拟输入实战——输入文本与模拟按键的区别

影刀RPA新手教程:键盘模拟输入实战——输入文本与模拟按键的区别 做影刀RPA自动化,十个新手有八个栽在"往输入框里填东西"这件事上:要么填不进去,要么填了一半,要么直接把原来内容追加在后面。这背后的根因&…

2026/10/17 1:44:59 阅读更多 →
影刀RPA新手教程:阅文起点小说数据采集实战——书籍信息与章节内容

影刀RPA新手教程:阅文起点小说数据采集实战——书籍信息与章节内容

影刀RPA新手教程:阅文起点小说数据采集实战——书籍信息与章节内容 1. 认识影刀:什么场景该用RPA采小说数据 起点中文网的页面结构相对稳定——分类榜单、书籍详情、章节内容三块独立页面,跳转链路清晰。这种场景非常适合影刀自动化&#x…

2026/10/16 15:04:24 阅读更多 →

月新闻

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/16 21:54:38 阅读更多 →
Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/16 3:49:43 阅读更多 →
黑夜航拍船只数据集训练YOLOV5模型全流程解析

黑夜航拍船只数据集训练YOLOV5模型全流程解析

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/16 14:23:36 阅读更多 →