目录
shell解释器:
就像下面Centos的环境下的命令行,可以解析我们输入的指令来达到运行不同功能的实现;
shelll条件:
必须是永不退出的,常驻内存的,我们使用死循环来解决;
输入的命令又指令和指令选项:ls -a -l,我们使用命令分割来进行区分
命令分割后解析需要子进程来运行解析后的指令对应的进程,这里需要运行其他进程,但是又不能影响父进程,我们创建子进程用execvp进行程序替换,来实现运行不同指令的效果;
我们需要将输入的指令和选项分割开,方便我们来解析指令;
这里我们采用了字符串函数strtok()来分割
- g_argv[0] = strtok(cmd_line, SEP);//第一次调用,传入原始字符串
- int index = 1;
- if (strcmp(g_argv[0], "ls") == 0)
- {
- g_argv[index++] = "--color=auto";
- }
- while(g_argv[index++] = strtok(NULL, SEP));//第二次调用,如果还要解析,传入NUL
将命令解析后,创建子进程使用execvp()替换函数,来进行程序替换,实现功能;
这时的父进程只需要等待子进程正常退出即可;
- 64 //5.fork();
- 65 pid_t id = fork();
- 66 if (id == 0)// child
- 67 {
- 68 printf("功能子进程执行\n");
- 69 // cd 只影响当前的进程
- 70 execvp(g_argv[0], g_argv);//ls -a -l
- 71 exit(-1);
- 72 }
- 73
- 74 // father
- 75 int status = 0;
- 76 pid_t ret = waitpid(id, &status, 0);
- 77 if (ret > 0)
- 78 {
- 79 printf("exit code:%d\n", WEXITSTATUS(status));
- 80 }
- 1 #include <stdio.h>
- 2 #include <stdlib.h>
- 3 #include <string.h>
- 4 #include <unistd.h>
- 5 #include <sys/wait.h>
- 6 #include <sys/types.h>
- 7
- 8 #define NUM 1024
- 9 #define SIZE 32
- 10 #define SEP " "
- 11
- 12 //保存打散之后的命令行 字符串
- 13 char *g_argv[SIZE];
- 14 //保存完成的命令行
- 15 char cmd_line[NUM];
- 16
- 17 //shell运行原理
- 18 //通过让子进程执行命令,父进程等待&&解析命令
- 19 int main()
- 20 {
- 21 //0.命令行解释器, 一定是一个常驻内存进程,不退出
- 22 while (1)
- 23 {
- 24 //1.打印提示信息
- 25 // [mr@localhost myshell]#
- 26 printf("[my@localhost myshell]#");
- 27 fflush(stdout);
- 28 memset(cmd_line, '\0', sizeof cmd_line);
- 29 //2.获取用户键盘输入的各种指令和选项: “ls -a -l”
- 30 if (fgets(cmd_line, sizeof cmd_line, stdin) == NULL)
- 31 {
- 32 continue;
- 33 }
- 34 cmd_line[strlen(cmd_line) - 1] = '\0';
- 35
- 36 //printf("echo:%s\n", cmd_line);
- 37
- 38 //3.命令行字符串解析
- 39 g_argv[0] = strtok(cmd_line, SEP);//第一次调用,传入原始字符串
- 40 int index = 1;
- 41 if (strcmp(g_argv[0], "ls") == 0)
- 42 {
- 43 g_argv[index++] = "--color=auto";
- 44 }
- 45 while(g_argv[index++] = strtok(NULL, SEP));//第二次调用,如果还要解析,传入NUL
- 46
- 47 // for (index = 0; g_argv[index]; index++)
- 48 // {
- 49 // printf("g_argv[%d]:%s\n",index,g_argv[index]);
- 50 // }
- 51 //4.TODO 内置命令 :让父进程(shell)自己执行命令,叫做内置命令,内建命令
- 52 //内建命令本质就是shell中的一个函数调用
- 53 if (strcmp(g_argv[0], "cd") == 0) //not child excute, father excute
- 54 {
- 55 if(g_argv[1] != NULL)
- 56 {
- 57 chdir(g_argv[1]);
- 58
- 59 continue;
- 60 }
- 61 }
- 62
- 63
- 64 //5.fork();
- 65 pid_t id = fork();
- 66 if (id == 0)// child
- 67 {
- 68 printf("功能子进程执行\n");
- 69 // cd 只影响当前的进程
- 70 execvp(g_argv[0], g_argv);//ls -a -l
- 71 exit(-1);
- 72 }
- 73
- 74 // father
- 75 int status = 0;
- 76 pid_t ret = waitpid(id, &status, 0);
- 77 if (ret > 0)
- 78 {
- 79 printf("exit code:%d\n", WEXITSTATUS(status));
- 80 }
- 81 }
- 82
- 83 return 0;
- 84 }