目录
模拟实现shell程序
所用知识
1.基础的C语言知识,fgets,fflush(刷新缓冲区)
2.字符串相关的函数:strtok
3.进程的创建(fork)进程的等待(waitpid) 进程的替换(exec*函数) 进程的终止(exit)
shell运行原理
父进程等待&&解析指令,子进程执行指令
1.实现逻辑
shell需要一直等待用户输入指令,然后执行指令,因此写一个死循环
1.打印出字符串"[zy@localhost myshell]# "提示用户输入信息
--使用fflush刷新缓冲区
2.父进程分析指令
--定义一个字符数组cmd来存放完整的指令(使用fgets函数,将命令读取到字符数组cmd中)
--定义一个字符指针数组来存放拆解后的指令(使用strtok函数,将其拆解)
--创建子进程执行指令,然后阻塞等待执行的结果
3.子进程执行指令
--调用execvp函数,执行拆解好的指令
2.代码及效果展示
--预备工作
--定义一个字符数组cmd来存放完整的指令(使用fgets函数,将命令读取到字符数组cmd中)
--定义一个字符指针数组来存放拆解后的指令(使用strtok函数,将其拆解)
--定义一个分割符(使用#define定义SEP为空格)
1.打印字符串提示用户输入指令
19 //1.打印字符串,提示用户输入指令 20 printf("[zy@localhost myshell]# "); 21 fflush(stdout); 22 memset(cmd,'\0',sizeof(cmd));//初始化 23 24 if(fgets(cmd,sizeof(cmd),stdin)==NULL) continue;//读取用户输入的指令,若输入为NULL直接跳过 25 cmd[strlen(cmd)-1] = '\0';//由于是从键盘读取,会读取到\n,我们将其置为\0
--fflush是用来刷新缓冲区的
--memset将cmd数组初始化,也清除了上一次输入的指令
--fgets函数:参数:char *str,int num ,FILE* stream
1.存储从输入流中读取的字符串 2.读取的最大字符数 3.从那读
2.父进程拆解指令
代码:
27 //2.拆解指令,放进g_argv中,后面调用execvp的时候直接传递 28 int index = 0; 29 g_argv[index++] = strtok(cmd,SEP); 30 while(g_argv[index++]=strtok(NULL,SEP));
--strtok:参数:char* str , const char * strDelimit (要分割的字符串,用来分割的字符)
第一次调用后,下一次还要继续分割这个字符,传递NULL即可,它会记录分割点的位置
3.子进程执行指令,父进程等待结果
4.效果
3.实现过程中遇到的问题
1.打印字符串的时候不显示
字符串不显示
使用fflush,刷新缓冲区即可
效果:
2.多换了一行
代码:
这里可以看到多换了一行
原因:fgets从键盘读取数据会把\n也读进cmd中,我们需要把\n置为'\0'
方法:cmd[strlen(cmd)-1] = '\0'; strlen遇到\0就不在计数了,通过其找到'\n'的位置
效果:
3.cd路径无效
原因:
1.子进程是父进程的一份拷贝,直接用pwd显示的路径就是父进程的路径
2.如果使用cd指令,exec函数执行完就退出了,再执行pwd就是重新调用,父进程会生成一个新的子进程, 显示的是父进程的路径
解决:加一个判断,如果是cd命令,直接使用chdir改变当前父进程的路径
33 if(strcmp(g_argv[0],"cd")==0)//特殊处理一下cd指令 34 { 35 if(g_argv[1]!=NULL) chdir(g_argv[1]); 36 continue; 37 }
解决:
4.优化
1.ll指令
解决:特殊处理一下
32 if(strcmp(g_argv[0],"ll")==0)//特殊处理一下ll指令 33 { 34 g_argv[0] = (char*)"ls"; 35 g_argv[index++] = (char*)"-l"; 36 }
原来:
解决:
2.给文件或目录加上颜色
思路:特殊处理
这是ls加上颜色的指令:
代码:
32 if(strcmp(g_argv[0],"ls")==0)//特殊处理ls指令,为其加上颜色 33 { 34 g_argv[index++] = (char*)"--color=auto"; 35 } 36 37 if(strcmp(g_argv[0],"ll")==0)//特殊处理ll指令 38 { 39 g_argv[0] = (char*)"ls"; 40 g_argv[index++] = (char*)"--color=auto"; 41 g_argv[index++] = (char*)"-l";
效果: