将多个管道连接在一起时遇到问题
Having trouble connecting multiple pipes together
我正在尝试创建一个小的 shell 程序,它可以接受多个命令并将它们链接在一起并最终执行它们。
到目前为止,我已经创建了一个列表来存储输入并将它们保存到一个名为 command 的数组中,我在其中使用 strtok 拆分输入并将结果放入一个数组中。因此,如果我输入 cat -n filename.txt,我会将 cat at command[0] -n at command[1] 和 filename.txt at command[2]。我还在每个命令的末尾添加了 NULL,(在我的 cat 示例中以命令 [3] 结束)。
我能够执行第一个命令,但如果我尝试使用第二个命令,第一个命令是唯一要执行的命令,所以我怀疑我的管道未正确链接。
这是我目前所做的:
pid_t pid;
int status;
int pipes[number_arguments - 1][2];
// Create pipes
for (int i = 0; i < number_arguments - 1; i++)
{
if (pipe(pipes[i]))
{
perror("pipe");
exit(EXIT_FAILURE);
}
}
// Create new processes
for (int i = 0; i < number_arguments; i++)
{
pid = fork();
if (pid == -1)
{
perror("fork");
exit(EXIT_FAILURE);
}
if (pid == 0)
{
// First child
if (i == 0)
{
dup2(pipes[i][WRITE_END], STDOUT_FILENO);
}
//Middle child
if ((i != 0) && ((i+1) != number_arguments))
{
dup2(pipes[i-1][READ_END], STDIN_FILENO);
dup2(pipes[i][WRITE_END], STDOUT_FILENO);
}
// Last child
if ((i+1) == number_arguments)
{
dup2(pipes[i][WRITE_END], STDOUT_FILENO);
}
// close all pipes
for (int j = 0; j < number_arguments - 1; j++)
{
close(pipes[j][READ_END]);
close(pipes[j][WRITE_END]);
}
if (execvp(command[0], command) < 0)
{
perror("exec failure");
exit(EXIT_FAILURE);
}
}
// Parent
else
{
for (int j = 0; j < number_arguments - 1; j++)
{
close(pipes[j][READ_END]);
close(pipes[j][WRITE_END]);
}
waitpid(pid, &status, 0);
}
}
我很感谢能得到的任何帮助。
抱歉,如果我犯了一些错误 post,这是我的第一个 post。
您在命令启动循环之外正确地创建了管道,并且您正确地关闭了 children 中的所有管道文件描述符。后者尤其是一个常见问题。
但是,您错误地让 parent 进程在启动第一个 child 后关闭所有管道,因此第二个和后续的孩子没有管道可以使用。您还需要等待管道中的每个 child 结束,然后再启动下一个 — 您需要同时 children 到 运行。
您需要 parent 进程来启动所有 child 进程,然后才等待管道完成。
parent 进程(可能)需要记录其所有 children 的 PID。在启动所有 children 之前,它不得关闭其管道副本(但关键是它随后会这样做)。它将需要围绕 waitpid()
使用循环。它必须等到最后一个 child(管道中的最后一个进程)终止。它可能会也可能不会等到管道中所有较早的 children 也终止。
你应该做的一件事,尤其是当事情出错时,是错误检查来自系统调用的 return 值。您会发现 dup2()
和 close()
调用在第二次迭代中失败并显示 EBADF
— 错误的文件描述符。即使一切正常,检查系统调用并在它们失败时提出适当的策略也不是一个坏主意。
我正在尝试创建一个小的 shell 程序,它可以接受多个命令并将它们链接在一起并最终执行它们。
到目前为止,我已经创建了一个列表来存储输入并将它们保存到一个名为 command 的数组中,我在其中使用 strtok 拆分输入并将结果放入一个数组中。因此,如果我输入 cat -n filename.txt,我会将 cat at command[0] -n at command[1] 和 filename.txt at command[2]。我还在每个命令的末尾添加了 NULL,(在我的 cat 示例中以命令 [3] 结束)。
我能够执行第一个命令,但如果我尝试使用第二个命令,第一个命令是唯一要执行的命令,所以我怀疑我的管道未正确链接。
这是我目前所做的:
pid_t pid;
int status;
int pipes[number_arguments - 1][2];
// Create pipes
for (int i = 0; i < number_arguments - 1; i++)
{
if (pipe(pipes[i]))
{
perror("pipe");
exit(EXIT_FAILURE);
}
}
// Create new processes
for (int i = 0; i < number_arguments; i++)
{
pid = fork();
if (pid == -1)
{
perror("fork");
exit(EXIT_FAILURE);
}
if (pid == 0)
{
// First child
if (i == 0)
{
dup2(pipes[i][WRITE_END], STDOUT_FILENO);
}
//Middle child
if ((i != 0) && ((i+1) != number_arguments))
{
dup2(pipes[i-1][READ_END], STDIN_FILENO);
dup2(pipes[i][WRITE_END], STDOUT_FILENO);
}
// Last child
if ((i+1) == number_arguments)
{
dup2(pipes[i][WRITE_END], STDOUT_FILENO);
}
// close all pipes
for (int j = 0; j < number_arguments - 1; j++)
{
close(pipes[j][READ_END]);
close(pipes[j][WRITE_END]);
}
if (execvp(command[0], command) < 0)
{
perror("exec failure");
exit(EXIT_FAILURE);
}
}
// Parent
else
{
for (int j = 0; j < number_arguments - 1; j++)
{
close(pipes[j][READ_END]);
close(pipes[j][WRITE_END]);
}
waitpid(pid, &status, 0);
}
}
我很感谢能得到的任何帮助。
抱歉,如果我犯了一些错误 post,这是我的第一个 post。
您在命令启动循环之外正确地创建了管道,并且您正确地关闭了 children 中的所有管道文件描述符。后者尤其是一个常见问题。
但是,您错误地让 parent 进程在启动第一个 child 后关闭所有管道,因此第二个和后续的孩子没有管道可以使用。您还需要等待管道中的每个 child 结束,然后再启动下一个 — 您需要同时 children 到 运行。
您需要 parent 进程来启动所有 child 进程,然后才等待管道完成。
parent 进程(可能)需要记录其所有 children 的 PID。在启动所有 children 之前,它不得关闭其管道副本(但关键是它随后会这样做)。它将需要围绕 waitpid()
使用循环。它必须等到最后一个 child(管道中的最后一个进程)终止。它可能会也可能不会等到管道中所有较早的 children 也终止。
你应该做的一件事,尤其是当事情出错时,是错误检查来自系统调用的 return 值。您会发现 dup2()
和 close()
调用在第二次迭代中失败并显示 EBADF
— 错误的文件描述符。即使一切正常,检查系统调用并在它们失败时提出适当的策略也不是一个坏主意。