Linux文件系统——重定向

在这里插入图片描述

文章目录

    • 1. 文件描述符分配规则
    • 2. 重定向接口
      • dup2
      • 自定义shell重定向(补充)
    • 3. 标准输出和标准错误
    • 4. 如何理解一切接文件

本章代码gitee地址:文件重定向

1. 文件描述符分配规则

文件描述符的分配规则是从0下标开始,寻址最小的没有使用的数组位置,它的下标就是新文件的文件描述符。

我们来看一个现象:

#include<stdio.h>
#include<unistd.h>
#include<sys/types.h>
#include<sys/stat.h>
#include<fcntl.h>
#include<string.h>

#define filename "log.txt"
int main()
{
  close(1);
  int fd = open(filename,O_CREAT|O_WRONLY|O_TRUNC,0666);
  if(fd < 0)
  {
    perror("open");
    return 1;
  }

  const char *str = "hello linux\n";
  int cnt = 5;
  while(cnt--)
  {
    write(1,str,strlen(str));
  }
  close(fd);
  return 0;
}

这段代码本应该是想1号文件描述符写入,也就是向显示屏输出信息。我们将这个1号文件描述符指向的显示器文件关闭了,运行结果没有显示出来,这个符合预期。可是,我们发现原本应该向显示器文件写入的内容,却写进了log.txt这个文件。

image-20231107190948481

这个过程就叫做——输出重定向

我们将1号文件描述符关闭,将进程与显示器对应的关联关系去掉。这个1号位置就空出来了,然后我们重新打开一个文件,那么正好1号文件描述符指向的内容是空的,然后就与该文件建立关联关系,所以内容写入这个文件

2. 重定向接口

如果我们想将某个内容重定向,其实不需要我们自己每次都手动关闭某个文件描述符,再去覆盖,系统为我们还提供了一些接口。

dup2

man 2 dup2

image-20231109105208160

这里的并不是拷贝文件描述符,因为文件描述符只是一个数组的下标,本质上拷贝的是文件描述符指向的内容

#include<stdio.h>
#include<unistd.h>
#include<sys/types.h>
#include<sys/stat.h>
#include<fcntl.h>
#include<string.h>

#define filename "log.txt"
int main()
{
  //close(1);
  int fd = open(filename,O_CREAT|O_WRONLY|O_TRUNC,0666);
  if(fd < 0)
  {
    perror("open");
    return 1;
  }
  dup2(fd,1);
  close(fd);
  const char *str = "hello linux\n";
  int cnt = 5;
  while(cnt--)
  {
    write(1,str,strlen(str));
  }
  //close(fd);
  return 0;
}

image-20231109112020545

我们这里就能看到,原本应该向显示器文件输出的内容,重定向到了log.txt文件当中。

重定向的本质就是将文件描述表当中的文件地址做拷贝

自定义shell重定向(补充)

有了这些知识原理,就能写出自己的重定向代码

不了解的可以查看这篇文章——Linux实现简易shell

#define NONE -1
#define IN_RDIR 0
#define OUT_RDIR 1
#define APPEND_RDIR 2
char *rdirfilename = NULL;
int redir = NONE;

void check_redir(char *cmd)
{
  char *pos = cmd;
  while(*pos)
  {
    if(*pos == '>')
    {
      if(*(pos+1) == '>')
      {
        *pos++ = '\0';
        *pos++ = '\0';
        while(isspace(*pos))  pos++;
        rdirfilename = pos;
        redir = APPEND_RDIR;
        break;
      }
      else
      {
        *pos++ = '\0';
        while(isspace(*pos))  pos++;
        rdirfilename = pos;
        redir = OUT_RDIR;
        break;
      }
    }
    else if(*pos == '<')
    {
      *pos++ = '\0';
      while(isspace(*pos))  pos++;
      rdirfilename = pos;
      redir = IN_RDIR;
      break;
    }
    else
    {
      //不改变
    }
    pos++;
  }
}

