)
目录1.重定向1.1引入1.2dup21.3原理1.4重定向的实现1.5重定向与进程替换2.2重定向示例2.文件描述符1与23.一切皆文件的理解1.重定向1.1引入首先使用close接口关闭文件描述符为1的文件起初是标准输出文件然后open函数打开一个文件根据最小未使用文件描述符策略该文件的文件描述符为1接着向文件描述符为1的文件写入5条信息最后再关闭open函数打开的文件这样就实现了输出重定向的非常搓的版本先关闭再打开原本向标准输出文件写入的内容变为了写入filename文件当中1.2dup2实现输入输出追加重定向调用dup2函数即可这样就不用先关闭再打开了类别详情函数原型#include unistd.hint dup2(int oldfd, int newfd);功能描述将文件描述符oldfd复制到newfd使两者指向同一文件表项。若newfd已打开则先关闭它。参数说明-oldfd源文件描述符必须有效且已打开。-newfd目标文件描述符可指定范围通常为[0, OPEN_MAX-1]。返回值- 成功返回newfd。- 失败返回-1并设置errno如EBADF、EMFILE。(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 效果fd1标准输出 → log.txt文件分别重定向./mytest 1normal.log 2err.log 效果 fd1 → normal.log正常输出 fd2 → err.log错误输出合并重定向方式1 ./mytest all.log 21 等价于 ./mytest 1all.log 21 执行顺序 1 all.log 或 1all.log → fd1指向all.log 2 21 → fd2也指向fd1当前指向的文件all.log 方式2 ./mytest all.log 等价于 all.log 21 错误的方式 ./mytest 1all.log 2all.log //error 竞争 两个描述符独立打开文件会产生竞争条件内容可能交错混乱 ./mytest 21 all.log //error 顺序错误 21 → fd2指向fd1当前指向的文件此时fd1仍指向显示器 all.log → fd1改为指向all.log 结果 fd2指向显示器fd1指向all.log 默认重定向fd12 重定向fd221 不是重定向到文件而是让fd2指向fd1的当前位置顺序很重要先重定向目标再复制描述符 是bash的简写等价于file 212.文件描述符1与2文件描述符1fd1标准输出stdout - 正常输出信息文件描述符2fd2标准错误stderr - 错误信息输出默认情况下程序刚启动时文件描述符1和2指向不同的文件对象但这两个文件对象最终都连接到同一个终端设备3.一切皆文件的理解自底向上Linux内核为统一管理各类硬件设备和系统资源为每种设备类型定义一组操作方法如读、写、控制等封装在file_operations结构体中。当设备被访问时内核创建struct file对象来描述这次打开操作其中的f_op指针指向该设备对应的操作方法集。进程通过文件描述符访问文件时内核查找对应的struct file对象并通过其f_op指针调用具体的设备操作方法。这种抽象层在用户空间表现为统一的文件接口从而实现了一切皆文件的设计哲学