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.父进程等待子进程退出

相关推荐
云边有个稻草人1 小时前
【Linux系统】第四节—详解yum+vim
linux·vim·yum·软件包管理器·linux软件生态·linux编辑器-vim使⽤·yum具体操作
小陶来咯1 小时前
【高级IO】多路转接之单线程Reactor
服务器·网络·数据库·c++
dz小伟4 小时前
vim的配置
linux·编辑器·vim
江湖人称-杰6 小时前
CentOS配置了镜像源之后依旧下载元数据失败
linux·运维·centos
C++实习生6 小时前
powerbuilder9.0中文版
c语言·c++
阿运河6 小时前
如何配置 VScode 断点调试Linux 工程代码
linux·ide·vscode
oioihoii7 小时前
C++23 std::generator:用于范围的同步协程生成器 (P2502R2, P2787R0)
开发语言·c++·c++23
Cuit小唐7 小时前
C++ 迭代器模式详解
c++·算法·迭代器模式
Xena_Networks8 小时前
SierraNet协议分析使用指导[RDMA]| 如何设置 NVMe QP 端口以进行正确解码
linux·服务器·网络
2401_858286118 小时前
CD37.【C++ Dev】string类的模拟实现(上)
开发语言·c++·算法