C中的多管道bash样式

C中的多管道bash样式,c,shell,unix,pipe,C,Shell,Unix,Pipe,我知道有很多线程都在讨论这个问题,但我真的不明白如何解决这个问题 我正在尝试制作一个可以执行linux命令的shell,比如ps | grep | less 我已经完成了解析,将每个命令及其参数放入一个简单的链表中 这是我的实现,它不起作用。希望这足够清楚 if ((son = fork()) < 0) return printerr_sys("Unable to fork", 0); if (son == 0) { if (first > 1 &&

我知道有很多线程都在讨论这个问题,但我真的不明白如何解决这个问题

我正在尝试制作一个可以执行linux命令的shell,比如ps | grep | less 我已经完成了解析,将每个命令及其参数放入一个简单的链表中

这是我的实现,它不起作用。希望这足够清楚

if ((son = fork()) < 0)
  return printerr_sys("Unable to fork", 0);
if (son == 0)
  {
    if (first > 1 && data->format[first - 1] &&
    is_directing_elt(data->format[first - 1]) == DIRECT_TPIPE)
       dup2(tube_p[0], STDIN_FILENO);
       first = make_argv(data, first, &argv);
    if (next)
     {
      dup2(tube_v[1], STDOUT_FILENO);
      close(tube_v[0]);
     }
    if (execvp(argv[0], argv) < 0)
      return printerr_cmd(argv[0], 1);
  }
else
  {
    if (next)
        {
           close(tube_v[1]);
           cmdline_executer(data, next, tube_v);
        }
    waitpid(son, &(data->lastcmd), WUNTRACED);
    data->lastcmd = WEXITSTATUS(data->lastcmd);
  }
return TRUE;
我的问题是:

正确的实施方式是什么? 可以用递归来实现吗? 我需要从右到左还是从左到右分叉,逻辑上它会给出相同的结果?
进程独立运行,因此您需要在fork之前为至少第一对命令设置管道,但您在子进程中这样做==0。您可以编写一个递归解决方案,只要剩下至少两个命令,就可以创建一个管道,然后分叉,然后运行第一个命令。

进程独立运行,因此您需要在分叉之前为至少第一对命令设置管道,但您是在子命令==0中这样做的。您可以编写一个递归解决方案,只要剩下至少两个命令,就可以创建一个管道,然后分叉,然后运行第一个命令。

这是我在计算机科学生涯中必须用C为操作系统主题实现的UNIX Shell的一部分

这可能是一个小问题,我没有检查fork是否<0,等等,但主要思想是正确的

>可以用递归来实现吗


大多数情况下,如果我不使用递归就可以编写类似的可理解代码,我会尽量避免递归

在我的计算机科学生涯中,我必须用C语言为操作系统主题实现UNIX Shell的一部分

这可能是一个小问题,我没有检查fork是否<0,等等,但主要思想是正确的

>可以用递归来实现吗


大多数情况下,如果我不使用递归就可以编写类似的可理解代码,我会尽量避免递归

哦,天哪,对不起,我认错了。希望这是允许的。请将代码放入代码块并格式化。编辑您的帖子并在每行前面添加四个空格。sh从左向右分叉,我相信它只关心最右边的过程,假设它退出后,所有其他进程都将很快消失,并显示一个SIGPIPE,假设您正确关闭了所有管道。@只需Jake或高亮显示所有代码,然后按“代码格式”按钮1和0图标。别担心,Stack Overflow的markdown编辑器实际上工作得很好:哦,天哪,很抱歉出现这种情况。希望这是允许的。请将代码放入代码块并格式化。编辑您的帖子并在每行前面添加四个空格。sh从左向右分叉,我相信它只关心最右边的过程,假设它退出后,所有其他进程都将很快消失,并显示一个SIGPIPE,假设您正确关闭了所有管道。@只需Jake或高亮显示所有代码,然后按“代码格式”按钮1和0图标。别担心,Stack Overflow的markdown编辑器实际上工作得很好:很难找到实现的任何线索?我认为我写的是一个很大的线索。我脑海中浮现出:runcmdsinpipe,list{ifinpipe reopen stdin使用inpipe;iflist->next{create outpipe;fork;runcmdsoutpipe,list->next;reopen stdout使用outpipe;}exec*list;}并用runcmdsnall,list启动它。也许runcmds应该像它做的第一件事一样分叉。很难找到一个实现任何线索?我认为我写的是一个相当大的线索。我脑海中浮现出:runcmdsinpipe,list{ifinpipe reopen stdin使用inpipe;iflist->next{create outpipe;fork;runcmdsoutpipe,list->next;reopen stdout使用outpipe;}exec*list;}并用runcmdsnall,list启动它。也许runcmds应该像它做的第一件事一样分叉。
/* Executes the command 'buffer' assuming that doesn't contain redirections */
void execute_only_pipes(char* buffer)
{
    char *temp = NULL, *pipeCommands[MAX_PIPES], *cmdArgs[MAX_ARGUMENTS];
    int newPipe[2], oldPipe[2], pipesCount, aCount, i, status;
    pid_t pid;

    pipesCount = -1; /* This variable will contain how many pipes the command contains */

    /* Counting the number of pipes and splitting them into pipeCommands */
    do 
    {
        temp = strsep(&buffer, "|");

        if(temp != NULL) 
        {
            if(strlen(temp) > 0) 
            {
                pipeCommands[++pipesCount] = temp;
            }
        }
    } while(temp);

    cmdArgs[++pipesCount] = NULL;

    for(i = 0; i < pipesCount; i++) /* For each command */
    {
        aCount = -1;

        /* Parsing command & arguments */
        do 
        {
            temp = strsep(&pipeCommands[i], " ");
            if(temp != NULL) 
            {
                if(strlen(temp) > 0) 
                {
                    /* If a parameter is ~, then replace it by /home/user */
                    if (!strcmp(temp, "~"))
                        strcpy(temp, home);
                    cmdArgs[++aCount] = temp;
                }
            }
        } while(temp);

        cmdArgs[++aCount] = NULL;

        /* If there still are commands to be executed */
        if(i < pipesCount-1) 
        {
            pipe(newPipe); /* just create a pipe */
        }

        pid = fork();

        if(pid == 0)  /* Child */
        {
            /* If there is a previous command */
            if(i > 0)
            {
                close(oldPipe[1]);
                dup2(oldPipe[0], 0);
                close(oldPipe[0]);
            }

            /* If there still are commands to be executed */
            if(i < pipesCount-1) 
            {
                close(newPipe[0]);
                dup2(newPipe[1], 1);
                close(newPipe[1]);
            }

            /* Execute it */
            int res = execvp(cmdArgs[0], cmdArgs);

            if (res == -1)
            {
                printf("Error. Command not found: %s\n", cmdArgs[0]);
            }
            exit(1);
        } 
        else /* Father */
        {
            /* If there is a previous command */
            if(i > 0) 
            {
                close(oldPipe[0]);
                close(oldPipe[1]);
            }

            /* do we have a next command? */
            if(i < pipesCount-1) 
            {
                oldPipe[0] = newPipe[0];
                oldPipe[1] = newPipe[1];
            }

            /* wait for last command process? */
            if(i == pipesCount-1) 
            {
                waitpid(pid, &status, 0);
            }
        }
    }
}