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

2024-02-18 10:52

本文主要是介绍【Linux系统化学习】文件重定向,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

目录

文件内核对象

文件描述符的分配规则 

重定向

重定向的概念

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

这篇关于【Linux系统化学习】文件重定向的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/720931

相关文章

HarmonyOS学习(七)——UI(五)常用布局总结

自适应布局 1.1、线性布局(LinearLayout) 通过线性容器Row和Column实现线性布局。Column容器内的子组件按照垂直方向排列,Row组件中的子组件按照水平方向排列。 属性说明space通过space参数设置主轴上子组件的间距,达到各子组件在排列上的等间距效果alignItems设置子组件在交叉轴上的对齐方式,且在各类尺寸屏幕上表现一致,其中交叉轴为垂直时,取值为Vert

Ilya-AI分享的他在OpenAI学习到的15个提示工程技巧

Ilya(不是本人,claude AI)在社交媒体上分享了他在OpenAI学习到的15个Prompt撰写技巧。 以下是详细的内容: 提示精确化:在编写提示时,力求表达清晰准确。清楚地阐述任务需求和概念定义至关重要。例:不用"分析文本",而用"判断这段话的情感倾向:积极、消极还是中性"。 快速迭代:善于快速连续调整提示。熟练的提示工程师能够灵活地进行多轮优化。例:从"总结文章"到"用

【前端学习】AntV G6-08 深入图形与图形分组、自定义节点、节点动画(下)

【课程链接】 AntV G6:深入图形与图形分组、自定义节点、节点动画(下)_哔哩哔哩_bilibili 本章十吾老师讲解了一个复杂的自定义节点中,应该怎样去计算和绘制图形,如何给一个图形制作不间断的动画,以及在鼠标事件之后产生动画。(有点难,需要好好理解) <!DOCTYPE html><html><head><meta charset="UTF-8"><title>06

linux-基础知识3

打包和压缩 zip 安装zip软件包 yum -y install zip unzip 压缩打包命令: zip -q -r -d -u 压缩包文件名 目录和文件名列表 -q:不显示命令执行过程-r:递归处理,打包各级子目录和文件-u:把文件增加/替换到压缩包中-d:从压缩包中删除指定的文件 解压:unzip 压缩包名 打包文件 把压缩包从服务器下载到本地 把压缩包上传到服务器(zip

学习hash总结

2014/1/29/   最近刚开始学hash,名字很陌生,但是hash的思想却很熟悉,以前早就做过此类的题,但是不知道这就是hash思想而已,说白了hash就是一个映射,往往灵活利用数组的下标来实现算法,hash的作用:1、判重;2、统计次数;

Linux 网络编程 --- 应用层

一、自定义协议和序列化反序列化 代码: 序列化反序列化实现网络版本计算器 二、HTTP协议 1、谈两个简单的预备知识 https://www.baidu.com/ --- 域名 --- 域名解析 --- IP地址 http的端口号为80端口,https的端口号为443 url为统一资源定位符。CSDNhttps://mp.csdn.net/mp_blog/creation/editor

【Python编程】Linux创建虚拟环境并配置与notebook相连接

1.创建 使用 venv 创建虚拟环境。例如,在当前目录下创建一个名为 myenv 的虚拟环境: python3 -m venv myenv 2.激活 激活虚拟环境使其成为当前终端会话的活动环境。运行: source myenv/bin/activate 3.与notebook连接 在虚拟环境中,使用 pip 安装 Jupyter 和 ipykernel: pip instal

零基础学习Redis(10) -- zset类型命令使用

zset是有序集合,内部除了存储元素外,还会存储一个score,存储在zset中的元素会按照score的大小升序排列,不同元素的score可以重复,score相同的元素会按照元素的字典序排列。 1. zset常用命令 1.1 zadd  zadd key [NX | XX] [GT | LT]   [CH] [INCR] score member [score member ...]

【机器学习】高斯过程的基本概念和应用领域以及在python中的实例

引言 高斯过程(Gaussian Process,简称GP)是一种概率模型,用于描述一组随机变量的联合概率分布,其中任何一个有限维度的子集都具有高斯分布 文章目录 引言一、高斯过程1.1 基本定义1.1.1 随机过程1.1.2 高斯分布 1.2 高斯过程的特性1.2.1 联合高斯性1.2.2 均值函数1.2.3 协方差函数(或核函数) 1.3 核函数1.4 高斯过程回归(Gauss