使用dup后恢复stdout

时间:2016-01-22 10:58:18

标签: c stdout dup

使用fork我创建了一个孩子,在孩子中我正在使用ls执行execl命令。要将输出发送到父级,我使用了pipedup。父母然后打印输出。代码给出了预期的输出,但是当我尝试恢复最初在stdout中保存的stdout_holder时,终端上没有打印任何内容(当我使用printf(“hello”)或execl语句时在它下面)。 然而,在几次观察之后,观察到仅在第一次重定向“1”之后没有做任何事情时才打印hello。 (如果我在dup(fd[1],1)之后没有做任何事情,只做dup(stdout_holder,1)) 为什么会这样?

#include<stdio.h>
#include<sys/types.h>
#include<unistd.h>
#include<errno.h>
#include<sys/wait.h>
#include<stdlib.h>
#include<string.h>
int main()
 {int fd[2],stdout_holder;
 char str;
 pid_t pid;
 pipe(fd);
 pid=fork();
 if(pid==0)
  { stdout_holder=dup(1);
    close(fd[0]);
   printf("stdout_holder=%d\n",stdout_holder); 
   fd[1]=dup2(fd[1],1);
   execl("/bin/ls","ls","-l",NULL);
   stdout_holder=dup2(stdout_holder,1);
   printf("hello\n"); //Terminal doesnt show output.
   execl("/bin/ls","ls","-l",NULL); //Terminal doesnt show output

 }
else
 { close(fd[1]);
   wait(&pid);
   while(read(fd[0],&str,1)>0)
   printf("%c",str);
  } 
}

3 个答案:

答案 0 :(得分:0)

有很多问题:

  1. execl()未返回(除非出现错误),您需要再次fork()或使用例如系统()。 在execl上,缓冲区不会自动清空,所以 printf输出(至少对我而言)没有达到标准输出。

  2. printf("stdout_holder= ...ls的第一个输出直接转到stdout,而不是 通过管道(stdout没有被替换)。你会 首先需要使用dup2()close(1)来电前使用dup() ..

答案 1 :(得分:0)

每当您调用execl(execv,execlp等)时,它都会开始执行新程序(创建一个新的过程映像)。执行此新程序会导致进程忘记其先前的过程映像。除非遇到某些错误,否则execl函数不会返回到同一个进程映像。

if(pid==0)
  { stdout_holder=dup(1);
    close(fd[0]);
   printf("stdout_holder=%d\n",stdout_holder); 
   fd[1]=dup2(fd[1],1);
   execl("/bin/ls","ls","-l",NULL); //creates a new process image
   //will never reach here unless there is an error in the execl call
   stdout_holder=dup2(stdout_holder,1);//Line 7
   printf("hello\n");
   execl("/bin/ls","ls","-l",NULL);// Line 9
 }

子进程完成第一个execl调用后,它将终止,因此永远不会到达剩余的代码(从第7行到第9行)。执行新的过程映像会完全更改内存的内容,只将参数和环境字符串复制到新位置。

希望这能回答你的问题。

答案 2 :(得分:0)

this file的第63行中,您应该在更改之前保存stdout文件描述符:

int moutfd = dup(STDOUT_FILENO);
dup2(fd, STDOUT_FILENO);

// Do the going-to-be-buffered jobs

dup2(moutfd, STDOUT_FILENO);
close(moutfd);
close(fd);