C 实现 shell

简单shell,支持重定向,多重管道。

i know this is very ugly, but just for fun.

#include <sys/stat.h>
#include <fcntl.h>
#include <string.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <unistd.h>
#include <ctype.h>
#include <stdio.h>

#define END_CMD        11
#define END_ARG        11
#define MAX_CMD_NUM    (END_CMD-1)
#define MAX_ARG_NUM    (END_ARG-1)

/* 思路
 * (1)命令解析
 *     扫描输入字符串,直接修改输入字符串为 execvp 的arg格式。
 * (2)重定向
 *     在扫描输入字符串时做好记录,后用dup2 标准输入输出实现
 * (3)管道
 *     扫描时做好记录,使用管道重定向实现。    
 * (4)多重管道
 *     递归
 *
 * 分层实现即可。
 */

/* 细节
 * scanf: 会被空格阻断 fgets不会
 *
 * 管道重定向的实现:使用管道前一定要把没用的管道的关了。
 *
 */

typedef unsigned char bool;
#define true    1
#define false    0


void exec_pipe_cmd(char *(*cmd_vector)[MAX_ARG_NUM], int (*pipefd)[2], bool *is_pipe, int i)
{
    int pid;

    close(pipefd[i][1]);    // notice
    dup2(pipefd[i][0], STDIN_FILENO);
    close(pipefd[i][0]);


    i++;
    if (is_pipe[i] != true) {
        printf("return\n");
        execvp(cmd_vector[i][0], cmd_vector[i]);
    }
    pipe(pipefd[i]);
    pid = fork();
    if (pid < 0) {
        printf("fork2 err\n");
    }
    else if (pid == 0){
        close(pipefd[i][0]);    // notice
        dup2(pipefd[i][1], STDOUT_FILENO);
        close(pipefd[i][1]);
        execvp(cmd_vector[i][0], cmd_vector[i]);
    }
    else {
        exec_pipe_cmd(cmd_vector, pipefd, is_pipe, i);
    }

}

void exec_cmd(char *(*cmd_vector)[MAX_ARG_NUM], int (*pipefd)[2], bool *is_pipe, int i)
{
    int pid;

    if (is_pipe[i] != true) {
        printf("not pipe\n");
        execvp(cmd_vector[i][0], cmd_vector[i]);
    } else {
        if (pipe(pipefd[i]) < 0) {
            perror("pipe \n");
        }
        pid = fork();
        if (pid < 0) {
            printf("fork2 err\n");
        }
        else if (pid == 0){
            close(pipefd[i][0]);    // notice
            dup2(pipefd[i][1], STDOUT_FILENO);
            close(pipefd[i][1]);
            execvp(cmd_vector[i][0], cmd_vector[i]);
        }
        else {
            exec_pipe_cmd(cmd_vector, pipefd, is_pipe, i);
         }
    } 

}

int main()
{
    bool is_re_input = false;
    bool is_re_output = false;
    bool is_pipe[MAX_CMD_NUM];
    char cmd[100] = {0};    
    char *cmd_vector[MAX_CMD_NUM][MAX_ARG_NUM];
    char *ifile = NULL, *ofile = NULL;
    int ifd = -1, ofd= -1;
    int i = 0, cmd_index, arg_index;
    int pipefd[MAX_CMD_NUM][2];

    while(1) {
        printf("hello@:");
        fgets(cmd, sizeof(cmd), stdin);

        cmd_index = arg_index =  i = 0;
        is_re_input = is_re_output = false;
        ifile = ofile = NULL;
        ifd = -1, ofd= -1;
        memset(is_pipe, false, sizeof(is_pipe));
        while (cmd[i]) {
            if (isspace(cmd[i])) {
                i++;
                continue;
            }
            else if (cmd[i] == '-') {
                if (arg_index >= 10 || arg_index == 0) {
                    printf("arg err input\n");
                    goto __again;
                }
                cmd_vector[cmd_index][arg_index] = cmd+i;    
                arg_index++;
                while (cmd[i]) {
                    if (isspace(cmd[i]) || cmd[i] == '\n') {
                        cmd[i] = 0;
                        i++;
                        break;
                    }
                    else i++;
                }
            }
            else if (isalpha(cmd[i])) {
                cmd_vector[cmd_index][arg_index] = cmd+i;    
                arg_index++;
                while (cmd[i]) {
                    if (isspace(cmd[i]) || (cmd[i] == '\n')) {
                        cmd[i] = 0;
                        i++;
                        break;
                    } 
                    else {
                        i++;
                    } 
                }
            }
            else if (cmd[i] == '>') {
                while (cmd[i]) {
                    if (isalpha(cmd[i]) || isdigit(cmd[i]) || (cmd[i] == '_')) {
                        ofile = cmd+i;
                        break;
                    } 
                    else {
                        i++;
                    } 
                }
                if (!ofile) {
                    printf("failed to redirect onput\n");
                    break;
                }
                while (cmd[i]) {
                    if (isspace(cmd[i]) || (cmd[i] == '\n')) {
                        cmd[i] = 0;
                        i++;
                        break;
                    } 
                    else {
                        i++;
                    } 
                }

            }
            else if (cmd[i] == '<') {
                while (cmd[i]) {
                    if (isalpha(cmd[i]) || isdigit(cmd[i]) || (cmd[i] == '_')) {
                        ifile = cmd+i;
                        break;
                    } 
                    else {
                        i++;
                    } 
                }
                if (!ifile) {
                    printf("failed to redirect input\n");
                    break;
                }
                while (cmd[i]) {
                    if (isspace(cmd[i]) || (cmd[i] == '\n')) {
                        cmd[i] = 0;
                        i++;
                        break;
                    } 
                    else {
                        i++;
                    } 
                }


            }
            else if (cmd[i] == '|') {
                if (cmd_index < MAX_CMD_NUM) {
                    is_pipe[cmd_index] = true;    
                    cmd_vector[cmd_index][arg_index] = NULL;
                    cmd_index++;
                    arg_index = 0;
                }
                i++;
            }
        }



__exec:

        cmd_vector[cmd_index][arg_index] = NULL;
        cmd_vector[cmd_index+1][0] = NULL;

        for (i = 0; cmd_vector[i][0]; i++) {

            if (fork() == 0) {

                if (ofile) {
                    ofd = open(ofile, O_WRONLY | O_CREAT, 0644);
                    if (ofd < 0) {
                        perror("open ofile");
                        goto __exec;
                    }
                    if (dup2(ofd, STDOUT_FILENO) < 0) {
                        perror("stdout dup2 err");
                    }
                }
                else if (ifile) {
                    ifd = open(ifile, O_RDONLY);
                    if (ifd < 0) {
                        perror("open ifile");
                        goto __exec;
                    }
                    if (dup2(ifd, STDIN_FILENO) < 0) {
                        perror("stdin dup2 err");
                    }
                }

                exec_cmd(cmd_vector, pipefd, is_pipe, i);
            }
            else {
                wait(NULL);
                while (is_pipe[i]) i++;
            }
        }


__again:
        ;        
    }

}

猜你喜欢

转载自www.cnblogs.com/yangxinrui/p/11182955.html