【发布时间】:2018-11-19 07:23:51
【问题描述】:
我正在尝试在 C 中实现一个处理多个管道的基本 shell。它等待输入并在 for 循环中执行命令。当它收到EOF时,它停止等待输入并退出。
现在,当我输入流水线命令时,我的 shell 会输出正确的输出,例如ls | wc | grep ... 但它停止等待输入并退出外部 while 循环而不是等待下一行输入。
我发现发生这种情况是因为我的 while 循环中的 fgets 返回 null(stdin 以某种方式获取 EOF?)。在创建分叉、创建管道或执行时,我没有收到任何错误。
但是,如果我一次输入一个命令而没有任何管道,例如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 是否以某种方式发送到标准输入,所以封闭的fgets 返回NULL?
【问题讨论】:
-
"这是我的代码的高度简化版本,省略了大部分错误检查" - 那么为什么要发布它呢?见minimal reproducible example。
-
你试过在你的程序上运行
strace -f吗? -
因为如果我发布了我的整个代码,那么人们想要阅读的内容太多了?这已经足够简化,因此任何人都可以看到我的方法而不会省略重要的行(fork、pipe、dup2)。
-
如果你不知道bug在哪里,你怎么知道哪些行重要哪些不重要?
-
因为我得到了处理除这部分代码之外的所有内容的代码,我保证这是一个正确的解决方案。我知道错误在于这部分,它与我调用
dup2、fork和/或pipe有关。