【Linux系统化学习】文件重定向

news2024/12/26 10:47:57

目录

文件内核对象

文件描述符的分配规则 

重定向

重定向的概念

dup2系统调用

输出重定向

追加重定向

输入重定向        

stderr解析

重定向到同一个文件中

分离常规输出和错输出


文件内核对象

上篇文章中我们介绍到了操作系统中的文件,操作系统为了方便管理进程打开的每个文件都会给每个文件创建一个内核对象(struct file)。但是每个进程可能打开多个进程,因此操作系统会形成一个数组,数组中的每个元素为文件内核对象指针指向当前进程打开的每个文件;数组的下标就代表一个打开的文件;对文件进行操作就是对数组的下标进行操作。打开的文件会加载在内存中,每个文件也都会有一段内存空间(文件缓冲区);打开文件会对文件进行操作,一般就是读操作和写操作;因此每个文件内核对象中一定含有这三种信息:

  • 打开文件的属性
  • 进行文件操作的方法集
  • 文件的内存空间(文件缓冲区)

总结:

  • 不能对磁盘中的内存进行操作,只能先将文件加载到内存中。
  • 对文件进行读数据和写数据都先要将文件加载到内存中(当文件不在内存中时会造成缺页中断,操作系统自动会将文件加载到内存中)。
  • 数据的读写本质是将内核缓冲区中的数据进行来回拷贝。

文件描述符的分配规则 

  1 #include<stdio.h>
  2 #include<sys/types.h>
  3 #include<sys/stat.h>
  4 #include<fcntl.h>
  5 #include<unistd.h>
  6 #include<string.h>
  7 #define FILE_NAME "log.txt"
  8 int main()
  9 {
 10 
 11     char buffer[1024];
 12     ssize_t s = read(0,buffer,1024);
 13     if(s>0)                                                              
 14     {
 15         buffer[s-1]=0;
 16         printf("echo# %s\n",buffer);
 17         write(1,buffer,strlen(buffer));
 18     }
 26     return 0;
 27 }

 

可以直接使用0和1文件描述符进行键盘和显示器的读写。 

    #include<stdio.h>
  2 #include<sys/types.h>
  3 #include<sys/stat.h>
  4 #include<fcntl.h>
  5 #include<unistd.h>
  6 #include<string.h>                                                       
  7 #define FILE_NAME "log.txt"
  8 int main()
  9 {
 10     int fd = open(FILE_NAME,O_CREAT|O_WRONLY|O_TRUNC,0666);
 11     if(fd<0)
 12     {
 13         perror("open");
 14         return 0;
 15     }                                                                    
 16     printf("fd:%d\n",fd);
        close(fd);
 17     return 0;
 18 }

 

上篇文章我们说过进程会默认打开三个流(stdin、stdout、stderr),分别为0,1,2。

文件描述符的分配规则:寻找最小的,没有被使用的数据的位置分配给指定的打开文件


重定向

重定向的概念

  • 改变原来系统命令的默认执行方式
  • Linux重定向是指修改原来默认的一些东西,对原来系统命令的默认执行方式进行改变,比如说简单的我不想看到在显示器的输出而是希望输出到某一文件中就可以通过Linux重定向来进行这项工作。

先执行一段代码,看现象:

    #include<stdio.h>
  2 #include<sys/types.h>
  3 #include<sys/stat.h>
  4 #include<fcntl.h>
  5 #include<unistd.h>
  6 #include<string.h>
  7 #define FILE_NAME "log.txt"
  8 int main()
  9 {
 10 
 11     close(1);
 12     int fd = open(FILE_NAME,O_CREAT|O_WRONLY|O_TRUNC,0666);
 13     if(fd<0)
 14     {
 15         perror("open");
 16         return 0;
 17     }
 18     printf("fd : %d \n",fd);
 19     printf("stdout->fd : %d \n",stdout->_fileno);
        fflush(stdout);
        close(fd)
        return 0;
    }

 

当我们不使用fflush刷新stdout时,显示器和新打开的文件都不会输出我们打印的内容,现象对应我们的第一张图片。使用fflush刷新stdout时,显示器不会输出我们的内容,但是新打开的文件中含有我们输出的内容。

