十七、文件和目录——minishell(1)
主函数运行要去读取从标准输入或终端上输入的整个命令行,然后再去解析命令行参数,解析出来之后,要将其封装成一个 program,然后再将 program 放入 job 中,然后再去执行 job 中的命令行的内容。
17.1 job.o
job.h 文件
1 #ifndef __JOB_H__ 2 #define __JOB_H__ 3 4 typedef struct 5 { 6 char **args; //shell 当中输入的命令参数;对应主函数中的 char *argv[] 参数 7 }Program; 8 9 //作业结构体,表示若干个要执行的参数 10 typedef struct 11 { 12 char *cmd; 13 int progs_num; 14 Program *progs;//Program 的结构体指针 15 }Job; 16 17 extern Job * create_job(char *cmd); 18 extern void destroy_job(Job *job); 19 extern Program* create_program(char **arg);//创建一个程序 20 extern void destroy_program(Program *prog); 21 extern int add_program(Job *job, Program *prog);//将程序加入到 job 中 22 23 #endif
job.c 文件
1 #include "job.h" 2 #include <malloc.h> 3 #include <assert.h> 4 #include <stdlib.h> 5 #include <string.h> 6 #include <stdio.h> 7 #include <memory.h> 8 9 10 /* 根据 commond 命令创建 job */ 11 Job * create_job(char *cmd) 12 { 13 Job *job = (Job *)malloc(sizeof(Job)); 14 assert(job != NULL); 15 16 job->cmd = (char *)malloc(sizeof(char) * strlen(cmd)); 17 assert(job->cmd != NULL); 18 19 strcpy(job->cmd, cmd); 20 job->progs_num = 0; 21 job->progs = NULL; 22 23 return job; 24 } 25 26 void destroy_job(Job *job) 27 { 28 assert(job != NULL); 29 free(job->progs); 30 free(job->cmd); 31 free(job); 32 } 33 34 /* 统计命令行参数的个数 */ 35 static int arg_num(char **arg) 36 { 37 int i = 0; 38 char *start = arg[0]; 39 40 while(start != NULL) { 41 i++; 42 start = arg[i]; 43 } 44 45 return i; 46 } 47 48 49 /* 50 * 函数功能: 构建一个 program 51 * 函数参数: 52 * @arg:命令行传入的参数 53 * 返回值: 54 */ 55 Program* create_program(char **arg)//创建一个程序 56 { 57 //在堆当中创建 program 内存块 58 Program *prog = (Program *)malloc(sizeof(Program)); 59 assert(prog != NULL); 60 61 int counter = arg_num(arg); 62 63 //多 new 一个空间存放 NULL ,所以 counter 要 +1 64 prog->args = (char **)calloc(counter + 1, sizeof(char *)); 65 66 int i; 67 for(i = 0; i < counter; i++) { 68 int len = strlen(arg[i]); 69 prog->args[i] = (char *)malloc(len); 70 assert(prog->args[i] != NULL); 71 strcpy(prog->args[i], arg[i]); 72 } 73 prog->args[i] = NULL; 74 return prog; 75 } 76 77 void destroy_program(Program *prog) 78 { 79 assert(prog != NULL); 80 int i = 0; 81 82 /* 命令行释放 */ 83 while(prog->args[i] != NULL) { 84 free(prog->args[i]); 85 i++; 86 } 87 free(prog->args);//数组释放 88 free(prog); 89 } 90 91 /* 1.通过动态分配创建一个结构体数组 92 * 2.将 job 中原先的 progs 复制给 ps 结构体数组 93 * 3.在向 ps 结构体数组中加上新的 prog 94 * 4.把 job 中原先的 progs 释放掉 95 * 5.将 job 中的 progs 指向 ps 96 */ 97 int add_program(Job *job, Program *prog)//将程序加入到 job 中 98 { 99 Program *ps = (Program *)malloc(sizeof(Program) * (job->progs_num + 1));//1 为NULL的初始化 100 101 memcpy(ps, job->progs, job->progs_num * sizeof(Program)); 102 ps[job->progs_num++] = *prog; 103 free(job->progs); 104 job->progs = ps; 105 }
编译成 .o 文件
gcc -o obj/job.o -Iinclude -c src/job.c
17.2 命令行参数的解析
17.2.1 主函数
mshell.c
1 #include "job.h" 2 #include "cmd_func.h" 3 #include <unistd.h> 4 #include <string.h> 5 #include <fcntl.h> 6 #include <stdlib.h> 7 #include <stdio.h> 8 #include <stdlib.h> 9 #include <memory.h> 10 #include <assert.h> 11 #include <malloc.h> 12 13 /* shell 中的提示符 */ 14 char *prompt = "mshell > "; 15 16 /* 指定命令行中传递的最大命令行的长度 */ 17 #define MAX_COMMAND_LEN 256 18 19 20 /* 对命令行进行解析 */ 21 void parse_cmd(Job *job, char *line) 22 { 23 char **args = (char **)malloc(100 * sizeof(char *));//创建的 program 里面的args 24 assert(args != NULL); 25 26 /* 分割命令行 */ 27 char *cmd = strtok(line, " "); 28 args[0] = (char *)malloc(strlen(cmd) * sizeof(char)); //第一个参数为命令本身 29 strcpy(args[0], cmd); 30 31 int i = 1; 32 char *s; 33 while((s = strtok(NULL, " ")) != NULL) { 34 args[i] = (char *)malloc(strlen(s) * sizeof(char)); 35 strcpy(args[i], s); 36 i++; 37 } 38 39 //根据 args 创建 program 40 Program * prog = create_program(args); 41 add_program(job, prog); 42 43 int j; 44 for(j = 0; j < i; j++) { 45 free(args[j]); 46 } 47 48 free(args); 49 } 50 51 /* 执行命令 */ 52 void excute_cmd(Job *job) 53 { 54 int i; 55 for(i = 0; i < job->progs_num; i++) { 56 if(!strcmp(job->progs[i].args[0], "cd")) { 57 cd_func(&job->progs[i]); 58 return; 59 } 60 61 if(!strcmp(job->progs[i].args[0], "pwd")) { 62 pwd_func(&job->progs[i]); 63 return; 64 } 65 66 if(!strcmp(job->progs[i].args[0], "exit")) { 67 exit_func(&job->progs[i]); 68 return; 69 } 70 } 71 } 72 73 74 int main(int argc, char *argv[]) 75 { 76 char buff[MAX_COMMAND_LEN];//存放从命令行中输入的整个命令行 77 memset(buff, 0, MAX_COMMAND_LEN); 78 ssize_t size = strlen(prompt) * sizeof(char);//提示符占用的总的大小 79 80 write(STDOUT_FILENO, prompt, size);//输出 shell 的提示符 81 82 ssize_t len; 83 while(1) { 84 /* 从标准输入读取命令行的内容 */ 85 len = read(STDIN_FILENO, buff, MAX_COMMAND_LEN); 86 buff[len - 1] = 0; //结束符 87 88 if(strlen(buff) > 0) {//命令行要大于0 89 Job *job = create_job(buff);//创建 job 90 91 parse_cmd(job, buff); //对命令行进行解析 92 93 excute_cmd(job); // 执行命令 94 destroy_job(job); // 销毁 95 96 } 97 98 write(STDOUT_FILENO, prompt, size); 99 memset(buff, 0, MAX_COMMAND_LEN); 100 } 101 102 return 0; 103 }
17.2.2 命令功能函数
cmd_func.h
1 #ifndef __CMD_FUNC_H__ 2 #define __CMD_FUNC_H__ 3 4 #include "job.h" 5 6 #define BUFF_SIZE_256 256 7 8 9 extern void cd_func(Program *prog); 10 extern void pwd_func(Program *prog); 11 extern void exit_func(Program *prog); 12 13 #endif
cmd_func.c
1 #include "cmd_func.h" 2 #include <stdio.h> 3 #include <stdlib.h> 4 #include <errno.h> 5 #include "job.h" 6 #include <fcntl.h> 7 #include <string.h> 8 #include <unistd.h> 9 10 /* 切换目录 */ 11 void cd_func(Program *prog) 12 { 13 if(chdir(prog->args[1]) < 0) { 14 perror("cd error"); 15 } 16 } 17 18 /* 显示当前工作目录路径 */ 19 void pwd_func(Program *prog) 20 { 21 char buff[256]; 22 memset(buff, 0, sizeof(buff)); 23 24 /* 获取当前工作目录的绝对路径 */ 25 if(getcwd(buff, sizeof(buff)) == NULL) { 26 perror("pwd error"); 27 } 28 29 printf("%s\n", buff); 30 } 31 32 /* 退出 */ 33 void exit_func(Program *prog) 34 { 35 exit(0); 36 }
编译成.o 文件
gcc -o obj/cmd_func.o -Iinclude -c src/cmd_func.c
17.3 编译调试
gcc -o bin/mshell -Iinclude obj/*.o src/mshell.c