您没有关闭子级中管道的足够文件描述符,或者父级中的任何管道的文件描述符。
经验法则: 如果你dup2()将管道的一端连接到标准输入或标准输出,关闭两者
返回的原始文件描述符pipe()尽快地。
特别是,您应该在使用任何之前关闭它们exec*()函数族。
如果您使用以下任一方式重复描述符,则该规则也适用dup()
or
fcntl()
with F_DUPFD
这是正确关闭管道的工作代码。我删除了命令的路径部分,因为(a)它们对于我的机器来说是错误的,并且(b)使用没有意义execvp()
如果您指定命令的路径。我报告了大多数错误(但我不检查read()
and write()
来电。我还报告了孩子们的退出状况。如果孩子们未能执行命令,则报告并退出。您使用“save_stdin”等的代码进一步混淆了事情,因为变量在父级中未初始化,这是序列所在的位置:
dup2(save_stdin, 0);
dup2(save_stdout, 1);
close(save_stdin);
close(save_stdout);
被处决。你和我都不知道那两个是什么dup2()
调用确实如此——但它们很可能失败了,或者它们对您的标准 I/O 通道做了一些奇怪的事情。
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#define BUF_SIZE 100
int main(void)
{
pid_t pid1, pid2;
int fd[2];
char *argv1[] = { "ps", "-j", NULL }; // Remove PATH because using execvp()
char *argv2[] = { "more", NULL }; // Remove PATH because using execvp()
char prompt[] = "Press enter: ";
char buffer[BUF_SIZE];
write(STDOUT_FILENO, prompt, sizeof(prompt) - 1);
ssize_t readIn = readIn = read(STDIN_FILENO, buffer, BUF_SIZE);
buffer[readIn - 1] = '\0';
printf("readIn: %zd\n", readIn);
if (pipe(fd) < 0)
{
fprintf(stderr, "failed to create pipe\n");
exit(EXIT_FAILURE);
}
if ((pid1 = fork()) < 0)
{
fprintf(stderr, "failed to fork - 1\n");
exit(EXIT_FAILURE);
}
if (pid1 == 0) // child
{
dup2(fd[1], STDOUT_FILENO);
close(fd[0]);
close(fd[1]);
execvp(argv1[0], argv1);
fprintf(stderr, "failed to execute %s\n", argv1[0]);
exit(EXIT_FAILURE);
}
if ((pid2 = fork()) < 0)
{
fprintf(stderr, "failed to fork - 2\n");
exit(EXIT_FAILURE);
}
if (pid2 == 0)
{
dup2(fd[0], STDIN_FILENO);
close(fd[0]);
close(fd[1]);
execvp(argv2[0], argv2);
fprintf(stderr, "failed to execute %s\n", argv2[0]);
exit(EXIT_FAILURE);
}
close(fd[0]);
close(fd[1]);
int corpse;
int status;
while ((corpse = wait(&status)) > 0)
fprintf(stderr, "%d: child %d exited with status 0x%.4X\n",
(int)getpid(), corpse, (unsigned)status);
return 0;
}
该计划是pipe41
(对输出进行一些小的编辑,以删除那些实际上不需要让您了解我在其他窗口中所做的事情的内容):
$ ./pipe41
Press enter:
readIn: 1
USER PID PPID PGID SESS JOBC STAT TT TIME COMMAND
jonathanleffler 6618 6617 6618 0 1 S s000 0:00.11 -bash
jonathanleffler 6629 6628 6629 0 1 S+ s001 0:00.04 -bash
jonathanleffler 6660 6645 6660 0 1 S+ s002 0:00.04 -bash
jonathanleffler 6716 6695 6716 0 1 S+ s003 0:00.04 -bash
jonathanleffler 6776 6746 6776 0 1 S+ s004 0:00.04 -bash
jonathanleffler 6800 6771 6800 0 1 S+ s005 0:00.04 -bash
jonathanleffler 7487 7486 7487 0 1 S s006 0:00.04 -bash
jonathanleffler 9558 9557 9558 0 1 S s007 0:00.06 -bash
jonathanleffler 10375 9558 10375 0 1 S+ s007 0:00.01 ./pipe41
jonathanleffler 10377 10375 10375 0 1 S+ s007 0:00.00 more
(END)10375: child 10376 exited with status 0x0000
10375: child 10377 exited with status 0x0000
$