【Linux初阶】基础IO - 简易 shell添加重定向功能

🌟hello,各位读者大大们你们好呀🌟
🍭🍭系列专栏:【Linux初阶】
✒️✒️本篇内容:shell重定向功能的代码实现
🚢🚢作者简介:计算机海洋的新进船长一枚,请多多指教( •̀֊•́ ) ̖́-


文章目录

  • 前言
  • 一、Makefile文件
  • 二、shell代码修改(添加重定向功能)
    • 1.指令切割
    • 2.需要子进程实现重定向
    • 3.重定向代码填充(整体代码展示)
    • 4.运行展示
      • (1)输出重定向
      • (2)追加重定向
      • (3)输入重定向
  • 三、重定向不会影响父进程
  • 四、重定向不会影响程序替换
  • 结语


前言

本篇博客主要讲述 shell重定向功能的代码实现,其他简易shell的基础功能实现可查看作者这篇文章 -> 【Linux初阶】进程替换的应用 - 简易命令行解释器的实现

有对重定向基础概念和实现不清楚的同学可以看这篇文章 -> 【Linux初阶】基础IO - 文件管理(深入理解文件描述符) | 重定向


一、Makefile文件

myshell:myshell.cgcc - o $@ $ ^ -std = c99 # - DDEBUG
.PHONY:clean
clean :rm - f myshell

二、shell代码修改(添加重定向功能)

1.指令切割

实现重定向前,先要对指令做分割

  • “ls -a -l -i > myfile.txt” -> “ls -a -l -i” “myfile.txt” ->
  • “ls -a -l -i >> myfile.txt” -> “ls -a -l -i” “myfile.txt” ->
  • “cat < myfile.txt” -> “cat” “myfile.txt” ->

该段代码需要添加在,指令获取且去除 \n 之后

#define NONE_REDIR   0 //宏定义类型
#define INPUT_REDIR  1
#define OUTPUT_REDIR 2
#define APPEND_REDIR  3#define trimSpace(start) do{\                   //trimSpace过滤函数的实现while(isspace(*start)) ++start;\    //isspace判断*start是不是空格,是就++跳过}while(0)                               //isspace - #include <ctype.h>int redirType = NONE_REDIR; // 定义初始类型
char* redirFile = NULL;// "ls -a -l -i > myfile.txt" -> "ls -a -l -i" "myfile.txt" ->
void commandCheck(char* commands)
{assert(commands);char* start = commands; //定义指令检索始末位char* end = commands + strlen(commands);while (start < end) //合法范围内循环遍历{if (*start == '>'){*start = '\0';start++;if (*start == '>'){// "ls -a >> file.log"redirType = APPEND_REDIR; start++;}else{// "ls -a >    file.log"redirType = OUTPUT_REDIR; }trimSpace(start); //trimSpace过滤函数redirFile = start;break;}else if (*start == '<'){//"cat <      file.txt"*start = '\0';  //对指令进行拆分start++;trimSpace(start); //trimSpace过滤函数(实现在上面),对 *start指向的空格进行过滤// 填写重定向信息redirType = INPUT_REDIR;redirFile = start;break;}else{start++;}}
}// "ls -a -l -i > myfile.txt" -> "ls -a -l -i" "myfile.txt" ->
// "ls -a -l -i >> myfile.txt" -> "ls -a -l -i" "myfile.txt" ->
// "cat < myfile.txt" -> "cat" "myfile.txt" ->
commandCheck(lineCommand);

———— 我是一条知识分割线 ————

2.需要子进程实现重定向

原来的子进程执行代码

if (id == 0)
{execvp(myargv[0], myargv); exit(1);
}

修改后的子进程执行代码

if (id == 0)
{// 因为命令是子进程执行的,真正重定向的工作一定要是子进程来完成// 如何重定向,是父进程要给子进程提供信息的// 这里重定向会影响父进程吗?不会,进程具有独立性switch (redirType) //根据不同类型,执行不同的功能{case NONE_REDIR:// 什么都不做break;case INPUT_REDIR:{int fd = open(redirFile, O_RDONLY); //调用open系统接口,需要三个头文件(可自行查看)if (fd < 0) {perror("open");exit(errno);}// 重定向的文件已经成功打开了dup2(fd, 0); //dup2接口实现输入重定向}break;case OUTPUT_REDIR:case APPEND_REDIR: //两个合封在一起{umask(0);int flags = O_WRONLY | O_CREAT; //写入和创建if (redirType == APPEND_REDIR) flags |= O_APPEND; //追加下添加flagelse flags |= O_TRUNC; //不是追加要清空int fd = open(redirFile, flags, 0666);if (fd < 0){perror("open");exit(errno);}dup2(fd, 1); //dup2接口实现输出重定向}break;default:printf("bug?\n");break;}execvp(myargv[0], myargv); // 执行程序替换的时候,会不会影响曾经进程打开的重定向的文件?不会exit(1);
}

