我正在尝试运行这个命令ps -j | more。我认为我已经正确设置了管道,但由于某种原因它只是挂起:
我正在调用一个运行的叉子ps -j和另一个运行的叉子more,并用管道连接它们。
由于某种原因,这仍然没有按预期工作。
代码如下:
#define BUF_SIZE 100
int main() {
pid_t pid1, pid2;
int save_stdin, save_stdout;
int fd[2];
char *argv1[] = { "/bin/ps", "-j", NULL };
char *argv2[] = { "/bin/more", NULL };
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: %d\n", readIn);
pipe(fd);
pid1 = fork();
if (pid1 == 0) { // child
close(fd[0]);
save_stdout = dup(1);
dup2(fd[1], STDOUT_FILENO);
execvp(argv1[0], argv1);
close(fd[1]);
} else { // parent
pid2 = fork();
if(pid2 == 0) {
save_stdin = dup(0);
dup2(fd[0], STDIN_FILENO);
execvp(argv2[0], argv2);
close(fd[0]);
} else {
}
}
dup2(save_stdin, 0);
dup2(save_stdout, 1);
close(save_stdin);
close(save_stdout);
int i = 1;
do {
wait(NULL);
} while (i-- > 0);
exit(0);
}
Run Code Online (Sandbox Code Playgroud)
非常感谢任何帮助!
编辑:
dup2()我尝试在 after但 before关闭管道execvp(),但它仍然挂起:
pipe(fd);
pid1 = fork();
if (pid1 == 0) { // child
dup2(fd[1], STDOUT_FILENO);
close(fd[1]);
close(fd[0]);
int res1 = execvp(argv1[0], argv1);
printf("exec1: %d\n", res1);
} else { // parent
pid2 = fork();
if(pid2 == 0) {
dup2(fd[0], STDIN_FILENO);
close(fd[0]);
close(fd[1]);
int res2 = execvp(argv2[0], argv2);
printf("exec2: %d\n", res2);
} else {
}
}
close(fd[1]);
close(fd[0]);
printf("finished\n");
int i = 1;
do {
wait(NULL);
} while (i-- > 0);
Run Code Online (Sandbox Code Playgroud)
您没有关闭子级中管道的足够文件描述符,或者父级中的任何管道的文件描述符。
\n\n经验法则:如果您\n \n没有连接到标准输入或标准输出的管道末端,请尽快dup2()关闭\n \nas返回的两个原始文件描述符。\n特别是,您应该在使用任何文件之前关闭它们。 pipe()\n exec*()\n函数家族的成员。
dup()如果您使用\n \nor\n fcntl()\n复制描述符,则该规则也适用F_DUPFD
这是正确关闭管道的工作代码。execvp()我删除了命令的路径部分,因为(a)它们对于我的机器来说是错误的,并且(b)如果指定命令的路径,则使用没有意义。我报告了大多数错误(但我不检查read()和的结果write()调用的结果。我还报告子级的退出状态。如果子级无法执行命令,则报告并退出。您的代码带有 \'save_stdin`等等更加令人困惑,因为变量在父级中未初始化,这是序列所在的位置:
dup2(save_stdin, 0);\ndup2(save_stdout, 1);\nclose(save_stdin);\nclose(save_stdout);\nRun Code Online (Sandbox Code Playgroud)\n\n被处决。你和我都不知道这两个dup2()调用做了什么 \xe2\x80\x94 但它们很可能失败了,或者它们对您的标准 I/O 通道做了一些奇怪的事情。
#include <stdio.h>\n#include <unistd.h>\n#include <stdlib.h>\n\n#define BUF_SIZE 100\n\nint main(void)\n{\n pid_t pid1, pid2;\n int fd[2];\n\n char *argv1[] = { "ps", "-j", NULL }; // Remove PATH because using execvp()\n char *argv2[] = { "more", NULL }; // Remove PATH because using execvp()\n\n char prompt[] = "Press enter: ";\n char buffer[BUF_SIZE];\n\n write(STDOUT_FILENO, prompt, sizeof(prompt) - 1);\n\n ssize_t readIn = readIn = read(STDIN_FILENO, buffer, BUF_SIZE);\n buffer[readIn - 1] = \'\\0\';\n\n printf("readIn: %zd\\n", readIn);\n\n if (pipe(fd) < 0)\n {\n fprintf(stderr, "failed to create pipe\\n");\n exit(EXIT_FAILURE);\n }\n\n if ((pid1 = fork()) < 0)\n {\n fprintf(stderr, "failed to fork - 1\\n");\n exit(EXIT_FAILURE);\n }\n\n if (pid1 == 0) // child\n {\n dup2(fd[1], STDOUT_FILENO);\n close(fd[0]);\n close(fd[1]);\n execvp(argv1[0], argv1);\n fprintf(stderr, "failed to execute %s\\n", argv1[0]);\n exit(EXIT_FAILURE);\n }\n\n if ((pid2 = fork()) < 0)\n {\n fprintf(stderr, "failed to fork - 2\\n");\n exit(EXIT_FAILURE);\n }\n\n if (pid2 == 0)\n {\n dup2(fd[0], STDIN_FILENO);\n close(fd[0]);\n close(fd[1]);\n execvp(argv2[0], argv2);\n fprintf(stderr, "failed to execute %s\\n", argv2[0]);\n exit(EXIT_FAILURE);\n }\n\n close(fd[0]);\n close(fd[1]);\n\n int corpse;\n int status;\n while ((corpse = wait(&status)) > 0)\n fprintf(stderr, "%d: child %d exited with status 0x%.4X\\n",\n (int)getpid(), corpse, (unsigned)status);\n\n return 0;\n}\nRun Code Online (Sandbox Code Playgroud)\n\n该程序是pipe41(对输出进行一些小的编辑以删除实际上不需要让您了解我在其他窗口中所做的事情):
$ ./pipe41\nPress enter: \nreadIn: 1\nUSER PID PPID PGID SESS JOBC STAT TT TIME COMMAND\njonathanleffler 6618 6617 6618 0 1 S s000 0:00.11 -bash\njonathanleffler 6629 6628 6629 0 1 S+ s001 0:00.04 -bash\njonathanleffler 6660 6645 6660 0 1 S+ s002 0:00.04 -bash\njonathanleffler 6716 6695 6716 0 1 S+ s003 0:00.04 -bash\njonathanleffler 6776 6746 6776 0 1 S+ s004 0:00.04 -bash\njonathanleffler 6800 6771 6800 0 1 S+ s005 0:00.04 -bash\njonathanleffler 7487 7486 7487 0 1 S s006 0:00.04 -bash\njonathanleffler 9558 9557 9558 0 1 S s007 0:00.06 -bash\njonathanleffler 10375 9558 10375 0 1 S+ s007 0:00.01 ./pipe41\njonathanleffler 10377 10375 10375 0 1 S+ s007 0:00.00 more\n(END)10375: child 10376 exited with status 0x0000\n10375: child 10377 exited with status 0x0000\n$\nRun Code Online (Sandbox Code Playgroud)\n