MyShell

MyShell

#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <sys/wait.h>
#include<readline/readline.h>
#include <pwd.h>

#define NAME_SIZE 32
#define DIR_SIZE 64
#define COMMAND_NUM 16
#define COMMAND_LEN 64

//打印命令行提示符
void print_prompt();

//接收并解析输入命令
int analyzer(char **parameter);

//帮助命令
void help();

//执行普通命令
void common_command(char **parameter);

//返回管道符的位置,-1即不存在
int isPIPE(int num, char **parameter);

//执行管道命令
void pipe_command(int num, int location, char **parameter1);

//对标准输入符位置和标准输出符位置赋值,-1即不存在
void isRedirect(int num, char **parameter, int *stdin_location, int *stdout_location);

//执行重定向命令
void redirect_command(int stdin_location, int stdout_location, char **parameter);

//释放内存
void m_free(int offset, int num, char **parameter);

int main(int argc, char *argv[]) {

    int parameter_num;
    int pipe_location;
    int stdin_location;
    int stdout_location;
    char **parameter = malloc(COMMAND_NUM * sizeof(char *));

    while (1) {

        print_prompt();

        parameter_num = analyzer(parameter);

        pipe_location = isPIPE(parameter_num, parameter);

        isRedirect(parameter_num, parameter, &stdin_location, &stdout_location);

        //判断命令是否为exit,若是则退出程序
        if (strcmp(*parameter, "exit") == 0) {
            m_free(0, parameter_num, parameter);
            break;
        }

        //判断命令种类,按种类执行
        if (strcmp(*parameter, "cd") == 0) {
            chdir(*(parameter + 1));
        } else if (strcmp(*parameter, "help") == 0) {
            help();
        } else if (pipe_location != -1) {
            pipe_command(parameter_num, pipe_location, parameter);
        } else if (stdin_location != -1 || stdout_location != -1) {
            redirect_command(stdin_location, stdout_location, parameter);
        } else {
            common_command(parameter);
        }
        
        //释放存有命令参数的内存
        m_free(0, parameter_num, parameter);
    }

    free(parameter);
    parameter = NULL;
    return 0;
}

void print_prompt() {

    char *hostName = malloc(NAME_SIZE);
    char *dirName = malloc(DIR_SIZE);
    char *userName;
    struct passwd *user_msg;

    //获取主机名,当前目录名,用户名
    gethostname(hostName, NAME_SIZE);
    getcwd(dirName, DIR_SIZE);
    user_msg = getpwuid(getuid());
    userName = user_msg->pw_name;

    //判断是否为根用户
    if (strcmp(userName, "root") == 0) {
        printf("%s@%s:%s~#", userName, hostName, dirName);
    } else {
        printf("%s@%s:%s~$", userName, hostName, dirName);
    }
}

int analyzer(char **parameter) {

    char *message;
    char *delim = " ";
    char *p;
    int num = 1;
    message = readline(" ");
    *parameter = malloc(COMMAND_LEN);
    strcpy(*parameter, strtok(message, delim));

    //将输入信息用" "分割解析
    while (p = strtok(NULL, delim)) {
        *(parameter + num) = malloc(COMMAND_LEN);
        strcpy(*(parameter + num), p);
        num++;
    }

    return num;
}


int isPIPE(int num, char **parameter) {
    int location;
    //遍历返回管道符位置
    for (int i = 1; i < num - 1; ++i) {
        if (strcmp(*(parameter + i), "|=|") == 0) {
            location = i;
            return location;
        }
    }

    return -1;
}


void m_free(int offset, int num, char **parameter) {
    for (int i = offset; i < num; i++) {
        free(*(parameter + i));
        *(parameter + i) = NULL;
    }
}

void common_command(char **parameter) {
    int pid;
    pid = fork();

    if (pid == -1) {
        perror("getpid failed");
    }
    if (pid == 0) {
        if (execvp(*parameter, parameter) == -1) {
            perror("execl failed");
            exit(1);
        }
    }

    waitpid(pid, NULL, 0);
}