void normalExcute(char *_argv[])
{
  pid_t id = fork();
  if(id < 0)
  {
    perror("fork fail");
    return; 
  }
  else if(id == 0)
  {
    //判断是否重定向
    int fd = 0;
    if(redir == IN_RDIR) //输入重定向
    {
      fd = open(rdirfilename,O_RDONLY);
      dup2(fd,0);
    }
    else if(redir == OUT_RDIR) //输出重定向
    {
      fd = open(rdirfilename,O_CREAT|O_WRONLY|O_TRUNC,0666);
      dup2(fd,1);
    }
    else if(redir == APPEND_RDIR)  //追加重定向
    {
      fd = open(rdirfilename,O_CREAT|O_WRONLY|O_APPEND,0666);
      dup2(fd,1);
    }
  
    //子进程执行命令
    //execvpe(_argv[0],_argv,environ);  //直接程序替换
    execvp(_argv[0],_argv);   //直接替换程序
    exit(EXIT_CODE);  //替换失败的退出码
  }
  else
  {
    //父进程等待子进程退出
    int status = 0;
    pid_t rid = waitpid(id,&status,0);  //阻塞等待
    if(rid == id)
    {
      lastcode = WEXITSTATUS(status);
    }
  }
}

这里的重定向并不会影响到之后的程序替换

因为这里的进程结构体或者是文件结构体,都是属于内核的数据结构,而我们的程序替换是由程序地址空间通过页表来进行一个替换,这也将程序替换和重定向工作进行了解耦

3. 标准输出和标准错误

标准输出stdou和标准错误stderr都是显示器文件输出内容,那他们这两个有什么区别呢

#include<stdio.h>
#include<unistd.h>
#include<sys/types.h>
#include<sys/stat.h>
#include<fcntl.h>
#include<string.h>

#define filename "log.txt"
int main()
{
  fprintf(stdout,"hello stdout\n");
  fprintf(stdout,"hello stdout\n");
  fprintf(stdout,"hello stdout\n");


  fprintf(stderr,"hello stderr\n");
  fprintf(stderr,"hello stderr\n");
  fprintf(stderr,"hello stderr\n");
  return 0;
}

这里我们运行,确实是发现,都是往显示器文件上输出内容

image-20231111192917656

但是如果我们重定向,这里发现往标准错误输入的内容并没有重定向到我们的目标文件当中,而标准输出的内容被重定向到了目标文件

image-20231111193053970

通过这里我们可以验证,>这个输出重定向的符合,默认就是将一个号文件描述符的内容重定向到目标

image-20231111193321663

但是我们也可以指定将几号文件描述符指向的内容重定向到目标文件当中

这里有个2>&1,意思就是将一号文件描述符的内容拷贝到二号文件描述符当中,让其和1指向同一个文件

4. 如何理解一切接文件

所以操作计算机的动作,都是以进程的形式进行操作的;所以访问文件的操作,也都是以进程的形式访问的。

在计算机里面,存在着各种设备,例如键盘、显示器、磁盘、网卡…,这些都被称之为外设

操作系统和这些外设打交道的时候,都需要它们所对应的方法,例如显示要有读的方法、键盘要有读写方法…每个外设都要有其对应读写方法,这个简称为IO

因为在linux下一切皆文件,所以在操作系统看来,这些外设都是文件,而访问文件的操作,都是以进程的形式访问。linux内核里面又提供了一个方法表的结构struct operation_func,这里面包含了一些函数指针,函数指针可以调用这些外设的读写方法。

每打开一个文件,就会为其创建一个方法集对象,而在struct file中,又包含了一些指针,其中就有一个可以指向这个方法集。

那么在进程创建的时候,进程有对应的文件描述符表,这个表就能指向这些文件,我们用户就提供系统调用,来访问这些文件。

所以从这个struct file往上,我们并不用关心底层访问的是什么东西,我们看到就是一切皆文件

image-20231111210255538

这里指针指向哪一个对象,就访问哪一个对象,这个不就是多态的逻辑吗?

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

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

相关文章

可以体现Python语法精妙的十个例子!

