Tiny-shell (III): to achieve pipeline processing

Tiny-shell (III): to achieve pipeline processing


Outline

This lesson we explore how to implement pipeline processing tsh, such as cmd1 | cmd2 | cmd3the processing of this command. I recommend that you read the realization of the pipeline and processing tsh in redirect .

Analysis and realization

For cmd1 | cmd2 | cmd3such an order, we order |(pipe) as the separator, calling make_argvfunction command entire command is split into an array, i.e. split into cmd1, cmd2and cmd3. As can be seen, for the middle of the cmd2command that accepts cmd1input, and output to pass cmd3, which is the focus of our treatment. So for each |, we create a pipeline and sub-process, and using pipes to communicate between processes, so that between the input and output of the command will be strung up. For each command (except the last one outside), execute_cmdwe have created a pipeline and a child process, the standard output of each command will be redirected to the standard input of the next command. Its parent process standard output redirected to the pipe, and call the execute_redirectfunction executes the command. The child process to redirect standard input from a pipeline, and back to the for loop to create a child process to handle the next command in the pipeline, this is analogous to a process chain. For the last command list, it execute_cmddoes not create a child process or pipeline (because there is no command behind), but direct call execute_cmdfunction.

Father and son on the use of the pipeline to input and output communication, I can refer to this blog , which has detailed graphic explanation.

Compile and run

$ gcc -o pipeline tsh1.c execute_redirect.c parse_redirect.c execute_cmd_pipe.c make_argv.c
$ ./pipeline
tsh1>> ls -l | sort -n | grep execute
-rw-rw-r-- 1 chris chris  1365 3月  10 21:22 execute_cmd_pipe.c
-rw-rw-r-- 1 chris chris  1513 3月  10 21:18 execute_redirect.c
-rw-rw-r-- 1 chris chris   448 2月  27 20:27 execute_cmd_simple.c
-rw-rw-r-- 1 chris chris   587 3月   1 22:11 execute_cmd_redirect.c

Code

execute_cmd_pipe.c

/**
 * @Filename: execute_cmd_pipe.c
 * @Description: 处理流水线的execute_cmd函数,为了直观,省略了错误检查。
 */
 
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>

void execute_redirect(char *s, int in, int out);
int make_argv(const char *, const char *delimiters, char ***argvp);

void execute_cmd(char *cmds) {
    int child;
    int count;
    int fds[2];
    int i;
    char **pipelist;

    count = make_argv(cmds, "|", &pipelist);
    if (count <= 0) {
        fprintf(stderr, "Failed to find any commands\n");
        exit(1);
    }

    /* 处理流水线, 比如"cmd1 | cmd 2 | cmd3" */ 
    for (i = 0; i < count - 1; i++) {
        pipe(fds);
        child = fork();
        if (child) {
            dup2(fds[1], STDOUT_FILENO);
            close(fds[0]);
            close(fds[1]);
            /* 只有第一条命令才可能有输入重定向 */ 
            execute_redirect(pipelist[i], i == 0, 0);
            exit(1);
        }
        dup2(fds[0], STDIN_FILENO);
        close(fds[0]);
        close(fds[1]);
    }

    /**
     * 处理最后一条命令, 只有最后一条命令才可能有输出的重定向
     * 当只有一条命令时且有输入输出重定向时, 上面的for循环不执行, 且in,out都为1
     */ 
    execute_redirect(pipelist[i], i == 0, 1);
    exit(1);
}

execute_redirect.c

/**
 * @Filename: execute_redirect.c
 * @Description: 对可能带有重定向的单个代码进行处理
 */
 
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>

int make_argv(const char *s, const char *delimiters, char ***argvp);
int parse_redirect_in(char *s);
int parse_redirect_out(char *s);


/**
 * in为1, 表示需要处理输入重定向
 * out为1, 表示需要处理输出重定向
 */ 
void execute_redirect(char *s, int in, int out) {
    char **chargv;
    char *pin;
    char *pout;

    /**
     * 实现了对于"sort > f2 < f1"这种小于符号在后的命令处理
     * 之前只能处理小于符号在大于符号之前. 
     */ 
    if (in && ((pin = strchr(s, '<')) != NULL) &&
        out && ((pout = strchr(s, '>')) != NULL) && (pin > pout)) {
        /* 先处理输入重定向, 处理完之后就把in置0 */ 
        if (parse_redirect_in(s) == -1) {
            perror("Failed to redirect input");
            return ;
        }
        in = 0;
    }

    /* 一般情况按先处理输出重定向再处理输入重定向 */ 
    if (out && (parse_redirect_out(s) == -1))
        perror("Failed to redirect output");
    else if (in && (parse_redirect_in(s) == -1))
        perror("Failed to redirect input");
    else if (make_argv(s, " \t", &chargv) <= 0)
        fprintf(stderr, "Failed to parse command line\n");
    else {
        execvp(chargv[0], chargv);
        perror("Failed to execute command");
    }
    exit(1);
}

Guess you like

Origin www.cnblogs.com/chrisynl/p/12460569.html