如外壳的“ prog1 | prog2 | prog3”

时间:2019-05-26 09:48:28

标签: c shell unix posix ipc

我正在尝试编写一个简单的shell(只是试图了解shell是如何工作的)。第一部分(解析命令行参数)可以正常工作,但是第二部分(执行命令)无法正常工作。

我正在尝试为每两个连续的程序创建一对管道。当前命令写入pdes [0],下一个从pdes [1]读取它。由于我要在一个循环中创建多个进程,因此使用一个名为prev_out的变量来记住列表中上一个命令的读取端。列表中的第一个命令从stdin而不是管道读取其输入。同样,最后一个程序还将其输出写入标准输出,而不是管道。

         pipe1      pipe2
          *  *      *  *
         *    *    *    *
 --> CMD1      CMD2      CMD3 --> stdout

类似上面的安排。每个命令均写入pdes [0],并读取对应的pdes [1]。

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <signal.h>
#include <assert.h>

#include <unistd.h>
#include <sys/wait.h>

#define MAXLINE     255
#define MAXARG      32
#define MAXNCMD     16

    extern char   **environ;

    int
    main(int argc, char *argv[])
    {
        char           *cmds[MAXNCMD][MAXARG];
        char        line     [MAXLINE + 1];
        pid_t       childs  [MAXNCMD];
        char           *cmdcur, *argcur;
        char           *linecp;
        int         c        , st;
        int         i        , j, k;
        int         prev_in  , prev_out;

        for (;;) {
            printf("%% ");

            i = 0;

            while ('\n' != (c = getc(stdin)) && i < MAXLINE) {
                if (c == EOF)
                    exit(EXIT_SUCCESS);
                /* NOTREACHED */
                line[i++] = c;
            }
            line[i] = 0;    /* null-terminate */

            if (0 == strncmp(line, "exit", 4)) {
                exit(EXIT_SUCCESS);
                /* NOTREACHED */
            }
            if (0 == strncmp(line, "cd ", 3)) {
                if (-1 == chdir(line + 3)) {
                    perror("chdir()");
                }
                continue;
            }
            linecp = line;
            j = 0;
            k = 0;

            while (NULL != (cmdcur = strsep(&linecp, "|"))) {

                while (*cmdcur == ' ')
                    cmdcur++;

                k = 0;
                while (NULL != (argcur = strsep(&cmdcur, " "))) {

                    while (*argcur == ' ')
                        argcur++;

                    if (NULL == (cmds[j][k] = malloc(strlen(argcur) + 1))) {
                        perror("malloc()");
                        exit(EXIT_FAILURE);
                    }
                    strncpy(cmds[j][k], argcur, strlen(argcur));
                    k++;

                    if (k == MAXARG) {
                        fprintf(stderr, "%s: Too many args\n", argv[0]);
                        exit(EXIT_FAILURE);
                    }   /* NOTREACHED */
                }
                cmds[j][k] = NULL;
                j++;

                if (j == MAXNCMD) {
                    fprintf(stderr, "%s: Too many args\n", argv[0]);
                    exit(EXIT_FAILURE);
                    /* NOTREACHED */
                }
            }

            *cmds[j] = NULL;

            int         nc = j;

            for (int m = 0; m < nc; m++) {

                int         pdes      [2];
                if (-1 == pipe(pdes)) {
                    perror("pipe()");
                    exit(EXIT_FAILURE);
                }
                if (-1 == (childs[m] = fork())) {
                    perror("fork()");
                    exit(EXIT_FAILURE);
                }
                prev_out = pdes[1];
                if (0 == childs[m]) {
                    /* child */
                    if (0 == m) {
                        close(STDOUT_FILENO); /* the first process in the pipe group needs
                        dup(pdes[0]);          * only to set its stdout, the next process
                        prev_out = pdes[1];    * will use the other end */
                    } else if (m == (nc - 1)) {
                        close(STDIN_FILENO);  /* the last process only needs to set its stdin
                        dup(prev_out);         * it will use termical as stdout by default */
                    } else {
                        close(STDIN_FILENO);  /* inner processes should set both stdin and stdout */
                        dup(prev_out);
                        close(STDOUT_FILENO);
                        dup(pdes[0]);
                        prev_out = pdes[1];
                    }

                    if (-1 == execvp(cmds[i][0], cmds[i])) {
                        perror("execvp()");
                        exit(EXIT_FAILURE);
                    }
                } else if (childs[m] > 0) {
                    if (childs[m] != wait(NULL)) {
                        perror("wait()");
                        exit(EXIT_FAILURE);
                    }
                }
            }
        }

        return 0;
    }

0 个答案:

没有答案