文章目录 前言1.for - else2.一颗星*和两颗星**3.三元表达式4.with - as5.列表推导式6.列表索引的各种骚操作7.lambda函数8.yield 以及生成器和迭代器9.装饰器10.巧用断言assertPython技术资源分享1、Python所有方向的学习路线2、学习软件3、精品书籍4、入门学习视频5、实战案例…

Linux JumpServer 堡垒机远程访问

文章目录 前言1. 安装Jump server2. 本地访问jump server3. 安装 cpolar内网穿透软件4. 配置Jump server公网访问地址5. 公网远程访问Jump server6. 固定Jump server公网地址 前言 JumpServer 是广受欢迎的开源堡垒机&#xff0c;是符合 4A 规范的专业运维安全审计系统。JumpS…

野火i.MX6ULL开发板检测按键evtest(Linux应用开发)

之前一直查找不到evtest&#xff0c;因为没有下载成功&#xff0c;很可能是网络不好&#xff0c;下次可以软件源可以换成国内大学镜像网站。 重新断开板子电源启动&#xff0c;再次连接网络&#xff0c;下载evtest成功&#xff01;&#xff01;

PHP中传值与引用的区别

在PHP中&#xff0c;变量的传递方式主要分为传值和传引用两种。这两种方式在操作中有一些重要的区别&#xff0c;影响着变量在函数调用或赋值操作中的表现。下面详细解释一下这两种传递方式的区别。 传值&#xff08;By Value&#xff09; 传值是指将变量的值复制一份传递给函…

VB.NET—Bug调试(参数话查询、附近语法错误)

目录 前言: BUG是什么&#xff01; 事情的经过: 过程: 错误一: 错误二: 总结: 前言: BUG是什么&#xff01; 在计算机科学中&#xff0c;BUG是指程序中的错误或缺陷&#xff0c;它通过是值代码中的错误、逻辑错误、语法错误、运行时错误等相关问题&#xff0c;这些问题…

CL-MVSNet论文精读

本文是对CL-MVSNet: Unsupervised Multi-View Stereo with Dual-Level Contrastive Learning Kaiqiang Xiong, Rui Peng, Zhe Zhang, Tianxing Feng, Jianbo Jiao, Feng Gao, Ronggang Wang的阅读记录 Proceedings of the IEEE/CVF International Conference on Computer Visio…

miniconda安装

1.下载&#xff1a; Miniconda — miniconda documentation 点击选择对应版本下载&#xff1a; 2.安装 点击next 注意&#xff01;&#xff01;&#xff01; 在选择为谁安装的时候建议选择just me&#xff08;这会让你构建的虚拟环境默认保存在安装路径的envs下&#xff0c…

Nacos入门到运行-超详细~windwos

&#x1f4da;目录 ⚙️简介:⚡️Nacos下载⌛解压到文件⚙️配置信息☘️修改 application.properties ⛵运行程序☘️安全问题☄️程序出现问题查看方式 ⛳Nacos开启鉴权⚡️跳过Token获取数据⚓接口请求&#xff1a; ✍️结束&#xff1a; ⚙️简介: Nacos:正如官网说的,一个…

使用 HTTP Client 轻松进行 API 测试

在开发过程中&#xff0c;我们经常需要测试 API 接口以确保其正常工作。JetBrains 的集成开发环境&#xff08;IDE&#xff09;如 CLion、IntelliJ IDEA、PyCharm 等&#xff0c;默认内置了 HTTP Client 插件&#xff0c;可以方便地进行API测试。本文将介绍如何使用HTTP Client…

人工智能与教育:未来的技术融合

人工智能与教育&#xff1a;未来的技术融合 随着科技的飞速发展&#xff0c;人工智能&#xff08;AI&#xff09;逐渐渗透到我们生活的方方面面&#xff0c;包括教育领域。AI与教育的结合&#xff0c;有望引发一场教育变革&#xff0c;提高教学效果&#xff0c;实现个性化学习&…

Python 列表元素里面含有字典或者列表进行排序

