免费注册 查看新帖 |

Chinaunix

  平台 论坛 博客 文库
最近访问板块 发新帖
查看: 3972 | 回复: 8
打印 上一主题 下一主题

标准输出被重定向后, 恢复不了 [复制链接]

论坛徽章:
0
跳转到指定楼层
1 [收藏(0)] [报告]
发表于 2009-02-06 16:09 |只看该作者 |倒序浏览
10可用积分
我的步骤是:
1. 保存标准输出(dup2);
2. 重定向标准输出到一个管道;
3. 利用(1)保存的恢复标准输出;

但是然后用printf竟然没有打印出来, 怎么回事 ?有哪些可能的原因 ?

论坛徽章:
0
2 [报告]
发表于 2009-02-06 16:17 |只看该作者
你重新打开标准输出open(stdout),然后将返回的文件描述符恢复到1

论坛徽章:
0
3 [报告]
发表于 2009-02-06 17:04 |只看该作者
估计是你那个管道没结束, 所以标准输入还是被重定向了.

论坛徽章:
0
4 [报告]
发表于 2009-02-06 17:54 |只看该作者
原帖由 argstormsky 于 2009-2-6 17:04 发表
估计是你那个管道没结束, 所以标准输入还是被重定向了.


已经恢复了, 成功了的.

这个时候标准输出不指向管道了呀.

你说的这种情况不大可能吧.

论坛徽章:
0
5 [报告]
发表于 2009-02-06 18:29 |只看该作者
借楼主的地盘问一个问题

我在思考楼主碰到的问题的时候,自己写了个测试程序
结果屏幕打出
bbb
this will not appear STDOUT_FILENO
write to STDOUT_FILENO
不太明白的是this will not appear STDOUT_FILENO 这句话为什么也送到了终端显示,而且为什么会显示在bbb之后

程序如下:
  1. #include <stdio.h>
  2. #include <stdlib.h>
  3. #include <unistd.h>

  4. int main(void)
  5. {
  6.         int fdcopy = 9;
  7.         int fd[2];

  8.         if (pipe(fd) == -1)
  9.         {
  10.                 printf("pipe() error\n");
  11.                 exit(0);
  12.         }       
  13.        
  14.         if (dup2(STDOUT_FILENO, fdcopy) == -1)
  15.         {
  16.                 printf("dup2() error\n");
  17.                 exit(0);
  18.         }

  19.         if (dup2(fd[1], STDOUT_FILENO) == -1)
  20.         {
  21.                 printf("dup2() error for pipe[1]\n");
  22.                 exit(0);
  23.         }

  24.         write(STDOUT_FILENO, "aaa\n", sizeof("aaa\n"));
  25.         printf("this will not appear STDOUT_FILENO\n");

  26.         if (dup2(fdcopy, STDOUT_FILENO) == -1)
  27.         {
  28.                 printf("restore STDOUT_FILENO error\n");
  29.                 exit(0);
  30.         }

  31.         write(STDOUT_FILENO, "bbb\n", sizeof("bbb\n"));
  32.         printf("write to STDOUT_FILENO\n");
  33.         return 0;
  34. }

复制代码

论坛徽章:
0
6 [报告]
发表于 2009-02-06 18:40 |只看该作者
当STDOUT_FILENO被重定向到fd[1]以后,变成了全缓冲模式
所以  printf("this will not appear STDOUT_FILENO\n");里的“this will not appear STDOUT_FILENO\n”将会保存至缓冲区中
后来STDOUT_FILENO被恢复到终端,这时恢复到行缓冲,缓冲区里的内容这时候才发送,又因为定向到终端了,所以会在终端显示this will not appear STDOUT_FILENO\n

不知道我的理解是不是正确?

论坛徽章:
0
7 [报告]
发表于 2009-02-07 15:19 |只看该作者
原帖由 spiritX 于 2009-2-6 16:09 发表
我的步骤是:
1. 保存标准输出(dup2);
2. 重定向标准输出到一个管道;
3. 利用(1)保存的恢复标准输出;

但是然后用printf竟然没有打印出来, 怎么回事 ?有哪些可能的原因 ?



可能是c库缓存机制的问题,你试试在printf之后加一句fflush(stdout)看看怎么样

论坛徽章:
0
8 [报告]
发表于 2009-02-07 15:35 |只看该作者
原帖由 zhuhefang2006 于 2009-2-6 18:40 发表
当STDOUT_FILENO被重定向到fd[1]以后,变成了全缓冲模式
所以  printf("this will not appear STDOUT_FILENO\n");里的“this will not appear STDOUT_FILENO\n”将会保存至缓冲区中
后来STDOUT_FILENO被恢复到 ...


差不多吧,但不完全准确,开始时"this will not appear STDOUT_FILENO"没打印出来确实是因为全缓存,但之后它打印出来并不是因为
dup2(fdcopy, STDOUT_FILENO)使stdout恢复成行缓存,它这时还是全缓存,包括下一句"write to STDOUT_FILENO"都还是保存在C库的缓存中,最后显示出来是因为进程退出时C库才进行的刷新,你可以在return前加一条sleep(x)验证一下。

我没有读glibc的源码,但根据strace分析了一下,似乎glibc只是在第一次printf时去检查stdout的类型,并且之后就认为stdout是这个类型了。由于你第一次在调用printf时,stdout已经被重定向到了管道,因此glibc就认为stdout是管道了,因此之后都进行全缓存。如果你在第一次dup2(STDOUT_FILENO, fdcopy)前就先printf一下,那么glibc就会认为stdout是终端而进行行缓存了,之后还是那些代码打印出来的结果就会完全不同。

以上仅是我根据strace的推测,希望了解glibc代码的兄弟确认一下。

论坛徽章:
0
9 [报告]
发表于 2009-02-07 20:25 |只看该作者
看你的描述好像没错,可能是你代码写错了
您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

  

北京盛拓优讯信息技术有限公司. 版权所有 京ICP备16024965号-6 北京市公安局海淀分局网监中心备案编号:11010802020122 niuxiaotong@pcpop.com 17352615567
未成年举报专区
中国互联网协会会员  联系我们:huangweiwei@itpub.net
感谢所有关心和支持过ChinaUnix的朋友们 转载本站内容请注明原作者名及出处

清除 Cookies - ChinaUnix - Archiver - WAP - TOP