C语言 能够执行多个管道命令的简单Shell

e0bqpujr  于 2023-03-28  发布在  Shell
关注(0)|答案(1)|浏览(141)

正如标题所说,这段代码试图实现一个可以使用多个管道命令的shell。它可以很好地处理单个命令,但是每当命令被管道传输时,程序在某个点冻结。我试着调试,但由于某种原因,我无法到达子进程内的断点。如果有人能帮助我修复此代码,将有很大的帮助。这可能是关闭管道,我搞砸了,但我不确定。我花了几个小时,所以我张贴在堆栈溢出作为最后的手段。感谢您的帮助刚刚意识到,它不与tr命令工作。

void executefork(char **commands, int num_commands, int input_fd) {
    if (num_commands == 0) {
        
        return;
    }

    int pipefd[2];
    if (pipe(pipefd) == -1) {
        perror("pipe");
        return;
    }

    pid_t pid = fork();
    if (pid == -1) {
        perror("fork");
        exit(EXIT_FAILURE);
    } else if (pid == 0) {
        
        if (num_commands > 1) {
            if (dup2(pipefd[1], STDOUT_FILENO) == -1) {
                perror("dup2");
                exit(EXIT_FAILURE);
            }
        }

        if (input_fd != STDIN_FILENO) {
            if (dup2(input_fd, STDIN_FILENO) == -1) {
                perror("dup2");
                exit(EXIT_FAILURE);
            }
        }

        close(pipefd[0]);
        close(pipefd[1]);
        
        execute(commands[0]);

    } else {

        close(pipefd[1]);

        if (num_commands > 1) {
            printf("\nReached");
            executefork(commands + 1, num_commands - 1, pipefd[0]);
        }
        close(pipefd[0]);
        int status;
        if (waitpid(pid, &status, 0) == -1) {
            perror("waitpid");
            exit(EXIT_FAILURE);
        }

    }
}
int main(int argc, char *argv[]) {
    size_t len = 1024;

    ssize_t cha;
    char *line = (char *) malloc(len);
    
    char *pipeCmd[strlen(line)];

    while (1) {
        printf("sish> ");
        cha = getline(&line, &len, stdin);
        if (cha == -1 || cha == 0) {
            continue;
        }
        line[strcspn(line, "\n")] = '\0';
        if (line[0] == '\0') {
            continue;
        }

        
        char *copy = strdup(line);
        char *com = strtok(copy, "|");
        int index = 0;
        while (com != NULL) {
            pipeCmd[index++] = com;
            addHistory(com);
            com = strtok(NULL, "|");
        }
        pipeCmd[index] = NULL;

      
        executefork(pipeCmd, index, STDIN_FILENO);

        if (flag == 1) {
            break;
        }
    }

    free(line);

    return 0;
}
void
execute (char *phrase)
{
  char *va = strdup (phrase);
  char *token = strtok (strdup (va), " ");

  if (strcmp (token, "history") == 0)
    {
      history (phrase);
      return;
    }
  else if (strcmp (token, "exit") == 0)
    {
      flag = 1;
      return;
    }
  else if (strcmp (token, "cd") == 0)
    {
      changeDir (phrase);
      return;
    }
  else
    {
      pid_t cpid;
      cpid = fork ();
      if (cpid < 0)
    {
      perror ("fork error");
      exit (-1);
    }
      if (cpid == 0)
    {
      
      char *pass[sizeof (phrase) / sizeof (char *) + 1];
      int i = 0;
      while (token != NULL && i < sizeof (pass) / sizeof (char*))
        {
          pass[i++] = token;
          token = strtok (NULL, " ");
        }
      pass[i] = NULL;
      execvp (pass[0], pass);
      perror ("execvp failed");
      exit (EXIT_FAILURE);

    }
      else
    {
     
      waitpid (cpid, NULL, 0);
    }
    }
}
input and output code 
sish> cat pi.txt //This part is right 
Hello people, Run debug save share stop download languages
sish> cat pi.txt | grep the // This just keeps on going on.
sish> echo "Hi how are you" | tr h w
tr: missing operand after ‘h’
Two strings must be given when translating.
Try 'tr --help' for more information.
waitpid: No child processes
gywdnpxw

gywdnpxw1#

听起来,代码中管道的设置和关闭方式可能存在问题。如果没有看到代码本身,很难确切地说出问题所在,但这里有一些可能会有所帮助的一般提示:
确保关闭每个进程中未使用的所有文件描述符。这在使用管道时尤其重要,因为保持文件描述符打开可能会导致进程挂起或崩溃。您可以使用close()系统调用关闭文件描述符。
检查您在每个进程中使用了正确的管道端点。每个管道都有两个端点,一个用于写入,一个用于阅读。确保您在每个进程中使用了正确的端点,并且您没有意外地尝试从您正在写入的管道中读取(反之亦然)。
验证是否正确设置了管道。设置多个管道时,需要创建管道数组,并使用循环创建每个管道。请确保以正确的顺序创建管道,并且不会意外地用新管道覆盖管道。
使用错误检查来确保每个系统调用都成功。如果系统调用失败,则可能导致进程挂起或崩溃。您可以检查系统调用的返回值以查看它是否成功,如果失败,则使用perror()打印错误消息。
尝试使用像gdb这样的调试器来单步调试你的代码,看看它在哪里卡住了。你可以使用断点在代码中的特定点暂停执行,然后检查程序状态,看看发生了什么。确保使用调试符号(例如使用-g标志)编译你的代码,这样调试器就可以提供有用的信息。
我希望这些提示能帮助你追踪这个问题

相关问题