void pipe_command(int num, int location, char **parameter1) {
    int fds[2];
    int pid1;
    int pid0;

    pipe(fds);//调用pipe系统调用

    char **parameter0 = malloc(COMMAND_NUM * sizeof(char *));

    //获取读端命令参数
    for (int i = location + 1; i < num; i++) {
        *(parameter0 + i - location - 1) = malloc(COMMAND_LEN);
        strcpy(*(parameter0 + i - location - 1), *(parameter1 + i));
    }
    *(parameter0 + num - location - 1) = NULL;
    
    //释放多余命令参数,获取写端命令参数
    for (int i = location; i < num; i++) {
        *(parameter1 + i) = NULL;
    }

    pid1 = fork();

    if (pid1 == -1) {
        perror("getpid failed");
    }

    if (pid1 == 0) {

        //将写端文件描述符拷贝到标准输出文件
        dup2(fds[1], 1);

        //关闭读端
        close(fds[0]);

        //执行写端命令
        if (execvp(*parameter1, parameter1) == -1) {
            perror("execl failed");
            exit(1);
        }
    }
    waitpid(pid1, NULL, 0);

    pid0 = fork();

    if (pid0 == -1) {
        perror("getpid failed");
    }

    if (pid0 == 0) {

        //将读端文件描述符拷贝到标准输入文件
        dup2(fds[0], 0);

        //关闭写端
        close(fds[1]);

        //执行读端命令
        if (execvp(*parameter0, parameter0) == -1) {
            perror("execl failed");
            exit(1);
        }
    }

    close(fds[0]);
    close(fds[1]);
    waitpid(pid0, NULL, 0);

    m_free(0, num - location - 2, parameter0);

    free(parameter0);
    parameter0 = NULL;

}

void isRedirect(int num, char **parameter, int *stdin_location, int *stdout_location) {

    *stdin_location = -1;
    *stdout_location = -1;

    for (int i = 1; i < num - 1; ++i) {
        if (strcmp(*(parameter + i), "<") == 0) {
            *stdin_location = i;
        }
        if (strcmp(*(parameter + i), ">") == 0) {
            *stdout_location = i;
        }
    }

}

void redirect_command(int stdin_location, int stdout_location, char **parameter) {
    int pid0, pid1;
    char *in_file, *out_file;
    FILE *file_instream, *file_outstream;

    //获取白哦准输入指向的文件名
    if (stdin_location != -1) {
        in_file = malloc(COMMAND_LEN);
        strcpy(in_file, *(parameter + stdin_location + 1));
    }

    //获取标准输出指向的文件名
    if (stdout_location != -1) {
        out_file = malloc(COMMAND_LEN);
        strcpy(out_file, *(parameter + stdout_location + 1));
    }

    if (stdin_location != -1) {
        m_free(stdin_location, stdin_location + 2, parameter);
    }

    if (stdout_location != -1) {
        m_free(stdout_location, stdout_location + 2, parameter);
    }

    pid0 = fork();

    if (pid0 == -1) {
        perror("getpid failed");
    }

    if (pid0 == 0) {

        //重定向输入
        if (stdin_location != -1) {
            file_instream = fopen(in_file, "r");
            freopen(in_file, "r", stdin);
        }

        //重定向输出
        if (stdout_location != -1) {
            file_outstream = fopen(out_file, "w+");
            freopen(out_file, "w", stdout);
        }

        pid1 = fork();

        if (pid1 == -1) {
            perror("getpid failed");
        }

        if (pid1 == 0) {
            if (execvp(*parameter, parameter) == -1) {
                perror("execl failed");
                exit(1);
            }
        }

        waitpid(pid1, NULL, 0);
        fclose(stdin);
        fclose(stdout);
        fclose(file_instream);
        fclose(file_outstream);
        exit(1);

    }

    waitpid(pid0, NULL, 0);
    free(in_file);
    in_file = NULL;
    free(out_file);
    out_file = NULL;
}

void help() {
    printf("%s\n", "This is myShell!");
}
  • 3
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值