Linux 之 【文件】(重定向、一切皆文件的理解)

目录

1.重定向

1.1引入

1.2dup2

1.3原理

1.4重定向的实现

1.5重定向与进程替换

2.2重定向示例

2.文件描述符1与2

3.一切皆文件的理解


1.重定向

1.1引入

首先使用close接口关闭文件描述符为1的文件(起初是标准输出文件)

然后open函数打开一个文件,根据最小未使用文件描述符策略,该文件的文件描述符为1

接着向文件描述符为1的文件写入5条信息

最后再关闭open函数打开的文件

这样就实现了输出重定向的非常搓的版本(先关闭再打开):原本向标准输出文件写入的内容变为了写入filename文件当中

1.2dup2

实现输入输出追加重定向,调用dup2函数即可,这样就不用先关闭再打开了

类别 详情
函数原型 #include <unistd.h> int dup2(int oldfd, int newfd);
功能描述 将文件描述符 oldfd 复制到 newfd,使两者指向同一文件表项。若 newfd 已打开,则先关闭它。
参数说明 - oldfd:源文件描述符(必须有效且已打开)。 - newfd:目标文件描述符(可指定,范围通常为 [0, OPEN_MAX-1])。
返回值 - 成功:返回 newfd。 - 失败:返回 -1,并设置 errno(如 EBADFEMFILE)。

(1)输出重定向

(2)追加重定向

(3)输入重定向

1.3原理

文件描述符实质上是进程文件描述符表fd_array[]的数组下标,表中存储的是指向内核文件对象(struct file)的指针。dup2()的功能表面上是指定文件描述符的复制,实质上是将一个文件描述符表项中的指针复制到另一个表项中。重定向的原理就是:进程通过修改文件描述符表项中的指针指向,使得对特定文件描述符的操作实际作用于另一个文件。

1.4重定向的实现

实现重定向的思路是:在执行需要重定向的操作之前,通过系统调用(如dup2())让内核修改进程的文件描述符表,使得特定的文件描述符指向不同的文件对象,从而永久改变后续所有通过该文件描述符进行的I/O操作的目标

复制代码
void normalExecute(char* argv[])
{
    //创建子进程执行普通命令
    pid_t id = fork();
    if(id == 0)
    {
        //打开重定向文件,修改文件描述符的对应内容
        //文件描述符
        int fd = 0;
        //输入重定向
        if(rdir == IN_RDIR)
        {
            fd = open(rdirfilename, O_RDONLY);
            dup2(fd, 0);            
        }
        //输出重定向
        else if(rdir == OUT_RDIR)
        {
            fd = open(rdirfilename, O_CREAT|O_WRONLY|O_TRUNC, 0666);
            dup2(fd, 1);            
        }
        //追加重定向
        else if(rdir == APPEND_RDIR)
        {
            fd = open(rdirfilename, O_CREAT|O_WRONLY|O_APPEND, 0666);
            dup2(fd, 1);            
        }
        //子进程执行普通命令
        //参数1程序名,参数2命令行参数数组
        execvp(argv[0], argv);
        exit(EXIT_FAILURE);//替换失败返回错误码 
    }
    else if(id > 0)
    {
        //父进程阻塞等待
        int status = 0;
        pid_t rid = waitpid(id, &status, 0);
        if(rid > 0)//等待成功
        {  }
        else//等待失败 
        { }
    } 
    else
    {
        perror("fork fail\n");
        exit(EXIT_FAILURE);//创建子进程败
    }
}

1.5重定向与进程替换

结论:程序替换不会影响文件访问(包括重定向)

程序替换(exec)不会改变进程已打开的文件状态,包括重定向设置。这是因为Linux内核将进程管理与文件管理解耦,文件描述符表作为进程的一部分在exec时被保留。通过系统调用(如dup2)修改的文件描述符关联关系会被新程序继承,从而实现重定向的持久效果

2.2重定向示例

  • 仅重定向标准输出

    ./mytest > log.txt 等价于 ./mytest 1> log.txt
    效果:fd=1(标准输出) → log.txt文件

  • 分别重定向

    ./mytest 1>normal.log 2>err.log
    效果:
    fd=1 → normal.log(正常输出)
    fd=2 → err.log(错误输出)

  • 合并重定向

    方式1:
    ./mytest >all.log 2>&1 等价于 ./mytest 1>all.log 2>&1
    执行顺序:
    (1) >all.log 或 1>all.log → fd=1指向all.log
    (2) 2>&1 → fd=2也指向fd=1当前指向的文件(all.log)
    方式2:
    ./mytest &>all.log 等价于 >all.log 2>&1
    错误的方式:
    ./mytest 1>all.log 2>all.log //error 竞争
    !!两个描述符独立打开文件,会产生竞争条件,内容可能交错混乱!!

    ./mytest 2>&1 >all.log //error 顺序错误
    2>&1 → fd=2指向fd=1当前指向的文件(此时fd=1仍指向显示器)

    all.log → fd=1改为指向all.log
    结果: fd=2指向显示器,fd=1指向all.log

  • > 默认重定向fd=1,2> 重定向fd=2

  • 2>&1 不是重定向到文件,而是让fd=2指向fd=1的当前位置

  • 顺序很重要:先重定向目标,再复制描述符

  • &> 是bash的简写,等价于>file 2>&1

2.文件描述符1与2

  • 文件描述符1(fd=1):标准输出(stdout) - 正常输出信息

  • 文件描述符2(fd=2):标准错误(stderr) - 错误信息输出

  • 默认情况下,程序刚启动时,文件描述符1和2指向不同的文件对象,但这两个文件对象最终都连接到同一个终端设备

3.一切皆文件的理解

自底向上,Linux内核为统一管理各类硬件设备和系统资源,为每种设备类型定义一组操作方法(如读、写、控制等),封装在file_operations结构体中。当设备被访问时,内核创建struct file对象来描述这次打开操作,其中的f_op指针指向该设备对应的操作方法集。进程通过文件描述符访问文件时,内核查找对应的struct file对象,并通过其f_op指针调用具体的设备操作方法。这种抽象层在用户空间表现为统一的文件接口,从而实现了"一切皆文件"的设计哲学

相关推荐
盟接之桥6 分钟前
盟接之桥说制造:引流品 × 利润品,全球电商平台高效产品组合策略(供讨论)
大数据·linux·服务器·网络·人工智能·制造
忆~遂愿29 分钟前
ops-cv 算子库深度解析:面向视觉任务的硬件优化与数据布局(NCHW/NHWC)策略
java·大数据·linux·人工智能
湘-枫叶情缘33 分钟前
1990:种下那棵不落叶的树-第6集 圆明园的对话
linux·系统架构
Fcy6481 小时前
Linux下 进程(一)(冯诺依曼体系、操作系统、进程基本概念与基本操作)
linux·运维·服务器·进程
袁袁袁袁满1 小时前
Linux怎么查看最新下载的文件
linux·运维·服务器
代码游侠2 小时前
学习笔记——设备树基础
linux·运维·开发语言·单片机·算法
Gary Studio2 小时前
rk芯片驱动编写
linux·学习
mango_mangojuice2 小时前
Linux学习笔记(make/Makefile)1.23
java·linux·前端·笔记·学习
Harvey9032 小时前
通过 Helm 部署 Nginx 应用的完整标准化步骤
linux·运维·nginx·k8s
A星空1233 小时前
一、Linux嵌入式的I2C驱动开发
linux·c++·驱动开发·i2c