├── myShell ├── myShellhelp.png ├── Makefile ├── README.md └── myShell.c /myShell: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/renkangchen/myShell/HEAD/myShell -------------------------------------------------------------------------------- /myShellhelp.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/renkangchen/myShell/HEAD/myShellhelp.png -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | #myShell 2 | CC = gcc 3 | SRC = myShell.c 4 | .PHONY : clean 5 | 6 | all: 7 | $(CC) $(SRC) -o myShell -lreadline -lncurses 8 | clean: 9 | -rm myShell myShell.o 10 | 11 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # myShell 2 | 3 | ![](https://github.com/renkangchen/myShell/raw/master/myShellhelp.png) 4 | 5 | This is a C program which imitates the bash shell. 6 | 7 | **make**, 8 | then you should have the **myShell**, 9 | use **./myShell** to run it. 10 | 11 | make sure you already have installed the [readline library](http://cnswww.cns.cwru.edu/php/chet/readline/rltop.html#Introduction). 12 | -------------------------------------------------------------------------------- /myShell.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | 12 | 13 | //define the printf color 14 | #define L_GREEN "\e[1;32m" 15 | #define L_BLUE "\e[1;34m" 16 | #define L_RED "\e[1;31m" 17 | #define WHITE "\e[0m" 18 | 19 | #define TRUE 1 20 | #define FALSE 0 21 | #define DEBUG 22 | 23 | char lastdir[100]; 24 | char command[BUFSIZ]; 25 | char argv[100][100]; 26 | char **argvtmp1; 27 | char **argvtmp2; 28 | char argv_redirect[100]; 29 | int argc; 30 | int BUILTIN_COMMAND = 0; 31 | int PIPE_COMMAND = 0; 32 | int REDIRECT_COMMAND = 0; 33 | //set the prompt 34 | void set_prompt(char *prompt); 35 | //analysis the command that user input 36 | int analysis_command(); 37 | void builtin_command(); 38 | void do_command(); 39 | //print help information 40 | void help(); 41 | void initial(); 42 | void init_lastdir(); 43 | void history_setup(); 44 | void history_finish(); 45 | void display_history_list(); 46 | 47 | int main(){ 48 | char prompt[BUFSIZ]; 49 | char *line; 50 | 51 | init_lastdir(); 52 | history_setup(); 53 | while(1) { 54 | set_prompt(prompt); 55 | if(!(line = readline(prompt))) 56 | break; 57 | if(*line) 58 | add_history(line); 59 | 60 | strcpy(command, line); 61 | //strcat(command, "\n"); 62 | if(!(analysis_command())){ 63 | //todo deal with the buff 64 | if(BUILTIN_COMMAND){ 65 | builtin_command(); 66 | }//if 67 | else{ 68 | do_command(); 69 | }//else 70 | }//if analysis_command 71 | initial();//initial 72 | }//while 73 | history_finish(); 74 | 75 | return 0; 76 | } 77 | 78 | //set the prompt 79 | void set_prompt(char *prompt){ 80 | char hostname[100]; 81 | char cwd[100]; 82 | char super = '#'; 83 | //to cut the cwd by "/" 84 | char delims[] = "/"; 85 | struct passwd* pwp; 86 | 87 | if(gethostname(hostname,sizeof(hostname)) == -1){ 88 | //get hostname failed 89 | strcpy(hostname,"unknown"); 90 | }//if 91 | //getuid() get user id ,then getpwuid get the user information by user id 92 | pwp = getpwuid(getuid()); 93 | if(!(getcwd(cwd,sizeof(cwd)))){ 94 | //get cwd failed 95 | strcpy(cwd,"unknown"); 96 | }//if 97 | char cwdcopy[100]; 98 | strcpy(cwdcopy,cwd); 99 | char *first = strtok(cwdcopy,delims); 100 | char *second = strtok(NULL,delims); 101 | //if at home 102 | if(!(strcmp(first,"home")) && !(strcmp(second,pwp->pw_name))){ 103 | int offset = strlen(first) + strlen(second)+2; 104 | char newcwd[100]; 105 | char *p = cwd; 106 | char *q = newcwd; 107 | 108 | p += offset; 109 | while(*(q++) = *(p++)); 110 | char tmp[100]; 111 | strcpy(tmp,"~"); 112 | strcat(tmp,newcwd); 113 | strcpy(cwd,tmp); 114 | } 115 | 116 | if(getuid() == 0)//if super 117 | super = '#'; 118 | else 119 | super = '$'; 120 | sprintf(prompt, "\001\e[1;32m\002%s@%s\001\e[0m\002:\001\e[1;31m\002%s\001\e[0m\002%c",pwp->pw_name,hostname,cwd,super); 121 | 122 | } 123 | 124 | //analysis command that user input 125 | int analysis_command(){ 126 | int i = 1; 127 | char *p; 128 | //to cut the cwd by " " 129 | char delims[] = " "; 130 | argc = 1; 131 | 132 | strcpy(argv[0],strtok(command,delims)); 133 | while(p = strtok(NULL,delims)){ 134 | strcpy(argv[i++],p); 135 | argc++; 136 | }//while 137 | 138 | if(!(strcmp(argv[0],"exit"))||!(strcmp(argv[0],"help"))|| !(strcmp(argv[0],"cd"))){ 139 | BUILTIN_COMMAND = 1; 140 | } 141 | int j; 142 | //is a pipe command ? 143 | int pipe_location; 144 | for(j = 0;j < argc;j++){ 145 | if(strcmp(argv[j],"|") == 0){ 146 | PIPE_COMMAND = 1; 147 | pipe_location = j; 148 | break; 149 | } 150 | }//for 151 | 152 | //is a redirect command ? 153 | int redirect_location; 154 | for(j = 0;j < argc;j++){ 155 | if(strcmp(argv[j],">") == 0){ 156 | REDIRECT_COMMAND = 1; 157 | redirect_location = j; 158 | break; 159 | } 160 | }//for 161 | 162 | if(PIPE_COMMAND){ 163 | //command 1 164 | argvtmp1 = malloc(sizeof(char *)*pipe_location + 1); 165 | int i; 166 | for(i = 0;i < pipe_location + 1;i++){ 167 | argvtmp1[i] = malloc(sizeof(char)*100); 168 | if(i <= pipe_location) 169 | strcpy(argvtmp1[i],argv[i]); 170 | }//for 171 | argvtmp1[pipe_location] = NULL; 172 | 173 | //command 2 174 | argvtmp2 = malloc(sizeof(char *)*(argc - pipe_location)); 175 | int j; 176 | for(j = 0;j < argc - pipe_location;j++){ 177 | argvtmp2[j] = malloc(sizeof(char)*100); 178 | if(j <= pipe_location) 179 | strcpy(argvtmp2[j],argv[pipe_location + 1 + j]); 180 | }//for 181 | argvtmp2[argc - pipe_location - 1] = NULL; 182 | 183 | }//if pipe_command 184 | 185 | else if(REDIRECT_COMMAND){ 186 | strcpy(argv_redirect,argv[redirect_location + 1]); 187 | argvtmp1 = malloc(sizeof(char *)*redirect_location + 1); 188 | int i; 189 | for(i = 0;i < redirect_location + 1;i++){ 190 | argvtmp1[i] = malloc(sizeof(char)*100); 191 | if(i < redirect_location) 192 | strcpy(argvtmp1[i],argv[i]); 193 | }//for 194 | argvtmp1[redirect_location] = NULL; 195 | }//redirect command 196 | 197 | else{ 198 | argvtmp1 = malloc(sizeof(char *)*argc+1); 199 | int i; 200 | for(i = 0;i < argc + 1;i++){ 201 | argvtmp1[i] = malloc(sizeof(char)*100); 202 | if(i < argc) 203 | strcpy(argvtmp1[i],argv[i]); 204 | }//for 205 | argvtmp1[argc] = NULL; 206 | } 207 | 208 | 209 | #ifdef DEBUG 210 | //test the analysis 211 | if(BUILTIN_COMMAND){ 212 | printf("\tthis is a builtin command: %s\n",argv[0]); 213 | } 214 | else if(PIPE_COMMAND){ 215 | printf("\tthis is a pipe command:\n"); 216 | printf("\t==command 1:\n"); 217 | int k; 218 | for(k = 0;k < pipe_location + 1;k++){ 219 | printf("\t%d: %s\n",k,argvtmp1[k]); 220 | }//for 221 | printf("\t==command 2:\n"); 222 | for(k = 0;k < argc - pipe_location;k++){ 223 | printf("\t%d: %s\n",k,argvtmp2[k]); 224 | }//for 225 | } 226 | else if(REDIRECT_COMMAND){ 227 | printf("\tthis is a redirect command:\n"); 228 | printf("\t==command:\n"); 229 | int k; 230 | for(k = 0;k < pipe_location + 1;k++){ 231 | printf("\t%d: %s\n",k,argvtmp1[k]); 232 | }//for 233 | printf("redirect target: %s\n",argv_redirect); 234 | } 235 | else{ 236 | printf("\n\tthe command is:%s with %d parameter(s):\n",argv[0],argc); 237 | printf("0(command): %s\n",argv[0]); 238 | int k; 239 | for(k = 1;k < argc;k++){ 240 | printf("%d: %s\n",k,argv[k]); 241 | }//for 242 | } 243 | 244 | #endif 245 | 246 | return 0; 247 | } 248 | 249 | void builtin_command(){ 250 | struct passwd* pwp; 251 | //exit when command is exit 252 | if(strcmp(argv[0],"exit") == 0){ 253 | exit(EXIT_SUCCESS); 254 | } 255 | else if(strcmp(argv[0],"help") == 0){ 256 | help(); 257 | }//else if 258 | 259 | else if(strcmp(argv[0],"cd") == 0){ 260 | char cd_path[100]; 261 | if((strlen(argv[1])) == 0 ){ 262 | pwp = getpwuid(getuid()); 263 | sprintf(cd_path,"/home/%s",pwp->pw_name); 264 | strcpy(argv[1],cd_path); 265 | argc++; 266 | } 267 | else if((strcmp(argv[1],"~") == 0) ){ 268 | pwp = getpwuid(getuid()); 269 | sprintf(cd_path,"/home/%s",pwp->pw_name); 270 | strcpy(argv[1],cd_path); 271 | } 272 | 273 | //do cd 274 | #ifdef DEBUG 275 | printf("cdpath = %s \n",argv[1]); 276 | #endif 277 | if((chdir(argv[1]))< 0){ 278 | printf("cd failed in builtin_command()\n"); 279 | } 280 | }//else if cd 281 | } 282 | 283 | void do_command(){ 284 | //do_command 285 | 286 | if(PIPE_COMMAND){ 287 | int fd[2],res; 288 | int status; 289 | 290 | res = pipe(fd); 291 | 292 | if(res == -1) 293 | printf("pipe failed in do_command()\n"); 294 | pid_t pid1 = fork(); 295 | if(pid1 == -1){ 296 | printf("fork failed in do_command()\n"); 297 | }//if 298 | else if(pid1 == 0){ 299 | dup2(fd[1],1);//dup the stdout 300 | close(fd[0]);//close the read edge 301 | if(execvp(argvtmp1[0],argvtmp1) < 0){ 302 | #ifdef DEBUG 303 | printf("execvp failed in do_command() !\n"); 304 | #endif 305 | printf("%s:command not found\n",argvtmp1[0]); 306 | }//if 307 | }//else if child pid1 308 | else{ 309 | waitpid(pid1,&status,0); 310 | pid_t pid2 = fork(); 311 | if(pid2 == -1){ 312 | printf("fork failed in do_command()\n"); 313 | }//if 314 | else if(pid2 == 0){ 315 | close(fd[1]);//close write edge 316 | dup2(fd[0],0);//dup the stdin 317 | if(execvp(argvtmp2[0],argvtmp2) < 0){ 318 | #ifdef DEBUG 319 | printf("execvp failed in do_command() !\n"); 320 | #endif 321 | printf("%s:command not found\n",argvtmp2[0]); 322 | }//if 323 | }//else if pid2 == 0 324 | else{ 325 | close(fd[0]); 326 | close(fd[1]); 327 | waitpid(pid2,&status,0); 328 | }//else 329 | }//else parent process 330 | }//if pipe command 331 | 332 | else if(REDIRECT_COMMAND){ 333 | pid_t pid = fork(); 334 | if(pid == -1){ 335 | printf("fork failed in do_command()\n"); 336 | }//if 337 | else if(pid == 0){ 338 | int redirect_flag = 0; 339 | FILE* fstream; 340 | fstream = fopen(argv_redirect,"w+"); 341 | freopen(argv_redirect,"w",stdout); 342 | if(execvp(argvtmp1[0],argvtmp1) < 0){ 343 | redirect_flag = 1;//execvp this redirect command failed 344 | }//if 345 | fclose(stdout); 346 | fclose(fstream); 347 | if(redirect_flag){ 348 | #ifdef DEBUG 349 | printf("execvp redirect command failed in do_command() !\n"); 350 | #endif 351 | printf("%s:command not found\n",argvtmp1[0]); 352 | }//redirect flag 353 | 354 | }//else if 355 | else{ 356 | int pidReturn = wait(NULL); 357 | }//else 358 | }//else if redirect command 359 | else{ 360 | pid_t pid = fork(); 361 | if(pid == -1){ 362 | printf("fork failed in do_command()\n"); 363 | }//if 364 | else if(pid == 0){ 365 | if(execvp(argvtmp1[0],argvtmp1) < 0){ 366 | #ifdef DEBUG 367 | printf("execvp failed in do_command() !\n"); 368 | #endif 369 | printf("%s:command not found\n",argvtmp1[0]); 370 | }//if 371 | }//else if 372 | else{ 373 | int pidReturn = wait(NULL); 374 | }//else 375 | }//else normal command 376 | 377 | free(argvtmp1); 378 | free(argvtmp2); 379 | } 380 | 381 | void help(){ 382 | char message[50] = "Hi,welcome to myShell!"; 383 | printf( 384 | "< %s >\n" 385 | "\t\t\\\n" 386 | "\t\t \\ \\_\\_ _/_/\n" 387 | "\t\t \\ \\__/\n" 388 | "\t\t \\ (oo)\\_______\n" 389 | "\t\t \\ (__)\\ )\\/\\\n" 390 | "\t\t ||----w |\n" 391 | "\t\t || ||\n",message); 392 | } 393 | 394 | void initial(){ 395 | int i = 0; 396 | for(i = 0;i < argc;i++){ 397 | strcpy(argv[i],"\0"); 398 | } 399 | argc = 0; 400 | BUILTIN_COMMAND = 0; 401 | PIPE_COMMAND = 0; 402 | REDIRECT_COMMAND = 0; 403 | } 404 | 405 | void init_lastdir(){ 406 | getcwd(lastdir, sizeof(lastdir)); 407 | } 408 | 409 | void history_setup(){ 410 | using_history(); 411 | stifle_history(50); 412 | read_history("/tmp/msh_history"); 413 | } 414 | 415 | void history_finish(){ 416 | append_history(history_length, "/tmp/msh_history"); 417 | history_truncate_file("/tmp/msh_history", history_max_entries); 418 | } 419 | 420 | void display_history_list(){ 421 | HIST_ENTRY** h = history_list(); 422 | if(h) { 423 | int i = 0; 424 | while(h[i]) { 425 | printf("%d: %s\n", i, h[i]->line); 426 | i++; 427 | } 428 | } 429 | } 430 | 431 | --------------------------------------------------------------------------------