目的:我们要用c语言编写一个shell可以运行在linux机器上的。

介绍:shell所在的层次

 

 

我们要做的是操作系统,用于用户与操作系统进行交互的myhsell

 

思路:用户输入  一行字符串,我们先将其进行切割为一段段的字符串,然后一一匹配判断是内置命令还是 外置命令。内置命令是写在shell程序里面的,而外置命令是单独写的程序,用exec族系统调用。

 

好,那么下面我们看代码:

 

 

  1 #include<stdio.h>
  2 #include<unistd.h>
  3 #include<sys/wait.h>
  4 #include<stdlib.h>
  5 #include<pwd.h>
  6 #include<string.h>
  7 #define MAX_CMD 255
  8 #define MAX_DIR_NAME 255
  9 
 10 //help帮助文档
 11 int helps(char *inputs[],int i){
 12         if(i==1){
 13 printf("These shell commands are defined internally.  Type 'help' to see this list.\n");
 14 printf("Type 'help name' to find out more about the function 'name'\n");
 15        return 1;
 16         }
 17         else if (strcmp(inputs[1],"pwd")==0){
 18                 printf("pwd:打印当前绝对路径\n");
 19        return 1; 
 20         }else if(strcmp(inputs[1],"cd")==0){
 21         printf("cd:可以切换当前目录\n"); 
 22         return 1;
 23         } else if(strcmp(inputs[1],"exit")==0){
 24         printf("exit:退出shell\n"); 
 25         return 1;
 26         } else if(strcmp(inputs[1],"echo")==0){
 27         printf("echo:显示并换行\n"); 
 28         return 1;
 29         } 
 30                  return 0;
 31 }                
 32 
 33 
 34 
 35 //编写一个外置命令函数专门写内置指令 
 36 //返回值为1时为成功执行外置指令 
 37 //返回0时为执行失败不是外置命令
 38 int build_out_command(char *inputs[],int i){
 39 char path[]="/root/Desktop/codec/myshell/";
 40 char buffer[10];
 41 bzero(buffer,10);
 42 int fd[2];
 43 if(pipe(fd)==-1){
 44 return 0;
 45 }
 46 int rc=fork();
 47 if(rc<0){
 48 return 0;
 49 }
 50 else if(rc==0){
 51 //关掉读 
 52 close(fd[0]);
 53 if(execv(strcat(path,inputs[0]),inputs)<0){
 54 write(fd[1],"false",10);
 55 }else{
 56 write(fd[1],"true",10);
 57 }
 58 close(fd[1]);
 59 exit(0);
 60 //结束子进程 
 61 }else if(rc>0){
 62 close(fd[1]);
 63 wait(NULL);
 64 read(fd[0],buffer,10);
 65 if(strcmp(buffer,"false")==0){
 66 return 0;
 67 }else{
 68 return 1;
 69 }
 70 }
 71 }
 72 
 73 
 74 
 75 
 76 //编写一个内置命令函数专门写内置指令
 77 //返回值为1时为成功执行内置指令 
 78 //返回0时为不是内置命令 
 79 int build_in_command(char cmdstring[],char *inputs[],int i){
 80 //1.实现exit退出
 81 //printf("inputs[0]=%s",inputs[0]);
 82 if(strcmp(inputs[0],"exit")==0){
 83 printf("Bye.\n");
 84 exit(0);
 85 }
 86 //2.实现pwd返回目录
 87 else if(strcmp(inputs[0],"pwd")==0){
 88 char path[MAX_DIR_NAME];
 89 memset(path,0,MAX_DIR_NAME);
 90 printf("%s\n",getcwd(path,MAX_DIR_NAME));
 91 return 1;
 92 }
 93 //3.实现cd改变目录 
 94 else if(strcmp(inputs[0],"cd")==0){
 95         if(chdir(inputs[1])==0){
 96                 return 1;
 97         }
 98 
 99 }
100 //4.echo显示并换行
101 else if(strcmp(inputs[0],"echo")==0){
102         char *buf1=cmdstring;
103         while(*buf1==' '){
104                 buf1++;
105         }
106         while(*buf1!=' '){
107                 buf1++;
108         }
109         while(*buf1==' '){
110                 buf1++;
111         }
112 
113         printf("%s\n",buf1);
114         return 1;
115 
116 }
117 //help帮助文档 
118 else if(strcmp(inputs[0],"help")==0){
119 int i1= helps(inputs,i);
120 return i1;
121 }
122 
123 
124 
125 return 0;
126 }
127 
128 
129 struct passwd *pwd1;
130 pwd1=getpwuid(getuid());
131 char path[MAX_DIR_NAME];
132 memset(path,0,MAX_DIR_NAME);
133 getcwd(path,MAX_DIR_NAME);
134 int i=0;
135 int len=strlen(path);
136 char *p=path;
137 
138 int i1=len;
139 for(i1;i1>=0;i1--){
140 if(path[i1]=='/'){
141 path[i1]='\0';
142 break;
143 }
144 }
145 for(i;i<=i1;i++){
146 p++;
147 }
148 printf("<%s@localhost :%s#> ",pwd1->pw_name,p);
149 } 
150 
151 
152 
153 
154 
155 //解析指令 例如ls -l  ,将该指令分为ls和-l两个字符串分别存储在inputs字符串数数组
156 //返回值是存储的个数最后一位为NULL一共i+1个
157 int parsecommand(char buf[],char *inputs[]){
158 bzero(inputs,MAX_CMD);
159 int in=0;
160 char *p=buf;
161 int i=0;
162 while(*p==' '){
163     p++;
164     i++;
165 }
166 inputs[in]=p;
167 in++;
168 int i1=i;
169 int len=strlen(buf);
170 for(i;i<=len;i++){
171 if(buf[i]==' '){
172     buf[i]='\0';
173 
174 }
175 }
176 i1++;
177 p++;
178 for(i1;i1<=len;i1++,p++){
179 if(buf[i1]!='\0'){
180     if(buf[i1-1]=='\0'){
181         inputs[in]=p;
182         in++;
183     }
184 
185 }
186 }
187 inputs[in]=NULL;
188 
189 return in;
190 
191 //一共有in+1个字符串,最后一位NULL
192 
193 }
194 
195 
196 //整体执行函数分为内部命令和外部命令
197 //内部命令直接调用函数执行就好
198 //外部命令自己编写在另一个文件,通过gcc编译
199 //在该函数里通过exec家族函数调用执行
200 int  eval(char cmdstring[]){
201 char *inputs[MAX_CMD];
202 char buf[MAX_CMD];
203 strcpy(buf,cmdstring);
204 int i=parsecommand(buf,inputs);
205 //下面实现一些功能
206 //调用内置外置函数 
207 
208 int returnin=build_in_command(cmdstring,inputs,i);
209 if(returnin==0){
210 int rtout=build_out_command(inputs,i);
211 if(rtout==0){
212 printf("%s: not find command\n",cmdstring);
213 return 0;
214 }
215 }
216 return 1;
217 }
218 
219 
220 
221 
222 //main函数通过循环不断接受用户数据
223 //调用eval功能函数实现
224 int main(int argc,char *argv[]){
225 system("stty erase ^H");
226 char cmdstring[MAX_CMD];
227 bzero(cmdstring,MAX_CMD);
228 while(1){
229 attention();
230 fflush(stdout);
231 //读取输入流
232 fgets(cmdstring,MAX_CMD,stdin);
233 //如果没有输入从新开始
234 if(cmdstring[0]=='\n'){
235 continue;
236 }
237 int i=0;
238 for(i;cmdstring[i]!='\n';i++){
239     ;
240 }
241 cmdstring[i]='\0';
242 
243 int p=eval(cmdstring);
244 }
245 return 0;
246 
247 }
248   

 

外置命令单独写文件

 

 

对myshell运行使用几个命令如下:

 

 

代码从main函数开始看,如果有不明白的欢迎给我留言哦!!!

 

 

 

 

 

版权声明:本文为lhyzdd原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://www.cnblogs.com/lhyzdd/p/13997373.html