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

相关推荐
Konwledging16 分钟前
kernel-devel_kernel-headers_libmodules
linux
Web极客码18 分钟前
CentOS 7.x如何快速升级到CentOS 7.9
linux·运维·centos
一位赵38 分钟前
小练2 选择题
linux·运维·windows
代码游侠1 小时前
学习笔记——Linux字符设备驱动开发
linux·arm开发·驱动开发·单片机·嵌入式硬件·学习·算法
Lw老王要学习2 小时前
CentOS 7.9达梦数据库安装全流程解析
linux·运维·数据库·centos·达梦
CRUD酱2 小时前
CentOS的yum仓库失效问题解决(换镜像源)
linux·运维·服务器·centos
zly35002 小时前
VMware vCenter Converter Standalone 转换Linux系统,出现两个磁盘的处理
linux·运维·服务器
Albert Edison3 小时前
【Python】函数
java·linux·python·pip
General_G3 小时前
Linux中的信号
linux·运维·服务器
诸神缄默不语3 小时前
当无法直接用apt instll时,Linux如何离线安装软件包(以make为例)
linux·运维·服务器