1、首先了解shell的基本框架
如上图所示
[用户名@主机名 当前路径]$ 命令
执行命令结果
目标:完成一个简单的shell(输入命令可以得到执行结果)
所以框架分为:
1、【提示符】$的显示 -----一堆函数的调用即可
2、 命令的执行-----读入数据,进行解析,得到argv[],执行execvp
3、 对于内置命令cd的单独处理
#include <stdio.h> #include <pwd.h> #include <sys/types.h> #include <unistd.h> #include <string.h> #include <stdlib.h> void prompt() { struct passwd * p1; char username[64]; char hostname[256]; char pathname[1024]; //获取用户名 p1=getpwuid(getuid()); //获取路径 getcwd(pathname,sizeof(pathname)); //获取主机名---返回0正确 if(gethostname(hostname,sizeof(hostname))==0) { printf("[DIY %[email protected]%s:%s ]",p1->pw_name,hostname,pathname); } else { printf("[DIY %[email protected]:%s ]",p1->pw_name,pathname); } if(geteuid()==0) { printf("#"); } else { printf("$"); } } int main() { while(1) { prompt(); fflush(stdout); //获得环境变量 char buf[1024]; memset(buf,0,sizeof(buf)); size_t size=read(0,buf,sizeof(buf)-1); if(size>0) { buf[size-1]=‘\0‘; } // printf("%s\n",buf); char *p=buf; int i=0; char * my_argv[64]={0}; my_argv[0]=p; while(*p!=0) { if(*p==‘ ‘) { *p=‘\0‘; ++p; my_argv[++i]=p; } else { ++p; } } pid_t id=fork(); if(id==0) //子进程 { if(strcmp(my_argv[0],"cd")==0) { chdir(my_argv[1]); } else { execvp(my_argv[0],my_argv); } } else //父进程 { pid_t ret=waitpid(id,NULL,0); } } return 0; }
这样看好像一切都辣么完美~~~
然而却没办法退出,除非按control+z键强行退出
于是,我想是不是exit也可以实现
if(id==0) { if(strcmp(my_argv[0],"exit")==0) { exit(0); } ... } else { pid_t ret=waitpid(id,NULL,0); if(strcmp(my_argv[0],"exit")==0) { exit(0); } } } return 0; }
结果是:
然而接下来这个exit做出的事情就比较神奇了
用了两次cd,pwd操作,然而exit却要执行三次才可以退出,这是为什么呢?
于是为了调试我将所有指令执行的进程的id及其父进程的id进行了打印分析
结论:
ls:第一次创建的子进程在执行完execvp之后终止
cd..第二次创建的子进程在执行chdir并不会终止
cd..第三次创建的子进程其父进程是第二次创建的子进程且不会终止
当执行exit,会从里到外一层一层的终止,然后才退出整个程序
改进方案:
将cd执行的函数写入到父进程
#include <stdio.h> #include <pwd.h> #include <sys/types.h> #include <unistd.h> #include <string.h> #include <stdlib.h> void prompt() { struct passwd * p1; char username[64]; char hostname[256]; char pathname[1024]; //获取用户名 p1=getpwuid(getuid()); //获取路径 getcwd(pathname,sizeof(pathname)); //获取主机名---返回0正确 if(gethostname(hostname,sizeof(hostname))==0) { printf("[DIY %[email protected]%s:%s ]",p1->pw_name,hostname,pathname); } else { printf("[DIY %[email protected]:%s ]",p1->pw_name,pathname); } if(geteuid()==0) { printf("#"); } else { printf("$"); } } int main() { while(1) { prompt(); fflush(stdout); char buf[1024]; memset(buf,0,sizeof(buf)); size_t size=read(0,buf,sizeof(buf)-1); if(size>0) { buf[size-1]=‘\0‘; } // printf("%s\n",buf); char *p=buf; int i=0; char * my_argv[64]={0}; my_argv[0]=p; while(*p!=0) { if(*p==‘ ‘) { *p=‘\0‘; ++p; my_argv[++i]=p; } else { ++p; } } pid_t id=fork(); if(id==0) { if(strcmp(my_argv[0],"exit")==0) { exit(0); } if(strcmp(my_argv[0],"cd")==0) { exit(0); } else { execvp(my_argv[0],my_argv); } } else { pid_t ret=waitpid(id,NULL,0); if(strcmp(my_argv[0],"cd")==0) { chdir(my_argv[1]); } if(strcmp(my_argv[0],"exit")==0) { exit(0); } } } return 0; }
结果:
时间: 2024-10-29 19:09:48