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
,然后等待两个进程终止,但是这当然需要更多的系统资源。
在此先感谢您的帮助。
我正在尝试使用 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
,然后等待两个进程终止,但是这当然需要更多的系统资源。