C程序不能使用管道来执行;“更多”;命令在";execlp";要查看程序';s输出

C程序不能使用管道来执行;“更多”;命令在";execlp";要查看程序';s输出,c,pipe,fork,C,Pipe,Fork,提前感谢您的帮助 我试图使用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

提前感谢您的帮助

我试图使用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;
    }
}
#包括
#包括
#包括
int main(){
int page[2];//page是我的管道的名称
管道(第页);
开关(fork()){
案例1:
出口(1);
打破
案例0:;
关闭(第[1]页);
dup2(第[0]页,第0页);
关闭(第[0]页);
execlp(“更多”、“更多”、空);
违约:
关闭(第[0]页);
dup2(第[1]页,第1页);
关闭(第[1]页);
execlp(“ls”、“ls”、“-1”、“/usr/include”、NULL);
打破
}
}

但是它只打印一页(更多的就可以了),并导致一些奇怪的行为阻塞了我的终端(迫使我使用重置将其设置回正常状态)。

我刚刚意识到父进程和子进程的角色混淆了。运行
more
命令的应该是父级。由于
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[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);
    }
}
#包括
#包括
#包括
int main(){
int page[2];//page是我的管道的名称
管道(第页);
开关(fork()){
案例1:
出口(1);
打破
案例0:;
关闭(第[0]页);
dup2(第[1]页,第1页);
关闭(第[1]页);
execlp(“ls”、“ls”、“-1”、“/usr/include”、NULL);
打破
违约:
关闭(第[1]页);
dup2(第[0]页,第0页);
关闭(第[0]页);
execlp(“更多”、“更多”、空);
}
}

为什么这能解决问题?(我仍然不清楚它为什么起作用!)

我刚刚意识到父进程和子进程的角色混淆了。运行
more
命令的应该是父级。由于
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[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);
    }
}
#包括
#包括
#包括
int main(){
int page[2];//page是我的管道的名称
管道(第页);
开关(fork()){
案例1:
出口(1);
打破
案例0:;
关闭(第[0]页);
dup2(第[1]页,第1页);
关闭(第[1]页);
execlp(“ls”、“ls”、“-1”、“/usr/include”、NULL);
打破
违约:
关闭(第[1]页);
dup2(第[0]页,第0页);
关闭(第[0]页);
execlp(“更多”、“更多”、空);
}
}

为什么这样做可以解决问题?(我仍然不清楚它为什么起作用!)

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

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


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

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

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


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

控制终端和会话。请阅读setId、setpg上的手册页关于控制终端。控制终端和会话。阅读手册页