【问题标题】:How to implement piping in your own Linux shell?如何在自己的 Linux shell 中实现管道?
【发布时间】:2015-11-02 18:44:14
【问题描述】:

我正在用 C 语言为 Linux 编写自己的简单 shell。如果不退出整个 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()

pipelineProcesses() 函数:

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 在我通过管道传输两个命令后继续运行。我该如何解决这个问题?

【问题讨论】:

  • pipeProcesses 中,在调用runProcess 之后,你有一个exit(0);,为什么?很难阅读您的代码,将命令解析等分解为(有意义的、小的)函数可能会提高代码质量。
  • 我没有阅读您的所有代码(您可以使用strtok(input, "|") 来拆分命令吗?)。也许您可以在调用 pipelineProcesses() 之前再添加一个 fork() ?父级应该等待管道命令并继续您的主循环。

标签: c shell pipe fork execvp


【解决方案1】:

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

您也应该为该命令使用 fork()。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-04-01
    相关资源
    最近更新 更多