现象的解释:进程运行是会打开我们的stdin、stdout、stderr,对应的文件描述符为0,1,2。当我我们关闭1,即关闭显示器。当新打开文件时根据文件描述符的分配规则文件描述符为1,但是printf、fprintf底层只认文件描述符1,但是此时的文件描述符已经不是stdout,而是新打开的文件,因此输出到新打开的文件中。

  1 #include<stdio.h>
  2 #include<sys/types.h>
  3 #include<sys/stat.h>
  4 #include<fcntl.h>
  5 #include<unistd.h>
  6 #include<string.h>
  7 #define FILE_NAME "log.txt"
  8 int main()
  9 {
 10 
 11     close(0);
 12     char buffer[1024];
 13     int fd = open(FILE_NAME,O_RDONLY);                                                                                                                   
 14     if(fd<0)
 15     {
 16         perror("open");
 17         return 0;
 18     }
 19     fread(buffer,1,sizeof(buffer),stdin);
 20     printf("%s\n",buffer);
        close(fd)
        return 0;
    }

 

根据上面的原理我们可以关闭0,即关闭从键盘输入;打开新文件,此时新文件的文件描述符为0,从新打开的文件中读取数据输入。 

dup2系统调用

通过上面的代码我们可以实现输入、输出重定向;但是需要我们手动关闭键盘或者显示器非常的麻烦,Linux中提供了系统调用,方便我们进行重定向。

  • 当调用dup函数时,内核在进程中创建一个新的文件描述符,此描述符是当前可用文件描述符的最小数值,这个文件描述符指向oldfd所拥有的文件表项。
  • dup2和dup的区别就是可以用newfd参数指定新描述符的数值,如果newfd已经打开,则先将其关闭。如果newfd等于oldfd,则dup2返回newfd, 而不关闭它。dup2函数返回的新文件描述符同样与参数oldfd共享同一文件表项。 

输出重定向

#include<stdio.h>
  2 #include<sys/types.h>
  3 #include<sys/stat.h>
  4 #include<fcntl.h>
  5 #include<unistd.h>
  6 #include<string.h>
  7 #define FILE_NAME "log.txt"
  8 int main()
  9 {
 10     int fd = open(FILE_NAME,O_CREAT|O_WRONLY|O_TRUNC,0666);
 11     if(fd<0)
 12     {
 13         perror("open");
 14         return 0;
 15     }
 16     dup2(fd,1);
 17     printf("fd : %d \n",fd);
 18     printf("stdout->fd : %d\n ",stdout->_fileno);
 19     printf("hello Linux\n");
 20     fprintf(stdout,"hello world\n");   
        close(fd);
        return 0;
    }             

  

使用系统调用进行重定向时,并不会像我们一样关闭键盘或者显示器而是创建新的文件描述符,然后让键盘或者显示器的文件描述符和键盘、显示器断开;和我们新打开的文件建立联系,此时这个文件就含有两个文件描述符,使用引用计数进行关闭文件。

追加重定向

#include<stdio.h>
  2 #include<sys/types.h>
  3 #include<sys/stat.h>
  4 #include<fcntl.h>
  5 #include<unistd.h>
  6 #include<string.h>
  7 #define FILE_NAME "log.txt"
  8 int main()
  9 {
 10     int fd = open(FILE_NAME,O_CREAT|O_WRONLY|O_APPEND,0666);
 11     if(fd<0)
 12     {
 13         perror("open");
 14         return 0;
 15     }
 16     dup2(fd,1);
 17     printf("fd : %d \n",fd);
 18     printf("stdout->fd : %d\n ",stdout->_fileno);
 19     printf("hello Linux\n");
 20     fprintf(stdout,"hello world\n");   
        close(fd);
        return 0;
    }    

输入重定向        

#include<stdio.h>
  2 #include<sys/types.h>
  3 #include<sys/stat.h>
  4 #include<fcntl.h>
  5 #include<unistd.h>
  6 #include<string.h>
  7 #define FILE_NAME "log.txt"
  8 int main()
  9 {
 10    // int fd = open(FILE_NAME,O_CREAT|O_WRONLY|O_APPEND,0666);
 11    int fd = open(FILE_NAME,O_RDONLY);                                    
 12     if(fd<0)
 13     {
 14         perror("open");
 15         return 0;
 16     }
 17     dup2(fd,0);
 18    // printf("fd : %d \n",fd);
 19    // printf("stdout->fd : %d\n ",stdout->_fileno);
 20    // printf("hello Linux\n");
 21    // fprintf(stdout,"hello world\n");
 22    char buffer[1024];
 23    fread(buffer , 1,1024,stdin);
 24    printf("%s",buffer);
       close(fd);
       return 0;
    }

stderr解析

上篇文章我们提到stdout和stderr,都代表显示器流即往显示器文件中打印。

