【Linux】文件重定向与实现支持文件重定向的minishell


目录

0.前提

​编辑

1.重定向

1.1重定向的本质

1.2dup2

1.3模拟实现输出重定向 >

1.4模拟实现追加重定向 >>

1.5模拟实现输入重定向 <

2.让minishell支持重定向


0.前提

文件描述符的分配规则:

在文件描述符表里面,从小到大按照顺序寻找最小的且没有被占用的fd。


1.重定向

1.1重定向的本质

上层使用的fd不变,在内核中更改fd对应的struct file*的地址。

1.2dup2

让newfd变成oldfd的拷贝,如果需要关闭newfd.

1.3模拟实现输出重定向 >

1.4模拟实现追加重定向 >>

1.5模拟实现输入重定向 <

2.让minishell支持重定向

#include<stdio.h>
#include<string.h>
#include<assert.h>
#include<unistd.h>
#include<sys/types.h>
#include<sys/wait.h>
#include<fcntl.h>
#include<stdlib.h>
#include<sys/stat.h>
#include<errno.h>

#define B_NUM 1024
#define ARGV_NUM 10
#define NONE_REDIR 0
#define INPUT_REDIR 1
#define OUTPUT_REDIR 2
#define APPEND_REDIR 3



char buffer[B_NUM];
char* myargv[ARGV_NUM];
int quitcode=0;
int quitsignal=0;

int redirType=NONE_REDIR;
char* refilename=NULL;


void Commandcheck(char* command)
{
  assert(command);
  //判断是否有重定向,有是哪种
  char* begin=command;
  char* end=command+sizeof command-1;
  
  while(begin<end)
  //while((*begin)!='\0')
  {
    if(*begin=='>')
    {
      *begin='\0';
      begin++;
      if(*begin=='>')
      {
         redirType=APPEND_REDIR;
         begin+=2;
         refilename=begin;
      }
      else{
        redirType=OUTPUT_REDIR;
        refilename=(++begin);
        break;
      }
    }
    if(*begin=='<')
    {
      *begin='\0';
       redirType=INPUT_REDIR;
       begin+=2;
       refilename=begin;
       break;
    }
    begin++;
  }
  return ;
}

int main()
{

  while(1)
  {
    redirType=NONE_REDIR;
    refilename=NULL;
    errno=0;
   
    printf("【用户名@服务器 当前目录】$");
    fflush(stdout);

    char* s=fgets(buffer,sizeof (buffer)-1,stdin);
    assert(s!=NULL);
    buffer[strlen (buffer)-1]=0;
    (void)s;
   
    //和重定向区分开
    Commandcheck(buffer);
    
   // printf("切割成功:命令 %s 文件 %s\n",buffer,refilename);


    //切割字符串
    myargv[0]=strtok(buffer," ");
    int i=0;

    if(myargv[0] != NULL && strcmp(myargv[0], "ls") == 0)
    {
      myargv[++i] = (char*)"--color=auto";
    }

    while(myargv[i]!=NULL)
    {
      myargv[++i]=strtok(NULL," ");
    }

    //实现cd功能
    if(myargv[0] != NULL &&strcmp(myargv[0],"cd")==0)
    {
      if(myargv[1]!=NULL)
      {

        chdir(myargv[1]);
      }
      continue;
    }
    //实现echo $?功能
    if(myargv[0]!=NULL&&myargv[1]!=NULL&&strcmp(myargv[0],"echo")==0)
    {
      if(strcmp(myargv[1],"$?")==0)
      {
        //输出上一个进程的退出码
        printf("退出码为:%d\n",quitcode);

      }
      else
      {
        printf("%s\n",myargv[1]);
      }
      continue;

    }

    pid_t id =fork();
    assert(id!=-1);
    if(id==0)
    {
      //子进程

      //如果有文件打开文件
      switch(redirType)
      {
        case NONE_REDIR:
          break;
        case INPUT_REDIR:
          {
          int fd=open(refilename,O_RDONLY);
            if(fd < 0){           
               perror("open");
               exit(errno);
            }
          dup2(fd,0);
          }
          break;
        case OUTPUT_REDIR:
        case APPEND_REDIR:
          {
            
          int flag=O_WRONLY|O_CREAT;
          if(redirType==OUTPUT_REDIR)
          {
            flag|=O_TRUNC;
          }
          else{
            flag|=O_APPEND;
          }
          umask(0);
          int fd=open(refilename,flag,0666);
            if(fd < 0){            
               perror("open");
               exit(errno);
            }
          dup2(fd,1);
          }
          break;
       default:
          break;

      }


      //程序替换
      execvp(myargv[0],myargv); 
      //如果走到这里表示替换失败
      exit(1);
    }

   //父进程
   int status=0;
   pid_t ret= waitpid(id,&status,0);
   assert(ret > 0);
   (void)ret;
   quitcode=(status>>8)&0XFF;
   quitsignal= (status & 0x7F);

  }
  return 0;
}

注意:每次父进程循环都要记得刷新 redirType 、redirFile、errno 


最后

加油

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

windows10 powershell多个选项卡

您可以使用下载新的 Windows 终端&#xff0c;新的终端是可以开启多个选项卡的 Windows Terminal - Microsoft Appshttps://apps.microsoft.com/detail/9N0DX20HK701?hlen-us&glUS

使用Pycharm安装Python的库

1.点击文件-----设置&#xff08;setting&#xff09; 2.找到Python解释器&#xff0c;点击加号 3.搜索你需要的库&#xff0c;安装

利用k8s Infra 容器,解决pod网络故障注入的问题

目录 一、infra容器作用 二、pod网络故障注入问题 三、充分利用pod infra容器 一、infra容器的作用 我们知道&#xff0c;在kubernetes中&#xff0c;pod中容器的资源隔离主要通过namespace和cgroup来实现。那如果我们需要为pod中的容器共享某种资源应该怎么做。kubernetes …

91.网游逆向分析与插件开发-游戏窗口化助手-游戏窗口化助手的UI设计

内容参考于&#xff1a;易道云信息技术研究院VIP课 上一个内容&#xff1a;项目需求与需求拆解-CSDN博客 码云地址&#xff08;游戏窗口化助手 分支&#xff09;&#xff1a;https://gitee.com/dye_your_fingers/sro_-ex.git 码云版本号&#xff1a;e512d44da1b7e6a8726b1be0…

用GOGS搭建GIT服务器

GOGS官网 Gogs: A painless self-hosted Git service 进入文件所在目录 cd /usr/local/develop 解压文件 tar -xvf gogs_0.13.0_linux_amd64.tar.gz 解压之后 进入gogs 目录 cd gogs 创建几个目录 userdata 存放用户数据 log文件存放进程日志 repositories 仓库根目…

docker 网络模型

一、docker的网络模型分为四种 【1】Host(与宿主机共享一个网络)&#xff0c;宿主机的localhost 及 容器内的localhost 【2】Bridge(与宿主机共享一个局域网&#xff0c;有自己的网络&#xff1b;docker运行默认Bridge)&#xff1b;容器内localhost不是宿主机localhost 【3】…

Scrapy:Python中强大的网络爬虫框架

Scrapy&#xff1a;Python中强大的网络爬虫框架 在当今信息爆炸的时代&#xff0c;从互联网上获取数据已经成为许多应用程序的核心需求。Scrapy是一款基于Python的强大网络爬虫框架&#xff0c;它提供了一种灵活且高效的方式来提取、处理和存储互联网上的数据。本文将介绍Scrap…

初始数据库

华子目录 什么是数据库DBMS&#xff08;数据库管理系统&#xff09;数据库系统和文件系统的区别文件系统数据库系统对比区别优缺点总结 常见数据库关系型数据库ACID原则关系型数据库的优缺点优点缺点 非关系型数据库存储方式常见的非关系型数据库非关系型数据库的优缺点优点缺点…

docker 构建个人博客网站

1、项目地址 https://gitee.com/hhll/blog-hangliang.git 2、打包docker镜像并上传docker hub 【1】注册docker hub账号https://hub.docker.com/ 【2】在docker hub建对应的仓库 【3】登录docker hub并打包上传前后端镜像 sudo docker login -u xxxx 密码 xxxxxx 后端&am…

