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指针调用具体的设备操作方法。这种抽象层在用户空间表现为统一的文件接口,从而实现了"一切皆文件"的设计哲学

相关推荐
HIT_Weston2 小时前
99、【Ubuntu】【Hugo】搭建私人博客:搜索功能(三)
linux·运维·ubuntu
txinyu的博客2 小时前
select/poll/epoll
linux·c++
小蜗的房子2 小时前
Oracle 19c RAC重建AWR步骤详解
linux·运维·数据库·sql·oracle·操作系统·oracle rac
久绊A2 小时前
RAID10 单盘失效降级处理实操
linux·运维·服务器
xlp666hub2 小时前
Linux 设备模型学习笔记(2)之 kobject
linux·面试
松涛和鸣2 小时前
54、DS18B20单线数字温度采集
linux·服务器·c语言·开发语言·数据库
Vallelonga2 小时前
ELF 文件和 Linux 内核镜像文件
linux·经验分享
zzzsde2 小时前
【Linux】基础开发工具(4):自动化构建--make/makefile
linux·运维·服务器
txinyu的博客2 小时前
Reactor 模型全解析
java·linux·开发语言·c++