简体   繁体   English

C程序不能使用管道执行“execlp”中的“more”命令来查看程序的输出

[英]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我正在尝试复制 shell 命令ls -1 /usr/include | more的行为。 ls -1 /usr/include | more using a C program. ls -1 /usr/include | more使用 C 程序。 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).但它只打印一页( more会做)并导致一些奇怪的行为阻止我的终端(迫使我使用reset将其设置回正常)。

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.运行more命令的应该是父级。 Since more is an interactive command, the terminal will respond better to it as the parent (I'm guessing).由于more是一个交互式命令,终端将作为父级更好地响应它(我猜)。

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.您的原始代码在父进程和子进程以及启动程序的 shell 之间创建了一种竞争条件。 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. ls进程在more可以从管道中读取所有数据之前结束,并且由于在您的程序中父进程被ls进程替换,当ls进程结束时(将其所有输出写入管道缓冲区后),它退出,并且这样做会关闭管道并将控制权交还给外壳程序,外壳程序将立即准备好读取另一个命令。

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).所以,最初都more与外壳可从同一TTY设备读取(它是从它的阅读STDERR描述符,还是连接到您的TTY),然后一旦more ,最终得到了一些输入,它会尝试从管道再次读取(其STDIN ),它将获得文件结尾(管道已在写入端关闭,因为ls退出),因此more现在也将退出(不再打印任何输出)。 There's also a possible race between the more process and the shell as to which (re)sets the TTY driver modes and when. more进程和 shell 之间也可能存在竞争,关于哪个(重新)设置 TTY 驱动程序模式以及何时。

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.程序的另一种实现是让原始父进程启动两个子进程,一个用于more ,一个用于ls ,然后等待两个进程终止,但这当然需要更多的系统资源。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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