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?
We use the dup2() system call to duplicate the writing file descriptor of the pipe (pfd[1]) onto the standard output file descriptor, 1. We don't need the input end of the pipe (pdf[0]), so we close it. 6. Once that is done, we simple call execvp() to run the program.
The dup2() function duplicates an open file descriptor. Specifically, it provides an alternate interface to the service provided by the fcntl() function using the F_DUPFD constant command value, with fildes2 for its third argument. The duplicated file descriptor shares any locks with the original.
A pipe is a form of redirection (transfer of standard output to some other destination) that is used in Linux and other Unix-like operating systems to send the output of one command/program/process to another command/program/process for further processing.
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);
}
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With