myshell

cpp 复制代码
  1 #include<cstdio>                                                                                                          
  2 #include<string.h>
  3 #include<string>
  4 #include<cstring>
  5 #include<cstdlib>
  6 #include<cstdbool>
  7 #include<sys/types.h>
  8 #include<sys/wait.h>
  9 #include<unistd.h>
 10 #include<iostream>
 11 #define command_size 1024
 12 #define format "[%s@%s %s]#"
 13 //下面定义shell的全局变量 
 14 char cwd[1024];
 15 char cwdenv[1024];
 16 using namespace std;
 17 #define maxargc 128
 18 char*  my_argv[maxargc];
 19 #define maxenv 2000
 20 char* my_env[maxenv];
 21 int lastcode=0;
 22 int argc=0;
 23 int myenvs=0;
 24 const char* getusername()
 25 {
 26     const char* name=getenv("USER");
 27     return name==NULL?"None":name;
 28 }
 29 const char* gethostname()
 30 {
 31     const char* hostname=getenv("HOSTNAME");
 32     return hostname==NULL?"None":hostname;
 33 }
 34 const char* getpath()
 35 {
 36     const char* path=getcwd(cwd,sizeof(cwd));//获得当前进程的工作路径
 37     if(path)
 38     {
 39         snprintf(cwdenv,sizeof(cwdenv),"PWD=%s",cwd);
 40         putenv(cwdenv);
 41     }
 42     return path==NULL?"None":path;
 43 }
 44 const char* gethome()
 45 {
 46     const char* home=getenv("HOME");
 47     return home==NULL?NULL:home;
 48 }
 49 void makecmdline(char cmd_prompt[],int size)
 50 {
 51     snprintf(cmd_prompt,size,format,getusername(),gethostname(),getpath());                                               
 52 }
 53 void printcmdprompt()
 54 {
 55     char prompt[command_size];
 56     makecmdline(prompt,sizeof(prompt));
 57     printf("%s ",prompt);
 58     fflush(stdout);
 59 }
 60 bool getcommandline(char* out,int size)
 61 {    
 62     char* c=fgets(out,size,stdin);
 63     if(c==NULL) return false;
 64     out[strlen(out)-1]=0;
 65     if(sizeof(out)==0) return false;
 66     return true;
 67 }
 68 #define dsp " "
 69 bool commandparse(char* commandline)
 70 {
 71     argc=0;
 72     my_argv[argc++]=strtok(commandline,dsp); 
 73     while((bool)(my_argv[argc++]=strtok(NULL,dsp)));
 74     argc--;
 75     return argc>0?true:false;
 76 }
 77 int execute()
 78 {
 79     pid_t id=fork();
 80     int status=0;
 81     if(id==0)
 82     {
 83         //子进程
 84         execvp(my_argv[0],my_argv);                                                                                       
 85         exit(1);
 86     }
 87     pid_t rid=waitpid(id,&status,0);
 88     if(rid>0)
 89     {
 90         lastcode=WEXITSTATUS(status);
 91         
 92     }
 93     return 0;
 94 }
 95 bool check()//查看是否是内建命令,并对内建命令进行相应的操作
 96 {
 97     string cmd=my_argv[0];
 98     if(cmd=="cd") {
 99         if(argc==1)//返回家目录
100         {
101             if(gethome()==NULL) return true;
102             else chdir(gethome());
103         }
104         else{
105             string where=my_argv[1];
106             chdir(where.c_str());
107         }
108         return true;                                                                                                      
109     }
110     else if(cmd=="echo")
111     {
112         if(argc==2)
113         {
114             //echo "hello wworld"
115             //echo $?
116             //echo $PATH
117             string opt=my_argv[1];
118             if(opt=="$?") 
119             {
120                 cout<<lastcode<<endl;
121                 lastcode=0;
122             }
123             else if(opt[0]=='$')//查找父进程的环境变量,因为我们今天并没有创建自己进程的环境变量表,所以我们还是使用从父进    程继承的环境变量
124             {
125                 string envname=opt.substr(1);
126                 if(getenv(envname.c_str())) cout<<getenv(envname.c_str())<<endl;
127             }
128             else 
129             {                                                                                                             
130                 cout<<opt<<endl;
131             }
132         }
133         return true;
134     }  
135     else if(cmd=="export")
136     {
137         if(argc==2)
138         {
139             my_env[myenvs]=(char*)malloc(strlen(my_argv[1])+1);
140             strcpy(my_env[myenvs++],my_argv[1]);//strcpy会拷贝字符串结尾的\0,但是strlen并不会将\0计算在内
141             putenv(my_env[myenvs-1]);
142         }     
143         return true;
144     }
145     else return false;
146 }
147 void initenv()
148 {
149     extern char** environ;
150     memset(my_env,0,sizeof(my_env));
151     myenvs=0;
152     for(int i=0;environ[i];i++)
153     {
154         my_env[i]=(char*)malloc(strlen(environ[i])+1);
155         strcpy(my_env[i],environ[i]);
156         myenvs++;                                                                                                         
157     }
158     my_env[myenvs++]=(char*)"test=haha";
159     my_env[myenvs]=NULL;
160 
161     //导成环境变量
162     for(int i=0;my_env[i];i++)
163     {
164         putenv(my_env[i]);//换将变量中如果没有这个环境变量名字就新增这个环境变量,否则就将其替换。
165     }
166 }
167 int main()
168 {
169     //shell启动的时候要从系统中获取环境变量
170     //我们的环境变量的信息应该来原来父进程
171     initenv();
172     while(1)
173     {
174         //输出命令行提示符
175         printcmdprompt();
176         //获取用户输入的命令
177         char commandline[command_size];
178         if(!getcommandline(commandline,sizeof(commandline)))
179             continue;
180         //命令行分析
181         if(!commandparse(commandline)) continue;
182         //检查是否是内建命令
183         if(check()) continue;
184         //执行命令
185         execute();
186     }
187     return 0;
188 }   

命令行解释器:

1.获取命令行

2.解析命令行

3.建立子进程

4.替换子进程

5.父进程等待子进程退出

相关推荐
Sapphire~2 小时前
Linux-07 ubuntu 的 chrome 启动不了
linux·chrome·ubuntu
伤不起bb2 小时前
NoSQL 之 Redis 配置与优化
linux·运维·数据库·redis·nosql
广东数字化转型2 小时前
nginx怎么使用nginx-rtmp-module模块实现直播间功能
linux·运维·nginx
啵啵学习2 小时前
Linux 里 su 和 sudo 命令这两个有什么不一样?
linux·运维·服务器·单片机·ubuntu·centos·嵌入式
南郁2 小时前
007-nlohmann/json 项目应用-C++开源库108杰
c++·开源·json·nlohmann·现代c++·d2school·108杰
半桔3 小时前
【Linux手册】冯诺依曼体系结构
linux·缓存·职场和发展·系统架构
网硕互联的小客服3 小时前
如何利用Elastic Stack(ELK)进行安全日志分析
linux·服务器·网络·安全
菠萝014 小时前
共识算法Raft系列(1)——什么是Raft?
c++·后端·算法·区块链·共识算法
冰橙子id4 小时前
linux——磁盘和文件系统管理
linux·运维·服务器
海棠蚀omo4 小时前
C++笔记-C++11(一)
开发语言·c++·笔记