首先附上完整代码
#include <stdio.h> #include <stdlib.h> #include <unistd.h> #include <string.h> #include <sys/types.h> #include <sys/wait.h> //命令行解释器 //shell 运行原理:通过让子进程执行命令,父进程等待&&解析命令 //保存完整的命令行字符串 -- 充当缓冲区 #define NUM 1024 char cmd_line[NUM]; //保存切割之后的字符串 #define SIZE 32 char* g_argv[SIZE]; #define SEP " " int main() { //0.命令行解释器,一定是一个常驻内存的进程 --- 不退出(死循环) while(1) { //1打印出提示信息 -- [wxq@VM-4-9-centos shell]$ printf("[dwr@VM-1-1-test shell]$ "); fflush(stdout); //2.获取用户的键盘输入[输入的是各种指令和选项"ls -a -l"] memset(cmd_line, 0, sizeof cmd_line); if(fgets(cmd_line, sizeof cmd_line, stdin) == NULL) { continue; } //输入的回车键设为\0 ls -a -l \n \0 cmd_line[strlen(cmd_line)-1] = '\0'; // printf("echo:%s\n", cmd_line); //debug //3.命令行字符串进行解析 "ls -a -l -s" ---> "la" "-a" "-l" "-s" g_argv[0] = strtok(cmd_line, SEP); //第一次调用,传入原始的字符串 int index = 1; while(g_argv[index++] = strtok(NULL, SEP)); //第二次调用,如果还要分割原始字符串,传入NULL //简单配置ls的颜色 int i = 1; if(strcmp(g_argv[0], "ls") == 0) { g_argv[i++] = "--color=auto"; } //识别别名 - 主要是测试,一般是有接口的 if(strcmp(g_argv[0], "ll") == 0) { g_argv[0] = "ls"; g_argv[i++] = "-l"; g_argv[i++] = "--color=auto"; } //debug // for(index = 0 ; g_argv[index]; index++) // { // printf("g_argv[%d]: %s\n", index, g_argv[index]); // } //4.TODO 内置命令:让父进程(shell)自己执行的命令。我们叫做内置命令,内建命令 //内建命令本质就是shell中的一个函数调用 if(strcmp(g_argv[0], "cd") == 0) //not child execute; father execute; { if(g_argv[1] != NULL) { chdir(g_argv[1]); //cd cd .. } continue; } //5.创建子进程进行程序替换 pid_t id = fork(); //child if(id == 0) { execvp(g_argv[0],g_argv); exit(-1); } //father int status = 0; pid_t ret = waitpid(id, &status, 0); //阻塞等待 if(ret > 0) { printf("exit code:%d\n",WEXITSTATUS(status)); } } return 0; }
效果:
命令行解释器
shell 运行原理:通过让子进程执行命令,父进程等待&&解析命令
步骤1. 命令行解释器,一定是一个常驻内存的进程 --- 这意味着它是不退出的(死循环)