问题
Using fork
I created a child and in the child I'm executing the ls
command using execl
. To send the output to parent,I used pipe
and dup
. The parent then prints the output. The code gives the expected output, but when I tried to restore back the stdout
which I saved initially in stdout_holder
, nothing is printed on terminal (when I used printf("hello") or the execl statement below it).
However after few observations, it is observed that hello
is printed only when nothing is done after redirecting "1" for the first time. (If I don't do anything after dup(fd[1],1)
and simply do dup(stdout_holder,1)
)
Why is this happening?
#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);
}
}
回答1:
There are multiple issues:
execl()
does not return (except if there is an error), you need tofork()
again or use e.g. system(). Onexecl
the buffers are not emptied automatically, so the printf output does (at least for me) not reach stdout.The first output of
printf("stdout_holder= ...
andls
goes directly to stdout, not through the pipe (stdout is not replaced). You would need to usedup2()
at the first place orclose(1)
before thedup()
call..
回答2:
Whenever you place a call to the execl(execv, execlp, etc.), it starts the execution of a new program (creates a new process image). The execution of this new program causes the process to forget all about its previous process image. The execl function does not return to the same process image unless it encounters some error.
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
}
After the child process finishes the first execl call, it will terminate, and hence will never reach the remaining code (from line 7 to line 9). Executing a new process image completely changes the contents of the memory, copying only the argument and environment strings to the new locations.
Hope this answers your question.
回答3:
As in line 63 of this file you should save stdout file descriptor before changing it:
int moutfd = dup(STDOUT_FILENO);
dup2(fd, STDOUT_FILENO);
// Do the going-to-be-buffered jobs
dup2(moutfd, STDOUT_FILENO);
close(moutfd);
close(fd);
来源:https://stackoverflow.com/questions/34945049/restoring-stdout-after-using-dup