我实际上正在做一个项目,我们正在尝试用C语言重新创建一个bash终端。我在代码中处理管道时遇到了一些问题。正如你在写“cat”时所知道的|ls”,它首先显示ls结果,然后打开标准输入,但只打开一行。问题是我处理管道的方式,首先它显示ls结果为异常,但在标准输入阅读之后,直到我按下CTRL-D。我想让它在第一行之后结束,就像bash一样。我想我的水管有问题,但我试着用其他方法改造,结果总是一样的问题。
我的代码:
void make_command(t_list *cmds, char **env)
{
char *path;
int exec;
path = get_path((char *)cmds->content[0], env);
if (!path)
return ;
exec = execve(path, (char **)cmds->content, env);
if (exec < 0)
exit_error();
}
void make_pipe(t_list *cmds, char **env, t_listpids **pids, int *fd_old)
{
pid_t pid;
int tube[2];
while (cmds)
{
if (pipe(tube) == -1)
exit_error();
pid = fork();
if (pid == 0)
{
if (cmds->previous) //only if not first command
{
dup2((*fd_old), STDIN_FILENO);
close(*fd_old);
}
if (cmds->next) //only if not last command
{
dup2(tube[1], STDOUT_FILENO);
close(tube[1]);
}
make_command(cmds, env); //execute command function with execve
close(tube[0]);
close(tube[1]);
exit(EXIT_SUCCESS);
}
else
{
add_pids(pid, pids); //add pid to chained list of pids (used to waitpid them after)
*fd_old = tube[0];
close(tube[1]);
cmds = cmds->next;
while (cmds && ft_strncmp((char *)cmds->content[0], "|", 1) == 0)
cmds = cmds->next;
}
}
}
1条答案
按热度按时间yzuktlbb1#
当你写“猫”的时候|ls”时,首先显示ls结果,然后打开标准输入,但仅显示一行。
这是一个令人困惑的描述,在很大程度上是荒谬的管道发生了什么。这里有一个更好的:
ls
运行到完成,不等待任何输入,同时cat
等待其标准输入上的输入,并在阅读一行后终止,不将该行回显到终端。两者之间的重要区别:
cat
等待它的意义上,ls
命令并不首先运行。它本身简单地不必等待任何用户输入,因此其输出被立即显示。cat
命令从 shell 继承其标准输入,并且从该文件读取直到其终止。由于处于前台,它代替 shell 接收输入。此外,
cat
在阅读一行后终止是偶然的。如果有更多的行排队等待它立即读取,或者可能由于某种原因ls
运行缓慢,它可能会读取更多的行。当它终止时,这是因为它试图写入没有读取器的管道。这会导致SIGPIPE
被传递给它,从而导致它终止。这些都是相关的,因为它指出了您所描述的(错误)行为的问题。在您的例子中,
cat
一直阅读输入,直到您键入Ctrl-D
,这立即告诉我,要么它的标准输出根本没有连接到管道,要么它所连接的管道仍然在某个地方打开以供读取。知道了要查找什么,我们就可以确信,是的,父进程无法关闭它创建的管道的“每一个”的读端,它将它们保存在
*fd_old
中,一次一个,以便能够重定向下一个子进程的标准输入,但是在提供了重定向之后,它泄漏了打开文件描述符的副本。它只需要在下一个
fork()
之前保持FD打开,所以也许您需要在else
块中关闭它,如下所示:在循环结束后,你可能还需要关闭最后一个变量,我通常是这么认为的,但是你是通过指针间接存储它的,这让我不确定你到底想做什么。