Linux认证辅导:形象的理解dup和dup2函数(3)
Linux认证辅导:形象的理解dup和dup2函数(3)二、重定向后恢复
CU上有这样一个帖子,就是如何在重定向后再恢复原来的状态?首先大家都能想到要保存重定向前的文件描述符。那么如何来保存呢,象下面这样行么?
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)就会出错(出错原因上面有解释)。而第二种方法我们首先做一下复制,复制后的状态如下图所示:
进程A的文件描述符表(after dup)
------------
fd0 0 | p0
------------
fd1 1 | p1 -------------》 文件表1 ---------》 vnode1
------------ /|
fd2 2 | p2 /
------------ /
fd3 3 | p3 -------------》 文件表2 ---------》 vnode2
------------ /
s_fd 4 | p4 ------/
------------
。.. 。..
。.. 。..
------------
调用dup2后状态为:
进程A的文件描述符表(after dup2)
------------
fd0 0 | p0
------------
n_fd 1 | p1 ------------
------------ \
fd2 2 | p2 \
------------ _\|
fd3 3 | p3 -------------》 文件表2 ---------》 vnode2
------------
s_fd 4 | p4 -------------》文件表1 ---------》 vnode1
------------
。.. 。..
。.. 。..
------------
Linux认证辅导:形象的理解dup和dup2函数(3)
dup(fd)的语意是返回的新的文件描述符与fd共享一个文件表项。就如after dup图中的s_fd和fd1共享文件表1一样。</p> 确定第二个方案后重定向后的恢复就很容易了,只需调用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中为空,原因就是缓冲区作怪,由于最终的目标是屏幕,所以程序最后将缓冲区的内容都输出到屏幕。
页:
[1]