C 程序不能使用管道在 "execlp" 中执行 "more" 命令以查看程序的输出

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

在此先感谢您的帮助。

我正在尝试使用 C 程序复制 shell 命令 ls -1 /usr/include | more 的行为。 我写了这段代码:

#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;
    }
}

但它只打印一页(如 more 那样)并导致一些奇怪的行为阻塞我的终端(迫使我使用 reset 将其设置回正常)。

我刚刚意识到 parent 和 child 进程的角色被混淆了。 运行 more 命令应该是 parent。由于 more 是一个 interactive 命令,终端会更好地响应它作为 parent (我猜).

所以为了解决我的问题,我调换了 parent 和 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);
    }
}

为什么这样可以解决问题?(我还是不太明白为什么会这样!)

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

所以,最初 more 和 shell 可能都从同一个 TTY 设备读取(它从它的 STDERR 描述符读取,仍然附加到你的 TTY),然后一旦 more 最终获得一些输入,它将尝试再次从管道读取(它的 STDIN)并且它将得到一个文件结尾(管道已在写入端被出口关闭ls),因此 more 现在也将退出(不再打印任何输出)。 more 进程和 shell 之间也可能存在竞争,关于哪个(重新)设置 TTY 驱动程序模式以及何时设置。

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