打印出提示信息+获取用户键盘输入
cmd_line[NUM];用来保存完整的命令行
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/wait.h>#define NUM 1024
char cmd_line[NUM];
//shell
int main()
{while(1){printf("[root@localhost myshell]# ");fflush(stdout);//sleep(10);memset(cmd_line,'\0',sizeof cmd_line);if(fgets(cmd_line,sizeof cmd_line ,stdin) == NULL){continue;}cmd_line[strlen(cmd_line)-1] = '\0';printf("echo: %s\n",cmd_line);}
}
命令行字符串解析
char *g_argv[SIZE];保存打散后的命令符
strtok第一次调用传入原始字符串,第二次如果还要解析原始字符串则传入空
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/wait.h>#define NUM 1024
#define SIZE 32
#define SEP " "
char *g_argv[SIZE];
char cmd_line[NUM];
//shell
int main()
{while(1){printf("[root@localhost myshell]# ");fflush(stdout);//sleep(10);memset(cmd_line,'\0',sizeof cmd_line);if(fgets(cmd_line,sizeof cmd_line ,stdin) == NULL){continue;}cmd_line[strlen(cmd_line)-1] = '\0';printf("echo: %s\n",cmd_line);g_argv[0] = strtok(cmd_line,SEP);int index = 1;while(g_argv[index++] = strtok(NULL,SEP));for(index = 0;g_argv[index];index++)printf("g_argv[%d]:%s\n",index,g_argv[index]);}
}
加上颜色和部分连续命令
if(strcmp(g_argv[0], "ls") == 0){g_argv[index++] = "--color=auto";}if(strcmp(g_argv[0], "ll") == 0){g_argv[0] = "ls";g_argv[index++] = "-l";g_argv[index++] = "--color=auto";}
TODO内置命令
变化路径
fork()
全部代码
myshell.c
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/wait.h>
#include <sys/types.h>#define NUM 1024
#define SIZE 32
#define SEP " "//保存完整的命令行字符串
char cmd_line[NUM];
//保存打散之后的命令行字符串
char *g_argv[SIZE];// shell 运行原理 : 通过让子进程执行命令,父进程等待&&解析命令
int main()
{//0. 命令行解释器,一定是一个常驻内存的进程,不退出while(1){//1. 打印出提示信息 [whb@localhost myshell]# printf("[root@localhost myshell]# ");fflush(stdout);memset(cmd_line, '\0', sizeof cmd_line);//2. 获取用户的键盘输入[输入的是各种指令和选项: "ls -a -l -i"]if(fgets(cmd_line, sizeof cmd_line, stdin) == NULL){continue;}cmd_line[strlen(cmd_line)-1] = '\0';//"ls -a -l -i\n\0"//printf("echo: %s\n", cmd_line);//3. 命令行字符串解析:"ls -a -l -i" -> "ls" "-a" "-i"g_argv[0] = strtok(cmd_line, SEP); //第一次调用,要传入原始字符串int index = 1;if(strcmp(g_argv[0], "ls") == 0){g_argv[index++] = "--color=auto";}if(strcmp(g_argv[0], "ll") == 0){g_argv[0] = "ls";g_argv[index++] = "-l";g_argv[index++] = "--color=auto";}//?while(g_argv[index++] = strtok(NULL, SEP)); //第二次,如果还要解析原始字符串,传入NULL//for 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 path, cd ..continue;}//5. fork()pid_t id = fork();if(id == 0) //child{printf("下面功能让子进程进行的\n");//cd cmd , current child pathexecvp(g_argv[0], g_argv); // ls -a -l -iexit(1);}//fatherint status = 0;pid_t ret = waitpid(id, &status, 0);if(ret > 0) printf("exit code: %d\n", WEXITSTATUS(status));}
}Makefile```cpp
myshell:myshell.cgcc -o $@ $^.PHONY:clean
clean:rm -f myshell