Sklearn、TensorFlow 与 Keras 机器学习实用指南第三版(五)

原文&#xff1a;Hands-On Machine Learning with Scikit-Learn, Keras, and TensorFlow 译者&#xff1a;飞龙 协议&#xff1a;CC BY-NC-SA 4.0 第十二章&#xff1a;使用 TensorFlow 进行自定义模型和训练 到目前为止&#xff0c;我们只使用了 TensorFlow 的高级 API&#…

栈--数据结构

初始化栈、入栈、出栈 栈&#xff1a;只允许在一端进行插入或删除操作的线性表 栈顶&#xff08;Top&#xff09; 代码实战步骤依次是初始化栈&#xff0c;判断栈是否为空&#xff0c;压栈&#xff0c;获取栈顶元素&#xff0c;弹栈。 代码 #include <stdio.h>#define …

安卓平台valgrind交叉编译

背景 通过上次的文章valgrind跨平台调试及其问题分析,为同事们在大部分平台下进行内存问题分析提供了帮助。但是也遇到了阻塞情况&#xff1a;android 平台&#xff0c;无法交叉编译通过。大家对于编译这件事&#xff0c;似乎天然有一种排斥&#xff0c;本能的拒绝&#xff0c…

微信小程序checkbox多选

效果图 <view class"block"><view class"header"><view class"header-left"><text class"pu-title">数据</text><text class"pu-tip">至少选择一个指标</text></view>&l…

JS 基本语句

函数调用&#xff0c;分支&#xff0c;循环&#xff0c;语句示例。 <!DOCTYPE html> <html lang"en"><head><meta charset"UTF-8"><meta name"viewport" content"widthdevice-width, initial-scale1.0"&g…

如何在Vue应用程序中使用Vue-Router来实现路由嵌套动画效果

Vue-Router是Vue.js官方的路由管理插件&#xff0c;可以帮助我们轻松管理应用程序的路由。除了基本的路由功能外&#xff0c;Vue-Router还允许我们在切换路由时添加动画效果&#xff0c;提升用户体验。本文将介绍如何使用Vue-Router来实现路由嵌套动画效果&#xff0c;并提供具…

vscode 括号 python函数括号补全

解决方法 在setting.json中添加 “python.analysis.completeFunctionParens”: true 打开设置&#xff1b; 点击图中按钮打开setting.json文件 添加 “python.analysis.completeFunctionParens”: true

在 iOS 上安装自定企业级应用

了解如何安装您的组织创建的自定应用并为其建立信任。 本文适用于学校、企业或其他组织的系统管理员。 您的组织可以使用 Apple Developer Enterprise Program 创建和分发企业专用的 iOS 应用&#xff0c;以供内部使用。您必须先针对这些应用建立信任后&#xff0c;才能将其打…

电气器件系列四十六:固态继电器规格参数

ssr选型的时候&#xff0c;要和温控器的参数对应起来&#xff0c;我选的温控器&#xff08;ai-207d1g&#xff09;上&#xff0c;明确给出了给ssr的电压数据&#xff08;5vdc&#xff0c;30ma&#xff09;&#xff0c;买的这个ssr(ssr40n)是3-32v&#xff0c;8ma的. 关断电压&a…

Elasticsearch:使用 Inference API 进行语义搜索

在我之前的文章 “Elastic Search 8.12&#xff1a;让 Lucene 更快&#xff0c;让开发人员更快”&#xff0c;我有提到 Inference API。这些功能的核心部分始终是灵活的第三方模型管理&#xff0c;使客户能够利用当今市场上下载最多的向量数据库及其选择的转换器模型。在今天的…

IDEA如何进行远程Debug调试(二)解决jar包运行报错的问题

一、解决jar包运行报错的问题 上文提到在进行debug远程调试的时候&#xff0c;打包后的jar包本地无法运行&#xff0c;报如下的错误 ​​​​​​​IDEA如何进行远程Debug调试-CSDN博客 查看报错是找不到对应的类&#xff0c;那么我们使用jd-gui的反编译工具&#xff0c;看看…