一篇blog带你掌握重定向

20 篇文章 0 订阅
本文详细探讨了structfile内核对象的fd分配规则,以及如何利用dup2和标准输入输出重定向功能在shell编程中实现文件操作的控制。着重讲解了stdin、stdout和stderr的区别,以及如何通过C语言操作文件描述符实现数据流向的改变。
摘要由CSDN通过智能技术生成

理解struct file内核对象

一个structfile里面有内容+属性
在这里插入图片描述如何理解文件读写:
进程文件描述符表的第三步骤时才会对文件进行读写操作.

本质:对文件数据的读写====将内核中缓冲区的数据进行来回拷贝

fd的分配规则

在这里插入图片描述

返回值:实际返回读到的文件字符的长度
第一个参数:文件fd(文件描述符)
第二个参数:将读到的内容放入buf字符串
第三个参数:要读取的文件内容中的字符个数
向0号文件(stdin—键盘)读取---->read函数会以读的方式打开这个文件,
然后,等待键盘输入(这是stdin的特性)
打开0号文件,从0号文件向buf内读入1024个字节(以回车符结束)

在这里插入图片描述
在这里插入图片描述
1号文件的写入

在这里插入图片描述打开1号文件,向1号文件写入内容为buf,长度为strlen(buf)
在这里插入图片描述

在这里插入图片描述

结论1

在这里插入图片描述
当关闭1号文件时,那么打印信息不会输出,打开显示器的文件被关闭了
在这里插入图片描述
继续实验
在这里插入图片描述
在这里插入图片描述
关闭stdout文件,新文件创建文件描述符为stdout的文件描述符1
同时输出重定向,打印信息给了log.txt

结论2

结论3

在这里插入图片描述
新建文件的fd为1
printf()函数向文件名描述符为1的文件打印,只认1号文件,上层用户来说并不关心这个1是什么,所以只要修改1号位对应的文件,就能重定向
原先是显示器,现在是log.txt文件
所以完成重定向.
只需要修改文件描述符表中数组的下标所指向的文件即可

用fprintf()函数来验证(他可以指向文件进行输入)
在这里插入图片描述
按特定格式向指定文件输入:(不关闭1号文件演示)
在这里插入图片描述
在这里插入图片描述
现在关闭1号文件,再看fprintf()指向stdout输出的操作:
在这里插入图片描述
在这里插入图片描述
可以看到结果在log.txt’文件中,并不会在显示器输出

追加重定向只要open追加即可实现

重定向让读取数据从文件读取
上层:不变
下层:将文件描述符从0指向的stdin改为指定的文件
文件打开时的文件重定向为0
然后根据c语言的fread()函数进行内容写入,到stdin.
stdin的文件描述符0指向的是一个文件,所以写入实现
会写入到这个文件

补充

必选项(三种方式之间是互斥的)
O_RDONLY:只读打开--------rdonly
O_WRONLY:只写打开-------wrondly
O_RDWR:可读可写打开
可选项
O_APPEND:表示追加,加附到文件末尾,不覆盖原数据
O_CREAT:若此文件不存在则创建它,需提供第三个参数mode:表示该文件的访问权限
文件权限由open的mode参数和当前进程的umask掩码共同决定: mode&~umask
O_EXCL:如果同时指定了O_CREAT,并且文件已经存在,则出错返回
O_TRUNC:如果文件已经存在,则将其长度截断(Truncate)为0字节
O_NINBLOCK:设置文件为非阻塞状态

在这里插入图片描述
重点:
从stream中读取数据到buffer
读取的大小为nmeb,每次读取的字节大小为size
这边是:从stdin读取buffer个数据大小长度的数据,存到buffer中
对于C语言函数来说,确实是从stdin中读取,但是系统底层
是从stdini->fd:0文件中读取,现在这个0文件是log.txt
所以执行代码,会从这个log.txt文件读取

这个操作就是输入重定向

原理都是上层都不变
下层fd执行的文件进行改变

在这里插入图片描述

dup2的使用

在这里插入图片描述
以输出重定向为例:
在这里插入图片描述

dup2会保留oldfd
eg: dup2(fd,1);将fd和1 都指向fd所指的文件
原先1指向的文件OS会进行关闭

在这里插入图片描述在这里插入图片描述

重定向的实现

写入重定向

在这里插入图片描述

读取重定向

在这里插入图片描述

在这里插入图片描述
输入重定向本质:
command < input.txt
将文件的内容作为输入传递给命令

命令将从名为"input.txt"的文件中读取输入数据,而不是从键盘读取。

完善shell程序的重定向功能

往期手写shell

重定向检查

   //1.1检查重定向
    
     checkRedir(usercommand,strlen(usercommand));
    //2.分割字符串

函数实现:

#define SkipSpace(pos) do{while(isspace(*pos)) pos++;}while(0)
void checkRedir(char * command,int len)
{
  char* end = command + len - 1; 
  char* begin = command; 
  while(end > begin)
  {
    if(*(end) =='>')
    {
      if(*(end-1)=='>')
      {
        *(end-1)='\0';
        filename = end+1;
        SkipSpace(filename);
        redir = AppendRedir;
        break;
      }
      else{
        *(end)='\0';
        filename = end+1;
        SkipSpace(filename);
        redir = OutputRedir;
        break;
      }
    }
    else if(*(end)=='<')
    {
      *(end) = '\0';
      filename = end+1;
      SkipSpace(filename);
      redir = InputRedir;
      break;
    }
    else{
      end--;
    }
  }
}

在进行分割字符串之前就对这个字符串进行是否是重定向的检查
声明两个变量redir和filename
在cheakRedir函数中判断< >> >的个数
将判断的情况放在redir中,同时还会将这个用户输入的命令进行前后分割
即:会在文件和指令中间加上\0
然后,文件指令分给filename
指令继续是指令
后续工作交给执行指令的函数

检查完之后在执行指令的时候对重定向的文件进行test

int fd = 0;
      if(redir==InputRedir)
      {
        fd = open(filename,O_RDONLY);
        if(fd<0)
        {
          perror("open");
          return 1;
        }
        dup2(fd,0);
      }
      else if(redir==OutputRedir)
      {
             
        fd = open(filename,O_WRONLY | O_CREAT | O_TRUNC, 0666);
        if(fd<0)
        {
          perror("open");
          return 1;
        }
        dup2(fd,1);
      }
      else if(redir==AppendRedir)
      {

        fd = open(filename,O_WRONLY | O_CREAT | O_APPEND, 0666);
        if(fd<0)
        {
          perror("open");
          return 1;
        }
        dup2(fd,1);
      }
      else{
          //....
      }
      
      execvp(argv[0],argv);
      exit(1);
    }

在execute中,执行调用指令时,普通指令不进if条件
含有< >> > 的指令特殊处理
其中就包括存好的filename和不同的文件操作

然后在每次循环结束后,将这个redir和filename
进行初始化

filename = NULL;
    redir = 0;
    char usercommand[NUM];
    char *argv[SIZE];
    //int argc = 0;
    //1.印提示符&&获取用户命令字符串

探究stderr

#include<stdio.h>
int main()
{
fprintf(stdout,"output stdout\n");

fprintf(stderr,"output stderr\n");



  return 0;
}

stdout 和 stderr 都能向屏幕打印数据

在这里插入图片描述
区别:

输出重定向时:会改变1号文件的文件描述符指向的文件

在这里插入图片描述

欢迎三连支持,有问题可评论或者私信~

  • 19
    点赞
  • 18
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

温有情

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值