做Shell lab的时候要求完成重定向以及恢复,这里记录一下相关知识

#include <unistd.h>
int dup(int oldfd);

dup用来复制参数oldfd所指的文件描述符。当复制成功是,返回最小的尚未被使用过的文件描述符,若有错误则返回-1.错误代码存入errno中返回的新文件描述符和参数oldfd指向同一个文件,这两个描述符共享同一个数据结构,共享所有的锁定,读写指针和各项全现或标志位。

 #include <unistd.h>int dup2(int oldfd, int newfd);

dup2与dup区别是dup2可以用参数newfd指定新文件描述符的数值。若参数newfd已经被程序使用,则系统就会将newfd所指的文件关闭,若newfd等于oldfd,则返回newfd,而不关闭newfd所指的文件。dup2所复制的文件描述符与原来的文件描述符共享各种文件状态。共享所有的锁定,读写位置和各项权限或flags等.
返回值: 若dup2调用成功则返回新的文件描述符,出错则返回-1.

主要聊聊dup2
假设在调用dup2(4,l)之前,我们的状态如图

dup2(4, 1)之后,如图

理解如下:

n_fd = dup2(fd4,STDOUT_FILENO)表示n_fd与fd4共享一个文件表项(它们的文件表指针指向同一个文件表项),n_fd在文件描述符表中的位置为
STDOUT_FILENO(就是fd 1)的位置,而原先的STDOUT_FILENO所指向的文件表项(File A)被关闭。
理解dup2的一个好方法就是把fd看成一个结构体类型,就如上面图形中画的那样,我们不妨把之定义为:
struct fd_t {
int index;
filelistitem *ptr;
};
然后dup2匹配index,修改ptr,完成dup2操作。
在学习dup2时总是碰到“重定向”一词,上图完成的就是一个“从标准输出到文件的重定向”,经过dup2后该进程的任何目标为STDOUT_FILENO的I/O操作如printf等,其数据都将流入fd4所对应的文件中。

示例:

#define TESTSTR "Hello dup2\n"
int main() {int fd3;
fd3 = open("testdup2.dat",0666);
if (fd3 < 0) {printf("open error\n");
exit(-1);
}
if (dup2(fd3,STDOUT_FILENO) < 0) {printf("err in dup2\n");
}
printf(TESTSTR);
return 0;
}
其结果就是你在testdup2.dat中看到"Hello dup2"。

**

重定向后恢复

**

就是如何在重定向后再恢复原来的状态?首先大家都能想到要保存重定向前的文件描述符。那么如何来保存呢,下面这样行么?
int s_fd = STDOUT_FILENO;
int n_fd = dup2(fd3,STDOUT_FILENO);
还是这样可以呢?
int s_fd = dup(STDOUT_FILENO);
int n_fd = dup2(fd3,STDOUT_FILENO);
这两种方法的区别到底在哪呢?答案是第二种方案才是正确的,分析如下:按照第一种方法,我们仅仅在"表面上"保存了相当于fd_t(按照我前面说的理解方法)中的index,而在调用dup2之后,ptr所指向的文件表项由于计数值已为零而被关闭了,我们如果再调用dup2(s_fd,fd3)就会出错(出错原因上面有解释)。我们可以理解为原来STDOUT_FILENO的文件表是我们的屏幕,所以输出到屏幕上。但是现在这个文件表被关闭了,所以第一个方法失败了。
dup(fd)的语意是返回的新的文件描述符与fd共享一个文件表项。就如第二个方法中的s_fd和fd1共享文件表1一样。
确定第二个方案后重定向后的恢复就很容易了,只需调用dup2(s_fd,n_fd);即可。下面是一个完整的例子程序:

#define TESTSTR "Hello dup2\n"
#define SIZEOFTESTSTR 11
int main() {int fd3;
int s_fd;
int n_fd;
fd3 = open("testdup2.dat",0666);
if (fd3 < 0) {printf("open error\n");
exit(-1);
}
/* 复制标准输出描述符 */
s_fd = dup(STDOUT_FILENO);
if (s_fd < 0) {printf("err in dup\n");
}
/* 重定向标准输出到文件 */
n_fd = dup2(fd3,STDOUT_FILENO);
if (n_fd < 0) {printf("err in dup2\n");
}
write(STDOUT_FILENO,TESTSTR,SIZEOFTESTSTR); /* 写入testdup2.dat中 */
/* 重定向恢复标准输出 */
if (dup2(s_fd,n_fd) < 0) {printf("err in dup2\n");
}
write(STDOUT_FILENO,TESTSTR,SIZEOFTESTSTR); /* 输出到屏幕上 */
return 0;
}
注意这里我在输出数据的时候我是用了不带缓冲的write库函数,如果使用带缓冲区的printf,则最终结果为屏幕上输出两行"Hello dup2",而文件testdup2.dat中为空,原因就是缓冲区作怪,由于最终的目标是屏幕,所以程序最后将缓冲区的内容都输出到屏幕。

