简体   繁体   中英

C program cannot use pipe to execute the "more" command in "execlp" in order to view program's output

thanks in advance for any help.

I am trying to replicate the behavior of the shell command ls -1 /usr/include | more ls -1 /usr/include | more using a C program. I wrote this code:

#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
int main(){
    int page[2];   // page is the name of my pipe
    pipe(page);
    switch (fork()){
    case -1:
        exit(1);
        break;
    case 0:;
        close(page[1]);
        dup2(page[0], 0);
        close(page[0]);
        execlp("more", "more", NULL);
    default:
        close(page[0]);
        dup2(page[1], 1);
        close(page[1]);
        execlp("ls", "ls", "-1", "/usr/include", NULL);
        break;
    }
}

But it only prints one page (as more would do) and causes some weird behavior that blocks my terminal (forcing me to use reset to set it back to normal).

I just realized the roles of the parent and the child process were being mixed up. The one to run the more command should be the parent. Since more is an interactive command, the terminal will respond better to it as the parent (I'm guessing).

So to solve my issue, I switched the roles of the parent and the child.

#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>

int main(){
    int page[2];   // page is the name of my pipe
    pipe(page);
    switch (fork()){
    case -1:
        exit(1);
        break;
    case 0:;
        close(page[0]);
        dup2(page[1], 1);
        close(page[1]);
        execlp("ls", "ls", "-1", "/usr/include", NULL);
        break;
    default:
        close(page[1]);
        dup2(page[0], 0);
        close(page[0]);
        execlp("more", "more", NULL);
    }
}

WHY DOES THIS SOLVES THE PROBLEM? (I still do not clearly understand why it worked!)

Your original code creates a kind of a race condition between the parent and the child processes, and the shell which started your program. The ls process ends before more can read all the data from the pipe, and since in your program the parent process is replaced by the ls process, when that ls process ends (after writing all its output into the pipe buffer) it exits, and in doing so closes the pipe and gives control back to the shell which will immediately get ready to read another command.

So, initially both more and the shell may be reading from the same TTY device (it's reading from its STDERR descriptor, still attached to your TTY), and then once more eventually gets some input it will try to read from the pipe again (its STDIN ) and it will get an end-of-file (the pipe has been closed on the write end by the exit of ls ), and so more will now also exit (without printing any more output). There's also a possible race between the more process and the shell as to which (re)sets the TTY driver modes and when.

An alternative implementation of your program is for the original parent process to start two child processes, one for more and one for ls , and then to wait for both processes to terminate, but this will of course require more system resources.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM