shell 中的 C 无限循环在将命令输入其中后

C Infinite loop in shell after piping commands into it

我目前正在尝试为 class 构建自定义 shell。我能够毫无问题地执行从此 shell 发出的命令,但是如果我将我的命令传递到我的 shell,我最终会陷入无限循环。我不知道为什么会发生这种情况。下面的示例将导致无限循环。

echo "ls" | ./myshell

当然我必须重定向程序的输出,如果命令中出现管道,例如ls | grep test。在我的 shell 中,这完美无缺。我正在使用 fork()execv(),当然还有 pipe + dup 用于在子进程之间重定向流。

好像fgets() 不会从上次发出的命令中清除STDIN_FILENO

对于命令 echo "ls" | ./myshell,我的程序将执行以下操作:(最小工作示例)

编辑:最小工作示例

#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <fcntl.h>
#include <stdio.h>
#include <string.h>

int running = 1;
int exit_code = 0;

char cwd[256];
char command[256];
char args[10][256];
char buffer[256] __attribute__((aligned(4096)));

void handle_command(char* buffer, int buffer_size)
{
  int c = 0;
  int argsCount = -1;
  int lastIndex = 0;

  for (c = 0; c < buffer_size && buffer[c]; c++)
  {
    if (argsCount > 10)
    {
      argsCount = 10;
      printf("Argument Count is limited to 10 (no dynamic memory allocation) all other arguments will be ignored\n");
      break;
    }
    if (buffer[c] == '\r' || buffer[c] == '\n' || buffer[c] == ' ')
    {
      if (argsCount == -1)
      {
        memcpy(command, buffer + lastIndex, c - lastIndex);
        command[c - lastIndex] = 0;
      }
      else
      {
        memcpy(args[argsCount], buffer + lastIndex, c - lastIndex);
        args[argsCount][c - lastIndex] = 0;
      }
      argsCount++;
      lastIndex = c + 1;

    }
  }

  if (strcmp(command, "exit") == 0)
  {
    c = 4;
    while (buffer[c] == ' ')
      c++;
    exit_code = atoi(&buffer[c]);
    printf("Exiting Shell with exit_code %d\n", exit_code);
    running = 0;
  }
  else if (strcmp(command, "") != 0)
  {
    // -------------- Add structure to commands --------------------------------
    struct command_struct{
      char *options[10];
    } sub_commands[1];
    // Simplified code, there would be a dynamic amount of sub_commands
    // and further logic to handle pipes and < > >>

    // initialize first command, would work dynamically
    sub_commands[0].options[0] = command;
    sub_commands[0].options[1] = NULL;

    int status;
    int pid = fork();
    if (pid == 0) {
      execvp(sub_commands[0].options[0], sub_commands[0].options);
      perror("Error: Reached code after execvp\n");
    } else if (pid < 0) {
      perror("Cannot fork!\n");
    }
    wait(&status);
  }
}


int main(int argc, char *argv[])
{
  cwd[0] = '/';

  do
  {
    printf("\n%s %s%s", "SHELL:", cwd, "> ");
    fgets(buffer, 255, stdin);
    buffer[255] = 0;
    handle_command(buffer, 256);
    for (size_t a = 0; a < 256; a++)
      buffer[a] = 0;

  } while (running);

  return exit_code;
}

EDIT 我必须指出,此代码的部分内容已在 class.

中给出

如有任何帮助,我们将不胜感激!

OP 代码只会在 running == 0.

时退出 main() do 循环

running = 0; 仅在 strcmp(command, "exit") == 0 时出现,并且不清楚通过字符串解析 just "exit" 是否曾经加载到 command。注意:command 没有在每次 handle_command() 调用时被完全初始化,并且 command 不需要是一个全局变量。

调整代码以在 fgets() returns NULL 时退出并查看行处理。建议:

do {
  printf("\n%s %s%s", "SHELL:", cwd, "> ");
  if (fgets(buffer, sizeof buffer, stdin) == NULL) {
    break; 
  }
  // lop off potential end-of-line character(s)
  buffer[strcspn(buffer,"\r\n")] = '[=10=]';
  handle_command(buffer, sizeof buffer);
} while (running);