流水线的 C 语言实现中的 Mini Shell:等待子进程问题

Mini Shell in C implementation of pipeline : wait for child process problem

提问人:Jix 提问时间:11/14/2023 更新时间:11/14/2023 访问量:36

问:

我一直在尝试在使用 C 构建的迷你 shell 中实现管道功能。但是我注意到,当管道包含需要等待其他进程的进程并输出到 stderr 而不是 stdout 时,效果是使管道中的下一个命令也等待。

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <unistd.h>
#include "variante.h"
#include <sys/wait.h>
#include "readcmd.h"
#include <stdbool.h>


void execute_single_command(char **cmd){
   execvp(cmd[0],cmd);
}

void execute_pipeline(struct cmdline *l){     // *head_over=head // *head - > node 1
   int previous_pipe_read = -1;
   int file_descriptor[2];
   for(size_t i=0 ; l->seq[i] != 0; i++){
       pipe(file_descriptor);

       pid_t child_pid = fork();
       char**cmd = l->seq[i];
       

       if (child_pid == -1) {
           perror("fork error");
           exit(EXIT_FAILURE);
       }
       

       if(child_pid == 0){
           // Child process
           

           if (previous_pipe_read != -1)
           {
               // Redirect  to the reading side of the pipe ( file_descriptor[0] ) and use it as stdint
               dup2(previous_pipe_read, 0);
               close(previous_pipe_read);
           }

           if (l->seq[i + 1] != 0)
           {
               // Redirect stdout to the writing side of the pipe ( file_descriptor[1] )
               dup2(file_descriptor[1], 1);
           }
           // Close unecessary file descriptor
           close(file_descriptor[0]);
           // Execute command
           execute_single_command(cmd);
       }
       else{

           // Parent process
           // Handle the signal received by a terminated child process
           close(file_descriptor[1]); // Close unecessary file descriptor
           
           if (previous_pipe_read != -1)
           {
               close(previous_pipe_read);
           }

           
           if (!l->bg)
           {
               int status;
               waitpid(child_pid, &status, 0);
           }


           // save the reading side of the pipe (aka the ouput of the previous command) into the variable previous_pipe_read
           previous_pipe_read = file_descriptor[0];
       }



   }


}



int main()
{
//  unrelated code

   while (1)
   {
       struct cmdline *l;
       char *line = 0;
       char *prompt = "ensishell>";

       /* Readline use some internal memory structure that
          can not be cleaned at the end of the program. Thus
          one memory leak per command seems unavoidable yet */
       line = readline(prompt);
       if (line == 0 || !strncmp(line, "exit", 4))
       {
           terminate(line);
       }

#if USE_GNU_READLINE == 1
       add_history(line);
#endif

#if USE_GUILE == 1
       /* The line is a scheme command */
       if (line[0] == '(')
       {
           char catchligne[strlen(line) + 256];
           sprintf(catchligne, "(catch #t (lambda () %s) (lambda (key . parameters) (display \"mauvaise expression/bug en scheme\n\")))", line);
           scm_eval_string(scm_from_locale_string(catchligne));
           free(line);
           continue;
       }
#endif

       /* parsecmd free line and set it up to 0 */
       l = parsecmd(&line);

       /* If input stream closed, normal termination */
       if (!l)
       {

           terminate(0);
       }

       if (l->err)
       {
           /* Syntax error, read another command */
           printf("error: %s\n", l->err);
           continue;
       }

       if (l->in)
           printf("in: %s\n", l->in);
       if (l->out)
           printf("out: %s\n", l->out);
       if (l->bg)
           printf("background (&)\n");

       /* Display each command of the pipe */
       execute_pipeline(l);
   }
}

例如:

sleep 5 | echo " Hello World"

它会等待 5 秒钟,然后回显 Hello World,这不是正确的事情。我正在反思,也许我需要检查上一个命令是否输出到 stdout 以应用管道效果。

这是我的代码:

C

评论


答: 暂无答案