간이 셸

40772 단어 linux
  • 출처: 과정 확장 서적 인 의 예 1.5, 1.8
  • 기능 수요
  • 프로그램 이 콘 솔 에서 실 행 됩 니 다. 시작 하면 명령 프롬프트 '->' 를 표시 합 니 다.사용 자 는 특정한 환경 변수 에 값 을 부여 함으로써 명령 프롬프트 형식 을 바 꿀 수 있다.
  • 특정한 명령 이나 버튼 조합 을 통 해 이 프로그램 을 정상적으로 닫 을 수 있 습 니 다.
  • 백 스테이지 운영 체 제 를 제공 합 니 다.사용자 가 제출 한 작업 은 특정한 지 시 를 통 해 배경 에서 실행 할 수 있 습 니 다. 예 를 들 어 -> bg job 1 은 작업 job 1 을 배경 에서 실행 시 키 고 바로 사용자 에 게 새로운 알림 부 호 를 되 돌려 줍 니 다.
  • 출력 재 설정 을 제공 합 니 다.지정 한 파일 이름 을 통 해 작업 의 모든 출력 을 표준 출력 으로 보 내 는 것 이 아니 라 파일 에 덮어 씁 니 다.
  • 입력 재 설정 을 제공 합 니 다.지정 한 파일 이름 을 통 해 작업 이 표준 입력 이 아 닌 해당 파일 에서 필요 한 데 이 터 를 가 져 옵 니 다.

  • 요구 사항
  • C 언어 로 작업 을 완료 하 십시오. 다른 언어 는 사용 할 수 없습니다.
  • 이 절 차 는 독립 적 으로 완성 해 야 하 며 팀 이 함께 완성 하 는 것 을 허락 하지 않 는 다.
  • 문 서 는 일반 텍스트 형식 이나 TEX 로 작성 되 었 으 며 다른 형식 은 잘못 되 었 습 니 다.


  • 첫 번 째 완성 은 프로그램 입 니 다. 어 리 석고 길 며 bug 도 있 습 니 다. 붙 여서 열심히 공부 해 야 한 다 는 것 을 명심 하 세 요.
    /** * zsh.c : 简单的shell程序 * * created: zh * date: 2014.5.28~2014.6.8 * version1.0: first version * * *********************************************/
    
    #include <stdlib.h>
    #include <sys/wait.h>
    #include <sys/stat.h>
    #include <errno.h>
    #include <fcntl.h>
    #include <stdio.h>
    #include <string.h>
    #include <signal.h>
    #include <unistd.h>
    #include <pwd.h>
    #include <libgen.h>
    #include <sys/types.h>
    
    #include <readline/readline.h>
    #include <readline/history.h>
    
    
    int do_exit(int, char **);
    int do_export(int, char **);
    int do_echo(int, char **);
    int do_cd(int, char **);
    int do_history(int, char **);
    
    void do_line(char *line);
    void do_pipe_cmd(char *line);
    int do_simple_cmd(int argc, char **argv, int prefd[], int postfd[]);
    int isBgProgram(int len, char *line[10]);
    char **arrayToPointer(int num, char *argv[10]);
    int predo_for_redirect(int argc, char **argv, int *re);
    
    char lastdir[100];
    char **arg;
    
    typedef int (*buildin_cmd_handle) (int, char **);
    typedef struct {
        const char *cmd;
        buildin_cmd_handle handle;
    } CMD_ENTRY;
    
    const CMD_ENTRY buildin_cmd_table[] = {
        {"exit", do_exit},
        {"cd", do_cd},
        {"echo", do_echo},
        {"export", do_export},
        {"history", do_history},
        {0, 0}
    };
    
    
    void history_finish()
    {
        append_history(history_length, "/tmp/msh_history");
        history_truncate_file("/tmp/msh_history", history_max_entries);
    }
    
    /** * 用于获取函数句柄 */
    buildin_cmd_handle get_cmd_handle(const char *cmd)
    {
        int i = 0;
        while (buildin_cmd_table[i].cmd) {
        if (strcmp(buildin_cmd_table[i].cmd, cmd) == 0)
            return buildin_cmd_table[i].handle;
        i++;
        }
        return 0;
    }
    
    /** * 用于显示历史输入信息 */
    void display_history_list()
    {
        HIST_ENTRY **h = history_list();
        if (h) {
        int i = 0;
        while (h[i]) {
            printf("%d: %s
    "
    , i, h[i]->line); i++; } } } /*** * 功能:执行exit命令,退出shell解释器 * 输入:argc:命令行字符串数目;argv:命令行字符串组 */ int do_exit(int argc, char **argv) { int val = 0; if (argc > 1) val = atoi(argv[1]); //free_resource(); history_finish(); exit(val); return 0; } /*** * 功能:执行cd命令,切换shell当前路径 * 输入:argc:命令行字符串数目;argv:命令行字符串组 */ int do_cd(int argc, char **argv) { char *dir; char cwd[100]; if (argc == 1) { if (!(dir = getenv("HOME"))) { printf("cd: %s
    "
    , strerror(errno)); return -1; } } else if (argc == 2) { if (strcmp(argv[1], "-") == 0) { dir = lastdir; } else if (strcmp(argv[1], "~") == 0) { if (!(dir = getenv("HOME"))) { printf("cd: %s
    "
    , strerror(errno)); return -1; } } else dir = argv[1]; } else { printf("Usage: cd [dir]
    "
    ); return -1; } getcwd(cwd, 99); if (chdir(dir) == -1) { printf("cd: %s
    "
    , strerror(errno)); return -1; } strcpy(lastdir, cwd); return 0; } /*** * 功能:执行export命令,导入或显示环境变量 * 输入:argc:命令行字符串数目;argv:命令行字符串组 */ int do_export(int argc, char **argv) { int i = 1; char *p; while (argv[i]) { if ((p = strchr(argv[i], '='))) { *p = 0; if (strpbrk(argv[i], "~`!@#$%^&*()-_+=|\\{}[];:'\"<>,.?/")) { *p = '='; printf("export: %s: not a valid indentifier
    "
    , argv[i]); i++; continue; } if (setenv(argv[i], p + 1, 1) == -1) printf("export: %s
    "
    , strerror(errno)); *p = '='; } i++; } return 0; } /*** * 功能:执行echo命令,回显变量 * 输入:argc:命令行字符串数目;argv:命令行字符串组 */ int do_echo(int argc, char **argv) { int i = 1; int j; int argn = 0; int arge = 0; if (argv[1]) { if (strcmp(argv[1], "-n") == 0) { argn = 1; i = 2; } else if (strcmp(argv[1], "-e") == 0) { arge = 1; i = 2; } else if ((strcmp(argv[1], "-ne") == 0) || (strcmp(argv[1], "-en") == 0)) { argn = arge = 1; i = 2; } } j = i; while (argv[i]) { if (i > j) printf(" %s", argv[i]); else printf("%s", argv[i]); i++; } if (argn == 0) printf("
    "
    ); return 0; } /*** * 功能:执行history命令,显示历史信息 * 输入:argc:命令行字符串数目;argv:命令行字符串组 */ int do_history(int argc, char **argv) { display_history_list(); return 0; } /** * 设置shell命令提示符,可通过设置环境变量envprompt改变 */ void setShellPrompt(char *prompt) { char host[100]; char cwd[100]; struct passwd *pwp; if (gethostname(host, 99) == -1) { strcpy(host, "unknown"); } else { char *p = strchr(host, '.'); if (p) *p = 0; } if (!getcwd(cwd, 99)) { strcpy(cwd, "unknown"); } else { if (strcmp(cwd, "/") != 0) strcpy(cwd, basename(cwd)); } pwp = getpwuid(getuid()); sprintf(prompt, "[%s@%s %s]# ", (pwp ? pwp->pw_name : "unknown"), host, cwd); } /** * 释放程序中申请的内存 */ void free_source(int num, char **name) { int n; for (n = 0; n < num; n++) { free(name[n]); name[n] = 0; } } int main(int argc, char **argv) { char prompt[200]; setShellPrompt(prompt); //signal(SIGINT,SIG_IGN); char *line; //char line[300];// line = malloc(200); memset(line, 0, 200); char *env; env = malloc(strlen(prompt) + 11); strcpy(env, "envprompt="); strcat(env, prompt); putenv(env); char *tmpline; tmpline = malloc(strlen(prompt)); while (1) { tmpline = getenv("envprompt"); if (!(line = readline(tmpline))) { break; } if (*line) { add_history(line); } //printf("%s + %d
    ",line, strlen(line));
    do_line(line); putenv(line); } free(env); env = NULL; free(tmpline); tmpline = NULL; free(line); line = NULL; return 0; } /** * 功能:解析输入命令,并按";"解析命令,并传入到函数do_pipe_cmd() * 输入:原始命令行 */ void do_line(char *line) { int len, i, j = 0, k = 0; char *argv[20]; int m = 0; len = strlen(line); //printf("---%s---||---%d---
    ",line,len);
    for (i = 0; i <= len; i++) { if (line[i] == ';') { if ((argv[k] = (char *) malloc((i - j) * sizeof(char))) == 0) { fprintf(stderr, "error! can't malloc space for argv
    "
    ); } else { memset(argv[k], 0, (i - j) * sizeof(char)); for (m = 0; m < i - j; m++) { argv[k][m] = line[j + m]; } argv[k][m] = '\0'; //printf("---%s---
    ",argv[k]);
    do_pipe_cmd(argv[k]); j = i + 1; k++; } } else if (line[i] == '
    '
    || (i == len && i != 0)) { if ((argv[k] = (char *) malloc((i - j) * sizeof(char))) == 0) { fprintf(stderr, "error! can't malloc space for argv
    "
    ); } else { memset(argv[k], 0, (i - j) * sizeof(char)); //printf("(i - j) * sizeof(char) is %d
    ",(i - j) * sizeof(char));
    //printf("---%s---%d---%d---
    ",argv[k],m,strlen(argv[k]));
    for (m = 0; m < i - j; m++) { argv[k][m] = line[j + m]; } argv[k][m] = '\0'; //printf("---%s---%d---%d---
    ",argv[k],m,strlen(argv[k]));
    do_pipe_cmd(argv[k]); j = i; k++; } } } free_source(k - 1, argv); } /** * 功能:解析输入命令,并按"|"解析简单命令,并传入到函数do_simple_cmd() * 输入:函数do_line()解析后的简单命令 */ void do_pipe_cmd(char *line) { //printf("the line in pipe_cmd is %s
    ",line);
    int len, i, j = 0, k = 0; char *argv[20]; int m; len = strlen(line); int prepipe = 0; int prefd[2]; int postfd[2]; char *args[10]; int num = 0; for (i = 0; i <= len; i++) { if (line[i] == '|') { if ((argv[k] = (char *) malloc((i - j) * sizeof(char))) == 0) { fprintf(stderr, "error! can't malloc space for argv
    "
    ); } else { memset(argv[k], 0, (i - j) * sizeof(char)); for (m = 0; m < i - j; m++) { argv[k][m] = line[j + m]; } argv[k][m] = '\0'; num = add_arg(argv[k], args); j = i + 1; k++; pipe(postfd); if (prepipe) do_simple_cmd(num, arrayToPointer(num, args), prefd, postfd); else do_simple_cmd(num, arrayToPointer(num, args), 0, postfd); prepipe = 1; prefd[0] = postfd[0]; prefd[1] = postfd[1]; } } else if (i == len && i != 0) { if ((argv[k] = (char *) malloc((i - j) * sizeof(char))) == 0) { fprintf(stderr, "error! can't malloc space for argv
    "
    ); } else { memset(argv[k], 0, (i - j) * sizeof(char)); for (m = 0; m < i - j; m++) { argv[k][m] = line[j + m]; } argv[k][m] = '\0'; num = add_arg(argv[k], args); j = i; k++; pipe(postfd); if (prepipe) { do_simple_cmd(num, arrayToPointer(num, args), prefd, postfd); } else { do_simple_cmd(num, arrayToPointer(num, args), 0, 0); } } } } free_source(k - 1, argv); free_source(k - 1, args); free_source(num, arg); } /** * 功能:执行简单命令 * 输入:argc:命令行字符串数目;argv:命令行字符串组 * prefd,postfd:管道参数 */ int do_simple_cmd(int argc, char **argv, int prefd[], int postfd[]) { int pid; int status; buildin_cmd_handle hd; if (argc == 0) return 0; if (prefd == 0 && postfd == 0) { if ((hd = get_cmd_handle(argv[0]))) { if (predo_for_redirect(argc, argv, 0)) return 1; (*hd) (argc, argv); return 0; } } if ((pid = fork()) == 0) { //子进程 // 重置signal INT handle为默认 int redirect = 0; signal(SIGINT, SIG_DFL); if (predo_for_redirect(argc, argv, &redirect)) exit(1); if (redirect != 1 && prefd) { close(prefd[1]); if (prefd[0] != STDIN_FILENO) { dup2(prefd[0], STDIN_FILENO); close(prefd[0]); } } if (redirect != 2 && postfd) { close(postfd[0]); if (postfd[1] != STDOUT_FILENO) { dup2(postfd[1], STDOUT_FILENO); close(postfd[1]); } } if ((hd = get_cmd_handle(argv[0]))) { (*hd) (argc, argv); exit(0); } char buffer[100]; if (file_exist(argv[0], buffer)) { execv(buffer, argv); } else { fprintf(stderr, "-zsh: %s: command not found
    "
    , argv[0]); exit(0); } } else if (pid < 0) { } else { if (isBgProgram(argc, argv) == 0) { //printf("this is not bg
    ");
    waitpid(pid, &status, 0); } } if (postfd) { close(postfd[1]); // 关闭这个fd. } return 0; } /** * 将指针数组转换为二维指针,恕我学识浅薄,尚不明白为何一定要这样, * 只是这样才能通过编译....容我再学习 */ char **arrayToPointer(int num, char *argv[10]) { arg = (char **) malloc((num) * sizeof(char *)); memset(arg,0, (num)*sizeof(char *)); int p = 0; for (p = 0; p < num && num < 10; p++) { arg[p] = argv[p]; } return arg; } /** * 功能:判断简单命令是否需要后台运行,通过“&”判别 */ int isBgProgram(int len, char **line) { if (strcmp(line[len - 1], "&") == 0) { line[len - 1] = "\0"; return 1; } return 0; } /** * 功能:将简单命令(字符串)转换为字符串数组,数组每个元素即为一个标记 */ int add_arg(char *line, char *args[10]) { int len, i, j = 0, k = 0; //char *args[10]; len = strlen(line); int m = 0; char *newline; if ((newline = (char *) malloc(len * sizeof(char))) == 0) { fprintf(stderr, "error! can't malloc space for argv
    "
    ); } for (i = 0; i <= len;) { if (line[i] == ' ' && line[i + 1] == ' ' || line[i] == '\t') i++; else { newline[j] = line[i]; j++; i++; } } i = 0; while (newline[i] == ' ' || newline[i] == '\t') i++; j = i; //重新置为零 for (; i <= len; i++) { if (newline[i] == ' ') { if ((args[k] = (char *) malloc((i - j) * sizeof(char))) == 0) { fprintf(stderr, "error! can't malloc space for argv
    "
    ); } else { memset(args[k], 0, (i - j) * sizeof(char)); for (m = 0; m < i - j; m++) { args[k][m] = newline[j + m]; } args[k][m] = '\0'; j = i + 1; k++; } } else if (i == len) { if ((args[k] = (char *) malloc((i - j) * sizeof(char))) == 0) { fprintf(stderr, "error! can't malloc space for argv
    "
    ); } else { for (m = 0; m < i - j; m++) { args[k][m] = newline[j + m]; } args[k][m] = '\0'; j = i; k++; } } } return k; } /** * 功能:判断文件是否存在 */ int file_exist(const char *file, char *buffer) { int i = 0; const char *p; const char *path = getenv("PATH"); p = path; while (*p != 0) { if (*p != ':') buffer[i++] = *p; else { buffer[i++] = '/'; buffer[i] = 0; strcat(buffer, file); if (access(buffer, F_OK) == 0) return 1; i = 0; } p++; } const char *p2 = getenv("PWD"); p = p2; i = 0; while (*p != 0) { buffer[i++] = *p; p++; } buffer[i++] = '/'; buffer[i] = 0; strcat(buffer, file); if (access(buffer, F_OK) == 0) return 1; return 0; } /** * 功能:完成重定向功能 */ int predo_for_redirect(int argc, char **argv, int *re) { int i; int redirect = 0; for (i = 1; i < argc; i++) { if (strcmp(argv[i], "<") == 0) { redirect = 1; argv[i] = 0; break; } else if (strcmp(argv[i], ">") == 0) { redirect = 2; argv[i] = 0; break; } } if (redirect) { if (argv[i + 1]) { int fd; if (redirect == 2) { if ((fd = open(argv[i + 1], O_WRONLY | O_CREAT | O_TRUNC, S_IRUSR | S_IWUSR)) == -1) { fprintf(stderr, "Open out %s failed
    "
    , argv[i + 1]); return 1; } dup2(fd, STDOUT_FILENO); } else { //redirect == 1 if ((fd = open(argv[i + 1], O_RDONLY, S_IRUSR | S_IWUSR)) == -1) { fprintf(stderr, "Open in %s failed
    "
    , argv[i + 1]); return 1; } dup2(fd, STDIN_FILENO); } } else { fprintf(stderr, "Bad redirect, need more arg
    "
    ); return 1; } } if (re) *re = redirect; return 0; }

    좋은 웹페이지 즐겨찾기