#include<stdio.h>
int main()
{
    fprintf(stdout,"hello stdout\n");
    fprintf(stderr,"hello stderr\n");
    return 0;
}

 

但是我们进行重定向时只会将stdout进行重定向到文件中 ;stderr会在进程中保留。

因为fprintf底层只认文件描述符1,因此stderr不会被重定向。

重定向到同一个文件中

分离常规输出和错输出

进程运行时难免发生错误,输出错误信息;为了和常规信息进行区别,错误信息和常规信息分别独占一个显示器文件夹,我们只需要查看错误信息的显示器文件夹即可发现程序的报错信息。


今天对Linux下文件重定向的分享到这就结束了,希望大家读完后有很大的收获,也可以在评论区点评文章中的内容和分享自己的看法;个人主页还有很多精彩的内容。您三连的支持就是我前进的动力,感谢大家的支持!!! 

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

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

相关文章

react使用Map方法遍历列表不显示的问题

问题&#xff1a; 在最开始搭建选项卡的时候&#xff0c;我的js代码是这样的 import React, { Component } from react import ./css/02-maizuo.css export default class App extends Component {state {list: [{id: 1,text: 电影},{id: 2,text: 影院}, {id: 3,text: 我的}…

MySQL DQL 基本查询

一.概念 数据查询不应只是简单返回数据库中存储的数据&#xff0c;还应该根据需要对数据进行筛选以及确定数据以什么样的格式显示。 二.语法格式 select 列名 from 表 where 条件 1.查询所有的商品 select * from product; 2.查询商品名和商品价格 select pname,price from…

Quantitative Analysis: PIM Chip Demands for LLAMA-7B inference

1 Architecture 如果将LLAMA-7B模型参数量化为4bit&#xff0c;则存储模型参数需要3.3GB。那么&#xff0c;至少PIM chip 的存储至少要4GB。 AiM单个bank为32MB&#xff0c;单个die 512MB&#xff0c;至少需要8个die的芯片。8个die集成在一个芯片上。 提供816bank级别的访存带…

Docker 第十四章 : Docker 三剑客之 Machine

第十四章 : Docker 三剑客之 Machine 本章知识点: Docker Machine 是 Docker 三剑客之一,它是一个工具,允许用户在本地或远程机器上创建 Docker 主机。它简化了 Docker 环境的设置,特别是在不同的操作系统和云平台上。通过 Docker Machine,用户可以轻松地在虚拟机或物理…

《白话C++》第9章 泛型,Page842~844 9.4.2 AutoPtr

源起&#xff1a; C编程中&#xff0c;最容易出的问题之一&#xff0c;就是内存泄露&#xff0c;而new一个对象&#xff0c;却忘了delete它&#xff0c;则是造成内存泄露的主要原因之一 例子一&#xff1a; void foo() {XXXObject* xo new XXXObject;if(!xo->DoSomethin…

支付交易——跨境交易

摘要 老王兢兢业业经营生意多年&#xff0c;一步步从小杂货店做到现在&#xff0c;成立大型贸易公司。在做大做强的过程中&#xff0c;老王觉得国内市场已经饱和&#xff0c;竞争处处是红海。老王留意海外很多年了&#xff0c;决定走出去&#xff0c;转向海外:将国外的商品引进…

蓝桥杯官网填空题(寻找整数)

问题描述 本题为填空题&#xff0c;只需要算出结果后&#xff0c;在代码中使用输出语句将所填结果输出即可。 有一个不超过 10^17 的正整数 n&#xff0c;知道这个数除以 2 至 49 后的余数如下表所示&#xff0c;求这个正整数最小是多少。 运行限制 最大运行时间&#xff1a;…

C/C++重点解析——内存管理

1. C/C内存分布 我们先来看一段代码和其相关问题&#xff1a; int globalVar 1; static int staticGlobalVar 1; void Test() {static int staticVar 1;int localVar 1;int num1[10] { 1, 2, 3, 4 };char char2[] "abcd";const char* pChar3 "abcd"…

4 月 9 日至 4 月 10 日,Hack.Summit() 2024 首聚香江

Hack.Summit() 是一系列 Web3 开发者大会。2024 年的活动将于 2024 年 4 月 9 日至 4 月 10 日在香港数码港举行。自十年前首次举办以来&#xff0c;此次会议标志着 Hack.Summit() 首次在亚洲举办&#xff0c;香港被选为首次亚洲主办城市&#xff0c;这对 Hack VC 和该地区都具…

【大厂AI课学习笔记】【2.1 人工智能项目开发规划与目标】(4)数据准备的流程

