linux下编写一个仿shell
2016-06-25 22:21
344 查看
1、首先了解shell的基本框架
如上图所示
[用户名@主机名 当前路径]$ 命令
执行命令结果
目标:完成一个简单的shell(输入命令可以得到执行结果)
所以框架分为:
1、【提示符】$的显示 -----一堆函数的调用即可
2、 命令的执行-----读入数据,进行解析,得到argv[],执行execvp
3、 对于内置命令cd的单独处理
这样看好像一切都辣么完美~~~
然而却没办法退出,除非按control+z键强行退出
于是,我想是不是exit也可以实现
然而接下来这个exit做出的事情就比较神奇了
用了两次cd,pwd操作,然而exit却要执行三次才可以退出,这是为什么呢?
于是为了调试我将所有指令执行的进程的id及其父进程的id进行了打印分析
结论:
ls:第一次创建的子进程在执行完execvp之后终止
cd..第二次创建的子进程在执行chdir并不会终止
cd..第三次创建的子进程其父进程是第二次创建的子进程且不会终止
当执行exit,会从里到外一层一层的终止,然后才退出整个程序
改进方案:
将cd执行的函数写入到父进程
本文出自 “momo就是辣么萌” 博客,请务必保留此出处http://momo462.blog.51cto.com/10138434/1792908
如上图所示
[用户名@主机名 当前路径]$ 命令
执行命令结果
目标:完成一个简单的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 %s@%s:%s ]",p1->pw_name,hostname,pathname); } else { printf("[DIY %s@unkown:%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 %s@%s:%s ]",p1->pw_name,hostname,pathname); } else { printf("[DIY %s@unkown:%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; }结果:
本文出自 “momo就是辣么萌” 博客,请务必保留此出处http://momo462.blog.51cto.com/10138434/1792908
相关文章推荐
- 解决hbase 执行shell命令出错问题
- 说说shell脚本中的export 和 source,bash
- shell 字符(串)处理命令
- 详解Xshell连接本地安装的Linux虚拟机—— Debian
- spark源码阅读之spark-shell
- 模拟Linux的shell
- /etc/profile、/etc/bashrc、~/.bash_profile、~/.bashrc 的区别(转)
- Shell特殊变量:Shell $0, $#, $*, $@, $?, $$和命令行参数
- shell下正则表达式与其工具grep
- shell --- grep 命令详解
- Shell变量:Shell变量的定义、删除变量、只读变量、变量类型
- BASH SHELL not a valid identifier
- Java调用Shell脚本
- 第一个Shell脚本
- bash脚本设置时间
- shell脚本--sed工具
- shell的部分习题(持续更新)
- shell脚本实现动态时钟
- 什么时候使用Shell
- Shell脚本语言与编译型语言的差异