如何在自己的Linux shell中实现管道?

时间:2015-08-10 18:25:45

标签: c shell pipe fork execvp

我正在用C编写自己的简单shell for Linux。我无法在不退出整个shell的情况下实现管道。我相信我需要再实现一个fork()来实现这个目标,但我不知道该怎么做。

我的程序有一个main():

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>

int main(void){

    char input[256];
    char* temp = NULL;
    char* args[9];
    char* cmd1[5];
    char* cmd2[5];
    int i, j, pipe_pos;
    int fd[2];

    while(1){

        // set all args to NULL
        for (i = 0; i < 9; i++) {
            args[i] = NULL;
        }

        for (i = 0; i < 5; i++) {
            cmd1[i] = NULL;
            cmd2[i] = NULL;
        }


        // print message to terminal
        printf("My Shell (v2.0):>  ");

        // get input from user
        fgets(input,255,stdin);

        // test if input = 'quit'
        if (!strncmp(input,"quit",4)) {

            // exit program if input = quit
            exit(0);

        }
        else { // continue running program

            // initialise counter
            i = 0;

            // tokenize first word
            temp = strtok(input, " \n");

            // receive arguments from user input
            while ((temp != NULL) && (i < 9)) {

                args[i] = temp;
                temp = strtok(NULL, " \n");
                i++;

            }

            // find position of "|" (pipe)
            j = i - 1;
            pipe_pos = 8;

            for (i = 0; i < j; i++) {
                if (strcmp(args[i],"|") == 0) {
                    pipe_pos = i;
                    break;
                }
            }

            // copy 1st command with arguments to new array
            for (i = 0; i < pipe_pos; i++) {
                cmd1[i] = args[i];
            }

            // copy 2nd command with arguments to new array
            j = 0;
            if (pipe_pos != 8) {
                for (i = pipe_pos+1; i < 9; i++) {
                    // copy if array is not full
                    if (j < 5){

                        cmd2[j] = args[i];
                        j++;

                    } // end if (j < 5)
                } // end for
            } // end if (pipe_pos != 8) {

            // run if program needs piping
            if (pipe_pos != 8) {

                pipeProcesses(cmd1, cmd2);

            }
            else {

                runProcess(cmd1);

            }


        } // end else

    }// end while

    return 0;
}// end main()

pipingProcesses()函数:

void pipeProcesses(char ** cmd1, char ** cmd2){

    int fd[2];

    pipe(fd);

    if (!fork()) {

        // close STD_OUT
        close(1);
        // make STD_OUT same as fd[1]
        dup(fd[1]);
        // we don't need this
        close(fd[0]);
        runProcess(cmd1);
        exit(0);

    } else {

        // close STD_IN
        close(0);
        // make STD_IN same as fd[0]
        dup(fd[0]);
        // we don't need this
        close(fd[1]);
        execvp(cmd2[0], cmd2);

    }

}

和runProcess()函数:

void runProcess(char ** cmd){

    int error;

    // initialise error flag
    error = 0;

    if (fork() == 0) {
        // child process
        error = execvp(cmd[0], cmd);

        // print error: unknown command
        if (error == -1) {
            printf("ERROR: UNKNOWN COMMAND (%s)\n", cmd[0]);
            exit(0);
        }

    }
    else {

        // parent process
        waitpid(0,NULL,0);

    }

}

一切都按原样运行,除了我希望shell在管道输出两个命令后继续运行。我该如何解决这个问题?

1 个答案:

答案 0 :(得分:1)

您在主程序流程中调用execvp(cmd2[0], cmd2);,用cmd2替换您的程序。

你也应该为该命令fork()。