今天学习的是数据准备的流程。 我们已经知道&#xff0c;数据准备占了AI项目超过一半甚至79%的时间。 那么数据准备&#xff0c;都做些什么&#xff0c;有哪些流程。 1.数据采集 观测数据人工收集调查问卷线上数据库 2.数据清洗 有缺失的数据有重复的数据有内容错误的数据…

Filezilla:文件无法传输的问题

问题 解决方法 我发现我站点管理器原本设置的是FTP, 改成了SFTP就可以正常传输 FTP和SFTP 安全通道&#xff1a;FTP不提供安全通道&#xff0c;SFTP提供安全通道。 传输协议&#xff1a;FTP使用TCP/IP协议&#xff0c;SFTP是SSH协议的一部分。 最后由于SFTP使用了加密解密技…

究极小白如何自己搭建一个自动发卡网站-独角数卡

本人从来没接触过建站&#xff0c;我之前都是在TB上花90叫别人给我搭建的网站&#xff0c;前几天这个TB店倒闭跑路了&#xff0c;而我的发卡网也打不开了&#xff0c;没办法&#xff0c;逼上梁山&#xff0c;自己捣鼓出来了&#xff01;下面是2023/4/2自己建好的&#xff01; …

Tampermonkey油猴用户脚本API文档

个人名片&#xff1a; &#x1f43c;作者简介&#xff1a;一名大三在校生&#xff0c;喜欢AI编程&#x1f38b; &#x1f43b;‍❄️个人主页&#x1f947;&#xff1a;落798. &#x1f43c;个人WeChat&#xff1a;hmmwx53 &#x1f54a;️系列专栏&#xff1a;&#x1f5bc;️…

Redis篇----第三篇

系列文章目录 文章目录 系列文章目录前言一、缓存雪崩**二、缓存穿透三、缓存预热四、缓存更新五、缓存降级 前言 前些天发现了一个巨牛的人工智能学习网站&#xff0c;通俗易懂&#xff0c;风趣幽默&#xff0c;忍不住分享一下给大家。点击跳转到网站&#xff0c;这篇文章男女…

【数据结构】二叉查找树和平衡二叉树,以及二者的区别

目录 1、二叉查找树 1.1、定义 1.2、查找二叉树的优点 1.2、查找二叉树的弊端 2、平衡二叉树 2.1、定义 2.2、 实现树结构平衡的方法&#xff08;旋转机制&#xff09; 2.2.1、左旋 2.2.2、右旋 3、总结 1、二叉查找树 二叉查找树又名二叉排序树&#xff0c;亦称二叉搜…

【Java程序员面试专栏 Java领域】Java虚拟机 核心面试指引

关于Java 虚拟机部分的核心知识进行一网打尽,主要包括Java虚拟机的内存分区,执行流程等,通过一篇文章串联面试重点,并且帮助加强日常基础知识的理解,全局思维导图如下所示 JVM 程序执行流程 包括Java程序的完整执行流程,以及Javac编译,JIT即时编译 Java程序的完整执…

2024年【A特种设备相关管理(电梯)】找解析及A特种设备相关管理(电梯)模拟考试

题库来源&#xff1a;安全生产模拟考试一点通公众号小程序 A特种设备相关管理&#xff08;电梯&#xff09;找解析是安全生产模拟考试一点通生成的&#xff0c;A特种设备相关管理&#xff08;电梯&#xff09;证模拟考试题库是根据A特种设备相关管理&#xff08;电梯&#xff…

NBA2K24 精品蔡徐坤面补

NBA2K24 精品蔡徐坤面补 NBA2K23-NBA2K24通用 精品蔡徐坤面补 下载地址&#xff1a; https://www.changyouzuhao.cn/13072.html

【JavaEE】_HTTP请求报头header

目录 1. Host 2. Content-Length与Content-Type 2.1 Content-Length 2.2 Content-Type 3. User-Agent&#xff08;UA&#xff09; 4. Referer 5. Cookie header的整体格式是“键值对”结构&#xff0c;一行是一个键值对&#xff0c;这些键值对都是HTTP定义好的、有特殊含…

【STM32 CubeMX】SPI W25Q64功能实现

文章目录 前言一、内部函数的实现1.1 选中和取消选中SPI Flash1.2 写使能函数1.3 获取读状态1.4 等待就绪状态 二、Flash读写函数实现2.1 读Flash ID2.2 擦除某个扇区2.3 写扇区2.4 读数据 三、测试代码总结 前言 SPI Flash 存储器在嵌入式系统中扮演着重要角色&#xff0c;它…