大家早好、午好、晚好吖 ❤ ~欢迎光临本文章 如果有什么疑惑/资料需要的可以点击文章末尾名片领取源码 示例1&#xff1a;列表里面含有列表进行排序 s [[1, 2], [100, 2], [33, 3], [25, 6]] s.sort(keylambda k: k[0]) print(s)结果&#xff1a; [[1, 2], [25, 6], [33, 3…

SplayTree高分测试用例

测试用例结果展示 覆盖率 变异得分 测试注意点 从SplayTree测起&#xff0c;然后再测SubSplayTree&#xff0c;因为前者调用后者。SplaySubTree的remove方法大部分内容需要通过反射才能测到。value和index在SplayTree当中都不是唯一的。一个index可能对应多个value。 不足之…

[西湖论剑 2022]real_ez_node

文章目录 前置知识EJS模板注入&#xff08;CVE-2022-29078&#xff09;原型链污染漏洞 &#xff08;CVE-2021-25928&#xff09;HTTP响应拆分攻击&#xff08;CRLF&#xff09; 解题过程代码审计构造payload 前置知识 EJS模板注入&#xff08;CVE-2022-29078&#xff09; EJS…

ChatGPT 如何改变科研之路

《Nature》全球博士后调查[1]中约有三分之一的受访者正在使用人工智能聊天机器人来帮助完善文本、生成或编辑代码、整理其领域的文献等等。 来自巴西的 Rafael Bretas 在日本生活了十多年&#xff0c;日语说得很好。书面日语的各个方面&#xff0c;例如严格的礼貌等级制度&…

【蓝桥每日一题]-快速幂,倍增,滑动窗口(保姆级教程 篇1) #麦森数 #青蛙跳

之前是考试准备&#xff0c;所以有几天没更新&#xff0c;今天开始继续更新 目录 快速幂模板 题目&#xff1a;麦森数 思路&#xff1a; 题目&#xff1a;青蛙跳 思路&#xff1a; 快速幂模板 #include <bits/stdc.h> #define ll long long using namespa…

如何知道一个程序为哪些信号注册了哪些信号处理函数?

https://unix.stackexchange.com/questions/379694/is-there-a-way-to-know-if-signals-are-present-in-your-application-and-which-sign 使用 strace

数据结构与算法【二分查找】Java实现

需求&#xff1a;在有序数组 A 内&#xff0c;查找值target 如果找到返回索引如果找不到返回 -1 前提 给定一个内含 n 个元素的有序数组 A&#xff0c;一个待查值 target 1 设置 i0&#xff0c;jn-1 2 如果 i \gt j&#xff0c;结束查找&#xff0c;没找到 3 设置 m (…

只会CRUD程序员朋友,你开始拥抱云计算技术了吗

阅读建议 嗨&#xff0c;伙计&#xff01;刷到这篇文章咱们就是有缘人&#xff0c;在阅读这篇文章前我有一些建议&#xff1a; 本篇文章大概6000多字&#xff0c;预计阅读时间长需要6分钟。本篇文章的理论性较强&#xff0c;是一篇质量分数较高的技术文章&#xff0c;建议收藏…

STM32F407的看门狗

文章目录 看门狗时钟两种看门狗IWDG结构图作用 寄存器IWDG_KR键值寄存器IWDG_PR预分频寄存器2-0 PR预分频器系数 IWDG_RLR重装载寄存器IWDG_SR状态寄存器1RVU 重载值更新0 PVU 预分频值更新注意 写保护超时时间使用步骤取消寄存器 写保护设置预分频系数和重装载值看门狗溢出时间…

阿里云服务器搭建sql 服务

阿里云搭建mysql服务 环境准备 系统镜像 ubuntu 如果买点的实例不是ubuntu 系统镜像&#xff0c;需要停止服务之后&#xff0c;更改镜像 更新 apt-get &#xff1a; 更新apt-get: sudo apt-get update 如果没有出现&#xff1a;apt-get 找不到此命令的错误&#xff0c;可能是…