目的:我们要用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