Pipe () and fork () in c

I need to create two child processes. One child should run the command "ls -al" and redirect its output to the input of the next child process, which, in turn, will run the command "sort -r -n -k 5" on its input. Finally, the parent process should read this (data is already sorted) and display it in the terminal. The end result in the terminal (when the program is running) should be the same as if I entered the following command into the shell: "ls -al | sort -r -n -k 5". To do this, I need to use the following methods: pipe (), fork (), execlp ().

My program compiles, but I do not get the desired output to the terminal. I do not know what is wrong. Here is the code:

#include <sys/types.h> #include <stdio.h> #include <string.h> #include <unistd.h> int main() { int fd[2]; pid_t ls_pid, sort_pid; char buff[1000]; /* create the pipe */ if (pipe(fd) == -1) { fprintf(stderr, "Pipe failed"); return 1; } /* create child 2 first */ sort_pid = fork(); if (sort_pid < 0) { // error creating Child 2 process fprintf(stderr, "\nChild 2 Fork failed"); return 1; } else if(sort_pid > 0) { // parent process wait(NULL); // wait for children termination /* create child 1 */ ls_pid = fork(); if (ls_pid < 0) { // error creating Child 1 process fprintf(stderr, "\nChild 1 Fork failed"); return 1; } else if (ls_pid == 0) { // child 1 process close(1); // close stdout dup2(fd[1], 1); // make stdout same as fd[1] close(fd[0]); // we don't need this end of pipe execlp("bin/ls", "ls", "-al", NULL);// executes ls command } wait(NULL); read(fd[0], buff, 1000); // parent reads data printf(buff); // parent prints data to terminal } else if (sort_pid == 0) { // child 2 process close(0); // close stdin dup2(fd[0], 0); // make stdin same as fd[0] close(fd[1]); // we don't need this end of pipe execlp("bin/sort", "sort", "-r", "-n", "-k", "5", NULL); // executes sort operation } return 0; } 
+6
source share
1 answer

The parent wait process to complete the sort process before creating the ls process.

The sorting process must read its input before it is complete. And its input comes from ls, which will not start until wait is wait . Dead end.

You need to create both processes and then wait for both of them.

In addition, your file descriptors are not entirely correct. In this pair of calls:

 close(0); dup2(fd[0], 0); 

closing is redundant since dup2 automatically closes the existing fd 0, if any. You should do close(fd[0]) after ther dup2, so that you only have one file descriptor associated with this end of the pipe. And if you want to be really reliable, you should check wither fd[0]==0 already, in which case skip dup2 and close.

Apply all this to another dup2.

The question then becomes about the parent process in which the channel is open. I would say that you should close both ends of the channel in the parent after you passed them to the children, but you have this weird read from fd[0] after the last wait ... I don't know why this is. If the ls|sort pipeline works correctly, then the pipe will be empty, so there is nothing to read. In any case, you definitely need to close fd[1] in the parent element, otherwise the sorting process will not be completed, because the channel does not indicate EOF until all authors are closed.

After the weird read will be printf , which is likely to crash because the read buffer will not be '\0' -terminated.

And the point of using execlp is that it does a $PATH lookup for you, so you don't need to specify /bin/ . My first test run failed because my type is in /usr/bin/ . Why are hard ways when you don't need to?

+3
source

Source: https://habr.com/ru/post/946324/


All Articles