dup, dup2, 重定向恢复相关推荐

  1. linux c dup dup2 重定向函数简介

    dup()函数和dup2()函数书上在文件操作那一章,已经讲过了,这周看重定向这块,发现它挺重要,就再看了回,记录下. 1. dup函数 头文件及函数定义: #include <unistd.h ...

  2. dup/dup2重定向

    在linux编程中经常会看到stdin.stdout.stderr,他们的含有分别表示标准输入.标准输出.标准错误输出.三个系统文件的文件标识符分别用0.1.2表示. stdin 0 stdout 1 ...

  3. Linux:dup/dup2 文件描述符重定向函数(有图有代码有真相!!!)

    一.dup/dup2 有时我们希望把标准输入重定向到一个文件,或者把标准输出重定向到一个网络连接.系统调用dup和dup2能够复制文件描述符.dup返回新的文件文件描述符(没有用的文件描述符最小的编号 ...

  4. dup/dup2函数的用法

    系统调用dup和dup2能够复制文件描述符.dup返回新的文件文件描述符(没有用的文件描述符最小的编号).dup2可以让用户指定返回的文件描述符的值,如果需要,则首先接近newfd的值,他通常用来重新 ...

  5. 进程间通信管道进阶篇:linux下dup/dup2函数的用法

    由于利用管道实现进程间通信,是通过创建两个文件描述符,但是描述符的初始化是通过随机的,就是从可用的文件描述符中取出,并将可用的文件描述符与file对象相关联,如果我们需要将管道的两头与其他的流相关时, ...

  6. dup/dup2的用法及详解(转)

    相信大部分在Unix/Linux下编程的程序员手头上都有<Unix环境高级编程>(APUE)这本超级经典巨著.作者在该书中讲解dup/dup2之前曾经讲过"文件共享", ...

  7. linux dup跨进程使用,linux下dup/dup2函数的用法

    系统调用dup和dup2能够复制文件描述符.dup返回新的文件文件描述符(没有用的文件描述符最小的编号).dup2可以让用户指定返回的文件描述符的值,如果需要,则首先接近newfd的值,他通常用来重新 ...

  8. dup/dup2函数

    #include <unistd.h> int dup(int oldfd); int dup2(int oldfd, int newfd); 当调用dup函数时,内核在进程中创建一个新的 ...

  9. linux dup2实现重定向,dup/dup2输出重定向

    函数原型:#include int dup(int oldfd); int dup2(int oldfd,int newfd); dup用来复制oldfd所指的文件描述符.但复制成功时返回最小的尚未被 ...

最新文章

  1. 为什么说可视化编程是糟糕的想法?
  2. Ext JS 6正式版的GPL版本下载地址
  3. 《用户故事与敏捷方法》阅读笔记一
  4. main 函数解析(二)—— Linux-0.11 学习笔记(六)
  5. linux常用操作命令汇总
  6. CentOS 7下安装Mono
  7. redhat linux raid5,Linux 红帽   磁盘管理~~~~RAID5+LVM
  8. python用来正常显示中文标签 plt.rcParams['font.sans-serif'] = ['SimHei']错误
  9. VS Code:4个中文乱码问题及解决方法
  10. bokeh 设置做图工具
  11. 台式计算机入门基础知识,电脑基础知识:新手入门最全电脑知识干货
  12. 计算机每天早上自动开机,win10设置每天自动开机(电脑可以设置自动开机时间)...
  13. HGIMDA:用于miRNA-疾病关联预测的异构图推断
  14. 什么是大数据?零基础如何学习大数据?(附学习路线)
  15. 一个人可以办三个支付宝账号,这三个支付宝账户之间有什么影响?
  16. img加载中显示loading,加载失败显示默认图片(React)
  17. 2019 虎鲸杯电子取证大赛赛后复盘总结
  18. DHCP 服务原理与配置
  19. java 火车票_Java 面向对象 之 接口 火车票实例
  20. 当你收到面试通知后,通过如下的准备可以大大提升面试成功率

热门文章

  1. 业余草推荐阿里妈妈自研广告点击率预估核心算法MLR
  2. 拼多多上市背后:假货问题到底该不该由拼多多一家承担?
  3. 轻松使用git同步到gitee(码云)
  4. 中职学校计算机创新杯比赛课件,创新杯 计算机类 说课课件.ppt
  5. TMP451温度传感器
  6. css flex布局 —— 容器属性 align-items
  7. [Android]简易播放视频
  8. 重装win10纯净版操作系统
  9. 一个3D视频播放器的演示APK
  10. 帝国理工计算机软件工程,帝国理工学院计算机软件工程理学硕士