———— 我是一条知识分割线 ————

3.重定向代码填充(整体代码展示)

由于重定向是由子进程进行的,进程每次运行完需要恢复 redirType、redirFile、errno,防止被第二次运行的子进程再次使用上一次的端口数据。

        redirType = NONE_REDIR;redirFile = NULL;errno = 0;

我们可以将上述代码添加到,总的循环开始的地方,即 main函数的 while后。

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include <ctype.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <sys/wait.h>
#include <assert.h>
#include <errno.h>#define NUM 1024
#define OPT_NUM 64#define NONE_REDIR   0
#define INPUT_REDIR  1
#define OUTPUT_REDIR 2
#define APPEND_REDIR  3#define trimSpace(start) do{\while(isspace(*start)) ++start;\}while(0)char lineCommand[NUM];
char* myargv[OPT_NUM]; //指针数组
int  lastCode = 0;
int  lastSig = 0;int redirType = NONE_REDIR;
char* redirFile = NULL;// "ls -a -l -i > myfile.txt" -> "ls -a -l -i" "myfile.txt" ->
void commandCheck(char* commands)
{assert(commands);char* start = commands;char* end = commands + strlen(commands);while (start < end){if (*start == '>'){*start = '\0';start++;if (*start == '>'){// "ls -a >> file.log"redirType = APPEND_REDIR;start++;}else{// "ls -a >    file.log"redirType = OUTPUT_REDIR;}trimSpace(start);redirFile = start;break;}else if (*start == '<'){//"cat <      file.txt"*start = '\0';start++;trimSpace(start);// 填写重定向信息redirType = INPUT_REDIR;redirFile = start;break;}else{start++;}}
}int main()
{while (1){redirType = NONE_REDIR;redirFile = NULL;errno = 0;// 输出提示符printf("用户名@主机名 当前路径# ");fflush(stdout);// 获取用户输入, 输入的时候,输入\nchar* s = fgets(lineCommand, sizeof(lineCommand) - 1, stdin);assert(s != NULL);(void)s;// 清除最后一个\n , abcd\nlineCommand[strlen(lineCommand) - 1] = 0; // ?//printf("test : %s\n", lineCommand);// "ls -a -l -i" -> "ls" "-a" "-l" "-i" -> 1->n// "ls -a -l -i > myfile.txt" -> "ls -a -l -i" "myfile.txt" ->// "ls -a -l -i >> myfile.txt" -> "ls -a -l -i" "myfile.txt" ->// "cat < myfile.txt" -> "cat" "myfile.txt" ->commandCheck(lineCommand);// 字符串切割myargv[0] = strtok(lineCommand, " ");int i = 1;if (myargv[0] != NULL && strcmp(myargv[0], "ls") == 0){myargv[i++] = (char*)"--color=auto";}// 如果没有子串了,strtok->NULL, myargv[end] = NULLwhile (myargv[i++] = strtok(NULL, " "));// 如果是cd命令,不需要创建子进程,让shell自己执行对应的命令,本质就是执行系统接口// 像这种不需要让我们的子进程来执行,而是让shell自己执行的命令 --- 内建/内置命令if (myargv[0] != NULL && strcmp(myargv[0], "cd") == 0){if (myargv[1] != NULL) chdir(myargv[1]);continue;}if (myargv[0] != NULL && myargv[1] != NULL && strcmp(myargv[0], "echo") == 0){if (strcmp(myargv[1], "$?") == 0){printf("%d, %d\n", lastCode, lastSig);}else{printf("%s\n", myargv[1]);}continue;}// 测试是否成功, 条件编译
#ifdef DEBUGfor (int i = 0; myargv[i]; i++){printf("myargv[%d]: %s\n", i, myargv[i]);}
#endif// 内建命令 --> echo// 执行命令pid_t id = fork();assert(id != -1);if (id == 0){// 因为命令是子进程执行的,真正重定向的工作一定要是子进程来完成// 如何重定向,是父进程要给子进程提供信息的// 这里重定向会影响父进程吗?不会,进程具有独立性switch (redirType){case NONE_REDIR:// 什么都不做break;case INPUT_REDIR:{int fd = open(redirFile, O_RDONLY);if (fd < 0) {perror("open");exit(errno);}// 重定向的文件已经成功打开了dup2(fd, 0);}break;case OUTPUT_REDIR:case APPEND_REDIR:{umask(0);int flags = O_WRONLY | O_CREAT;if (redirType == APPEND_REDIR) flags |= O_APPEND;else flags |= O_TRUNC;int fd = open(redirFile, flags, 0666);if (fd < 0){perror("open");exit(errno);}dup2(fd, 1);}break;default:printf("bug?\n");break;}execvp(myargv[0], myargv); // 执行程序替换的时候,会不会影响曾经进程打开的重定向的文件?不会exit(1);}int status = 0;pid_t ret = waitpid(id, &status, 0);assert(ret > 0);(void)ret;lastCode = ((status >> 8) & 0xFF);lastSig = (status & 0x7F);}
}

4.运行展示

将简易shell代码进行编译,形成可运行文件并运行

(1)输出重定向

将 ls -a -l 的内容重定向输出到 log.txt 文件中

在这里插入图片描述

(2)追加重定向

将 ls 的内容追加到 log.txt 中

在这里插入图片描述

(3)输入重定向

将文件 log.txt 中的内容重定向输入到 cat中

在这里插入图片描述


三、重定向不会影响父进程

重定向会影响父进程吗?不会,进程具有独立性

通过上面的代码我们可以知道,重定向是在子进程中运行的,在子进程重定向之前,它会将父进程的 task_struct 和 files_strcut都拷贝一份,用于对文件的操作,但是不需要将存储文件属性或文件内容的数据块再拷贝一次。

在这里插入图片描述


四、重定向不会影响程序替换

上图中所有的操作都属于内核数据结构的范畴,而程序替换替换的是代码和数据,和内核数据结构不是一个东西,它们相互之前并没有关系,因此重定向并不会影响程序替换。

在这里插入图片描述


结语

🌹🌹 Linux下简易 shell添加重定向功能 的知识大概就讲到这里啦,博主后续会继续更新更多C++ 和 Linux的相关知识,干货满满,如果觉得博主写的还不错的话,希望各位小伙伴不要吝啬手中的三连哦!你们的支持是博主坚持创作的动力!💪💪

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://xiahunao.cn/news/351883.html

如若内容造成侵权/违法违规/事实不符,请联系瞎胡闹网进行投诉反馈,一经查实,立即删除!

相关文章

惊人的磁场定律:你是谁,就会遇见谁

作者&#xff1a;洞见ADC 生命里的磁场无法被看见&#xff0c;但它却在改变我们的人生。 点我 物理学上存在万有引力定律&#xff0c;即自然界任何两个物体&#xff0c;都是存在相互吸引的。 人与人之间&#xff0c;也不例外。 朗达拜恩在《力量》中写道&#xff1a; “每个人身…

基于RPC协议的接口自动化测试可以用Python语言实现

基于RPC协议的接口自动化测试可以用Python语言实现。下面是实现步骤&#xff1a; 1、安装依赖库&#xff0c;如protobuf、grpc。 2、编写.proto文件定义接口参数和返回值。 3、使用protoc编译.proto文件生成Python代码。 4、编写客户端代码调用远程接口进行测试。 具体实现…

【软件测试】cookie、session和token的区别

今天就来说说session、cookie、token这三者之间的关系&#xff01;最近这仨玩意搞得头有点大 为什么会有它们三个 我们都知道 HTTP 协议是无状态的&#xff0c;所谓的无状态就是客户端每次想要与服务端通信&#xff0c;都必须重新与服务端链接&#xff0c;意味着请求一次客户…

阿宝的成长记录

宝宝需要减肥了&#xff0c;翻身有点困难&#xff01;

阿宝的生日礼物

阿宝的生日蛋糕很好吃&#xff0c;很难的事情&#xff0c;在任何时候&#xff0c;都会有自己的判断和想法。

图片主色调提取

本文主要阐述用传统图像处理的手段来解决RGB图的颜色量化问题&#xff1b; 简单解释下颜色量化&#xff0c;一张RGB图&#xff0c;图上每个像素点分别有R、G、B三个分量&#xff0c;每个分量由一个字节表示&#xff0c;那么颜色空间大小是256^3。显然人眼观测的时候&#xff0…

如何获得完美的调色板?完美的配色素材专辑拿走!

第1步--原色和系统色 从一个主色开始&#xff0c;根据喜好、研究颜色含义来确定。 选择的主色是品牌色。 一旦有了主色&#xff0c;就需要文字、背景、容器等的颜色。 通常情况下&#xff0c;会选择一个深色的颜色&#xff0c;用于文本&#xff0c;而背景则是浅灰色的颜色。…

Seaborn的调色板(palette)

Seaborn的调色板&#xff08;palette&#xff09; Seaborn可以很容易地使用适合数据特征和可视化目标的颜色。本章讨论了指导您选择的一般原则和帮助您快速找到给定应用程序的最佳解决方案的seaborn工具。 由于我们眼睛的工作方式&#xff0c;一种特定的颜色可以用三个成分来定…

图片色调识别

图片色调识别 色调定义色调提取方法中位切分法RGB与色调 色调定义 (1) 暖色调温暖与热烈是暖色的基调。当人们见到红、橙、黄、红紫等暖色调后&#xff0c;比较容易联想到太阳、火焰、热血等事物&#xff0c;会有温暖、欢乐、刺激等感觉。按照给人温暖感觉的强度有高到低排序:…

Haishoku识别图片主色调和配色方案

对于图片分析&#xff0c;一直觉得很高大上&#xff0c;从来不动这方面。今天翻看python weekly&#xff0c;发现一个很有趣的库-Haishoku。 简介 haishoku 是一个日语词, 意思是配色. Haishoku 是一个用来获取图片主色调和主要配色方案的python库&#xff0c;依赖于python3和…

半色调技术

这个主要是为了对付作业&#xff0c;对各处找到的资料缝缝补补的整合&#xff0c;因为比较杂乱&#xff0c;已经忘记是在哪儿看到大佬们的文章了&#xff0c;整理一下思路。 背景 半色调图像如常见的印刷品图像&#xff0c;其由浅到深或由淡到浓的变化&#xff0c;是靠网点面…

DaVinci:调色版本

调色版本 Grade Version记录着片段的全部调色信息。 将一种调色风格或效果&#xff0c;保存为一个调色版本&#xff0c;从而可在多个调色版本之间查看、比较、挑选或者渲染输出。 调色版本类型 本地版本 Local Versions 在没有创建新的调色版本之前&#xff0c;片段的调色信息默…

seaborn库调色板color设置【知识整理】

seaborn库的使用&#xff08;color设置&#xff09; 综述代码模块调色板分类色板&#xff08;离散&#xff09;颜色的亮度及饱和度颜色对比xkcd选取颜色连续色板&#xff08;连续&#xff09;cubehelix_palette调色板RGB值选取颜色 小结 综述 学生党整理一些关于数据分析的知识…

转载之色调映射

一、概述 虽然HDR 图像有较大的动态范围&#xff0c;能更细致地反映真实场景&#xff0c;但他的缺点也很明显。一是同尺寸的数据比低动态范围图像大&#xff0c;需要更大的存储空间与传输带宽。二是难以输出&#xff0c;目前大多数显示器、打印机等图形输出设备的动态范围要比普…

Windows OpenGL 图像色调

目录 一.OpenGL 图像色调调节 1.原始图片2.效果演示 二.OpenGL 图像色调调节源码下载三.猜你喜欢 零基础 OpenGL ES 学习路线推荐 : OpenGL ES 学习目录 >> OpenGL ES 基础 零基础 OpenGL ES 学习路线推荐 : OpenGL ES 学习目录 >> OpenGL ES 特效 零基础 OpenGL…

【PHP】识别图片主色调

一、适用情景&#xff1a;如http://www.teapic.com/list.htm&#xff0c;根据颜色列出相应图片。 二、主程序及API解释&#xff1a; <?phpclass MajorColor {//参考颜色protected $_colors null;//容差protected $_tolerance 80;//忽略的颜色protected $_ignoreColors a…

色调列表

NamedNumericColor NameHex RGBDecimal LightPink浅粉红#FFB6C1255,182,193 Pink粉红#FFC0CB255,192,203 Crimson猩红 (深红)#DC143C220,20,60 LavenderBlush淡紫红#FFF0F5255,240,245 PaleVioletRed弱紫罗兰红#DB7093219,112,147 HotPink热情的粉红#FF69B4255,105,180 DeepPin…

图片调色学习

色相环 色相混合正红&#xff08;0&#xff09;正黄&#xff08;60&#xff09;&#xff0c;透明度为&#xff08;50%&#xff09;即红黄等比例混合橙色&#xff08;30&#xff09; (060&#xff09;/230 真实调整透明度混合出并不一定为两者均值的色相,需要选择不同的混合方法…

Seaborn--调色板(二)

调色板 颜色很重要 color_palette()能传入任何Matplotlib所支持的颜色 color_palette()不写参数则默认颜色 set_palette()设置所有图的颜色import numpy as np import seaborn as sns import matplotlib.pyplot as plt %matplotlib inline sns.set(rc{"figure.figsize&qu…