gpt4 book ai didi

c - 在 C 中实现 shell - 管道输入具有正确的输出,但退出循环

转载 作者:行者123 更新时间:2023-11-30 14:48:03 25 4
gpt4 key购买 nike

我正在尝试用 C 语言实现一个处理多个管道的基本 shell。它等待输入并在 for 循环中执行命令。当接收到EOF时,停止等待输入并退出。

现在,当我输入管道命令时,我的 shell 会输出正确的输出,例如ls |厕所 | grep ...它停止等待输入并退出外部 while 循环,而不是等待下一行输入。

我发现发生这种情况是因为 while 循环中的 fgets 返回 null (stdin 以某种方式获取 EOF?)。我在创建 fork 、创建管道或执行时没有收到任何错误。

但是,如果我在没有任何管道的情况下一次输入一个命令,例如ls,它成功打印出正确的输出等待下一行输入,正如它应该的那样。

我的程序在尝试执行每个命令之前将每一行输入解析为一个struct(下面省略)。 struct 的设计使我可以轻松地将解析后的参数传递到 execvp 中,这里我将不再描述。

这是我的代码的高度简化版本,省略了大部分错误检查:

FILE* input;
char line[MAX_LINE];

input = stdin;
printf("> ");
fflush(stdout);

while (fgets(line, sizeof(line), input)) {
int i;
struct cmdLine;
/* struct defined elsewhere
** commands = # of commands in parsed input
** start = index where a command and its args start
** args[] = array holding each command/arg
*/

/* parse input line into cmdLine */
...

/* exec all commands in pipeline except the last */
for (i = 0; i < cmdLine.commands-1; ++i) {
int pd[2];
pipe(pd);

if (fork() == 0) {
dup2(pd[1], 1);
execvp(cmdLine.args[cmdLine.start[i]], &(cmdLine.args[cmdLine.start[i]]));
} else {
wait(NULL);
}

dup2(pd[0], 0);
close(pd[1]);
}

/* exec last command */
if (fork() == 0) {
execvp(cmdLine.args[cmdLine.start[i]], &(cmdLine.args[cmdLine.start[i]]));
} else {
wait(NULL);
}

if (stdin == input) {
printf("> "); /* print shell prompt */
fflush(stdout);
}
}

我几乎可以肯定我的欺骗在某个地方搞砸了,但我已经尝试了几个小时,但我不明白我做错了什么。 EOF 是否以某种方式发送到 stdin,以便封闭的 fgets 返回 NULL

最佳答案

通过使用 0 (=stdin) 作为第二个参数调用 dup2,您将在每次迭代结束时关闭原始 stdinfor 循环,因此您无法再通过原始标准输入实际与您的程序对话。

您的代码中的问题是您试图将所有管道的连接交给其他人;那是行不通的。这是应该起作用的:

  • 对于 n 个程序,您至少需要 (n-1) 个管道。
  • 将所有管道 FD 记录在数组中:一个用于管道的输入侧(写入),一个用于输出侧(从中读取)。
  • 对于您要 fork 的每个进程,将前一个管道的输出(如果有)连接到其 stdin,并将下一个管道的输入连接到其 stdout(或主程序的stdout(如果您正在处理管道链中的最后一个进程)。
  • fork 完所有内容后:在循环中,对管道的输出 FD 进行 poll(),从任何具有事件的管道中读取数据,然后写入下一个管道的输入(您的管道)自己的 stdout 在最后)。如果其中一个管道上出现 EOF,请关闭下一个管道的输入(并从输出数组中删除 EOF 的管道输出)。一旦所有 FD 都关闭,就退出循环。

编辑:我只是想到了另一种更简单的方法,需要较少的代码更改,但我还没有完全考虑清楚。 :) 问题是你正在破坏你自己的标准输入。如果您在 fork 的子进程中执行所有这些操作(即整个“处理一行命令”),则在进程之间替换 stdin 根本不会影响父进程。不过,这将需要内核中的大量缓冲,因此它可能无法扩展。

关于c - 在 C 中实现 shell - 管道输入具有正确的输出,但退出循环,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/50774083/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com