I have to write a shell that can run pipes. For example commands like ls -l | wc -l
". I have successfully parsed the command given by the user as below:
"ls" = firstcmd
"-l" = frsarg
"wc" = scmd
"-l" = secarg
Now I have to use two forks since the commands are two and a pipe. The code block that I wrote to exec the command is the following:
pid_t pid;
int fd[2];
pipe(fd);
pid = fork();
if(pid==0)
{
dup2(fd[WRITE_END], STDOUT_FILENO);
close(fd[READ_END]);
execlp(firstcmd, firstcmd, frsarg, (char*) NULL);
}
else
{
pid=fork();
if(pid==0)
{
dup2(fd[READ_END], STDIN_FILENO);
close(fd[WRITE_END]);
execlp(scmd, scmd, secarg, (char*) NULL);
}
}
So when I run my shell and I enter the command ls -l | wc -l
(for example) the result from the execs doesn't show up but the shell keeps running normally.
The strange thing is that the result of the command shows only when I terminate my shell with "exit" or "^C".
What is wrong with that output? Why doesn't it show up right after I enter the command?
You need to close all the pipe descriptors in both the parent process and the child process (after duplication in the child process). In your code the main issue is that, the wc
process does not exit because there are still writers present (since the parent process has not closed the write end). Changes shown below. I have also added the waitpid
in the parent process to wait for the wc
process.
pid_t pid;
int fd[2];
pipe(fd);
pid = fork();
if(pid==0)
{
dup2(fd[WRITE_END], STDOUT_FILENO);
close(fd[READ_END]);
close(fd[WRITE_END]);
execlp(firstcmd, firstcmd, frsarg, (char*) NULL);
fprintf(stderr, "Failed to execute '%s'\n", firstcmd);
exit(1);
}
else
{
pid=fork();
if(pid==0)
{
dup2(fd[READ_END], STDIN_FILENO);
close(fd[WRITE_END]);
close(fd[READ_END]);
execlp(scmd, scmd, secarg,(char*) NULL);
fprintf(stderr, "Failed to execute '%s'\n", scmd);
exit(1);
}
else
{
int status;
close(fd[READ_END]);
close(fd[WRITE_END]);
waitpid(pid, &status, 0);
}
}