Multi Piping Bash-стиль в C - PullRequest
       13

Multi Piping Bash-стиль в C

1 голос
/ 06 марта 2011

Я знаю, что есть много потоков, которые говорят об этой проблеме , но я не совсем понимаю, как это можно сделать.

Я пытаюсь создать оболочку, которая можетвыполнить команду linux, например, 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;

Мои вопросы:

  • Какая будет правильная реализация?
  • Можно ли сделать это с помощью рекурсии?
  • Нужно ли разветвляться справа налево или слева направо (логически это дает тот же результат)?

Ответы [ 2 ]

5 голосов
/ 06 марта 2011

Вот часть оболочки UNIX, которую я должен был реализовать в C для Операционная система Предмет в моей Информатике карьере.

/* 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);
            }
        }
    }
}

Это может бытьнемного глючит (я не проверяю fork() < 0 и т. д.), но основная идея верна.

> Возможно ли сделать это с помощью рекурсии?

В большинстве случаев я стараюсь избегать рекурсии, , если , я могу написать похожий понятный код, не используя его.

0 голосов
/ 06 марта 2011

Процессы выполняются независимо, поэтому вам нужно настроить канал как минимум для первой пары команд перед тем, как вы разветвляетесь, но вы делаете это в потомке (сын == 0).Вы могли бы написать рекурсивное решение, которое, если осталось не менее двух команд, создает канал, затем разветвляется и выполняет первую команду.

...