我正在尝试创建一个小型外壳程序,该程序可以接受多个命令并将它们链接在一起,最后执行它们。
到目前为止,我已经创建了一个列表来存储输入,并将它们保存到名为command的数组中,在这里我使用strtok将输入分割开并将结果放入数组中。因此,如果我输入cat -n filename.txt,则将cat放在command [0] -n到command [1],并将filename.txt放在command [2]。我还在每个命令的末尾添加了NULL(在我的cat示例中以command [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);
}
}
我很感谢我能得到的任何帮助。
很抱歉,如果我在发布此帖子时出错,这是我的第一篇帖子。
答案 0 :(得分:0)
您可以在命令启动循环之外正确创建管道,并正确关闭子级中的所有管道文件描述符。后者尤其是一个常见问题。
但是,在启动第一个孩子之后,您错误地使父进程关闭了所有管道,因此第二个及以后的孩子没有管道可以使用。您还需要等待管道中的每个孩子死亡,然后再启动下一个孩子-您需要这些孩子同时运行。
您需要父进程来启动所有子进程,然后才等待管道完成。
父进程将(可能)需要保留其所有子PID的记录。在启动所有子项之前,它一定不能关闭其管道副本(但是这样做很关键)。它将需要在waitpid()
周围使用循环。它必须等到最后一个子项(管道中的最后一个进程)终止。它可能会或可能不会等到管道中所有较早的子项都终止之后。
您应该做的一件事,尤其是在出现问题时,是对系统调用的返回值进行错误检查。您会发现dup2()
和close()
调用在第二次迭代中失败,并带有EBADF
(错误的文件描述符)。即使一切正常,检查系统调用并在失败时提出适当的策略也不错。