├── Assignment4.pdf ├── README.md └── shell.c /Assignment4.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kalpishs/Unix-Shell-Implementation-in-C/1a91600608174c0faaa72229bf57b70fe674c641/Assignment4.pdf -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | =========================================================================================================================== 2 | UNIX SHELL IMPLEMENTATION IN C 3 | =========================================================================================================================== 4 | This program simulates the working of command line interface in Unix-like environment. Implemented Functionalities are as under: 5 | 6 | 1. Execute all the External commands (ls, clear, vi etc.) 7 | 8 | 2. Implement Internal commands: cd, pwd 9 | 10 | 3. Initialize and use environment variables 11 | 12 | 4. Print environment variables using echo command 13 | 14 | 5. Redirection operators: STDIN, STDOUT, STDERR (>>,>,<<,<,2>) 15 | 16 | 6. Support for history command and '!' operator (history, !!, !-1, !10,!-10 etc) 17 | 18 | 7. Pipes “|” (multiple) (Ex: ls | grep 'a' | wc) 19 | 20 | 21 | =========================================================================================================================== 22 | Input/Output Format 23 | =========================================================================================================================== 24 | 25 | Input from the 'stdin' in an infinite loop till an “exit” is entered. 26 | The corresponding output should be printed to 'stdout'. 27 | 28 | Ex: 29 | assume that PWD==home/user 30 | 31 | Shell name: My_Shell 32 | 33 | bash prompt:~$ ./a.out 34 | 35 | My_Shell:/home/user$ ls 36 | 37 | shell.c history.txt a.out 38 | 39 | My_Shell:/home/user$ gfhj 40 | 41 | gfhj: command not found 42 | 43 | My_Shell:/home/user$ exit 44 | 45 | Bye... 46 | 47 | bash prompt:~$ 48 | 49 | 50 | =========================================================================================================================== 51 | Implementation Details 52 | =========================================================================================================================== 53 | 54 | The shell.c contains the main function which takes the input from user and checks it for pipeline. If pipeline exist it processes the data separately else it passes the data to the functions. 55 | 56 | int with_pipe_execute(): 57 | This function is the initial function which is called for checking the all the command after initial preprocessing . It passes the processed output to function split 58 | 59 | int split(char *cmd_exec, int input, int first, int last): 60 | 61 | This function is responsible for splitting of command and passing it to command function 62 | 63 | 64 | static int command(int input, int first, int last, char *cmd_exec): 65 | 66 | this does the major part of the program. It checks for various possibilities of commands. The types of commands that are checked are as under: 67 | 68 | 1) Internal commands: pwd and cd 69 | 70 | 2) echo commands, setting and getting environment variables 71 | 72 | 3) redirection handler 73 | 74 | 4) PIPE 75 | 76 | 5) External commands 77 | 78 | it make use of various funtions like tokenise_redirect_input_output,tokenise_redirect_input,tokenise_redirect_output which internally calls tokenise_commands() for tokenization 79 | 80 | 81 | Helper functions: 82 | getcwd(): 83 | 84 | gets the current woring Directory 85 | 86 | signal(): 87 | 88 | Handle Interrupt Signal 89 | 90 | void prompt(): 91 | 92 | initiates new Promt 93 | 94 | 95 | -------------------------------------------------------------------------------- /shell.c: -------------------------------------------------------------------------------- 1 | /* 2 | Name : Kalpish Singhal 3 | ****************************************************************************** 4 | FUNCTIONALITIES IMPLEMENTED- 5 | 1. Execute all the External commands (ls, clear, vi etc.) 6 | 2. Implement Internal commands: cd, pwd 7 | 3. Print Initialize and use environment variables 8 | 4. Print environment variables using echo command 9 | 5. I/O redirection (<, >) 10 | 6. Support for history command and '!' operator (history, !!, !-1, !10,!-10 etc) 11 | 7. Pipes “|” (multiple) (Ex: ls | grep 'a' | wc) 12 | 8.Handle Interrupt Signal: On pressing "Ctrl+C", the command that is running 13 | currently should be terminated, your program should not terminate. 14 | 15 | ******************************************************************************** 16 | */ 17 | 18 | #include 19 | #include 20 | #include 21 | #include 22 | #include 23 | #include 24 | #include 25 | #include 26 | 27 | /*GLOBAL VARIABLES*/ 28 | int pipe_count=0, fd; 29 | static char* args[512]; 30 | char *history_file; 31 | char input_buffer[1024]; 32 | char *cmd_exec[100]; 33 | int flag, len; 34 | char cwd[1024]; 35 | int flag_pipe=1; 36 | pid_t pid; 37 | int no_of_lines; 38 | int environmment_flag; 39 | int flag_pipe, flag_without_pipe, output_redirection, input_redirection; 40 | int bang_flag; 41 | int pid, status; 42 | char history_data[1000][1000]; 43 | char current_directory[1000]; 44 | char ret_file[3000]; 45 | char his_var[2000]; 46 | char *input_redirection_file; 47 | char *output_redirection_file; 48 | extern char** environ; 49 | 50 | /***************************Header Files Used*****************************/ 51 | void clear_variables(); 52 | void fileprocess (); 53 | void filewrite(); 54 | void bang_execute(); 55 | void environmment(); 56 | void set_environment_variables(); 57 | void change_directory(); 58 | void parent_directory(); 59 | void echo_calling(char *echo_val); 60 | void history_execute_with_constants(); 61 | static char* skipwhite(char* s); 62 | void tokenise_commands(char *com_exec); 63 | void tokenise_redirect_input_output(char *cmd_exec); 64 | void tokenise_redirect_input(char *cmd_exec); 65 | void tokenise_redirect_output(char *cmd_exec); 66 | char* skipcomma(char* str); 67 | static int split(char *cmd_exec, int, int, int); 68 | void with_pipe_execute(); 69 | static int command(int, int, int, char *cmd_exec); 70 | void prompt(); 71 | void sigintHandler(int sig_num); 72 | 73 | /*************************************************************************/ 74 | void sigintHandler(int sig_num) 75 | { 76 | signal(SIGINT, sigintHandler); 77 | fflush(stdout); 78 | } 79 | void clear_variables() 80 | { 81 | fd =0; 82 | flag=0; 83 | len=0; 84 | no_of_lines=0; 85 | pipe_count=0; 86 | flag_pipe=0; 87 | flag_without_pipe=0; 88 | output_redirection=0; 89 | input_redirection=0; 90 | input_buffer[0]='\0'; 91 | cwd[0] = '\0'; 92 | pid=0; 93 | environmment_flag=0; 94 | bang_flag=0; 95 | } 96 | 97 | void fileprocess () 98 | { 99 | int fd; 100 | history_file=(char *)malloc(100*sizeof(char)); 101 | strcpy(history_file,current_directory); 102 | strcat(history_file, "/"); 103 | strcat(history_file, "history.txt"); 104 | fd=open(history_file, O_RDONLY|O_CREAT,S_IRUSR|S_IWUSR); 105 | int bytes_read=0, i=0, x=0, index=0; 106 | char buffer[1], temp_data[1000]; 107 | do 108 | { 109 | bytes_read = read (fd, buffer, sizeof (buffer)); 110 | for (i=0; ino_of_lines) 351 | { 352 | for(i=0; i"))!=NULL) 383 | m++; 384 | io_token[1]=skipwhite(io_token[1]); 385 | io_token[2]=skipwhite(io_token[2]); 386 | input_redirection_file=strdup(io_token[1]); 387 | output_redirection_file=strdup(io_token[2]); 388 | tokenise_commands(io_token[0]); 389 | 390 | } 391 | void tokenise_redirect_input(char *cmd_exec) 392 | { 393 | char *i_token[100]; 394 | char *new_cmd_exec1; 395 | new_cmd_exec1=strdup(cmd_exec); 396 | int m=1; 397 | i_token[0]=strtok(new_cmd_exec1,"<"); 398 | while((i_token[m]=strtok(NULL,"<"))!=NULL) 399 | m++; 400 | i_token[1]=skipwhite(i_token[1]); 401 | input_redirection_file=strdup(i_token[1]); 402 | tokenise_commands(i_token[0]); 403 | } 404 | void tokenise_redirect_output(char *cmd_exec) 405 | { 406 | char *o_token[100]; 407 | char *new_cmd_exec1; 408 | new_cmd_exec1=strdup(cmd_exec); 409 | int m=1; 410 | o_token[0]=strtok(new_cmd_exec1,">"); 411 | while((o_token[m]=strtok(NULL,">"))!=NULL) 412 | m++; 413 | o_token[1]=skipwhite(o_token[1]); 414 | output_redirection_file=strdup(o_token[1]); 415 | tokenise_commands(o_token[0]); 416 | 417 | } 418 | char* skipcomma(char* str) 419 | { 420 | int i=0, j=0; 421 | char temp[1000]; 422 | while(str[i++]!='\0') 423 | { 424 | if(str[i-1]!='"') 425 | temp[j++]=str[i-1]; 426 | } 427 | temp[j]='\0'; 428 | str = strdup(temp); 429 | 430 | return str; 431 | } 432 | static int split(char *cmd_exec, int input, int first, int last) 433 | { 434 | char *new_cmd_exec1; 435 | new_cmd_exec1=strdup(cmd_exec); 436 | //else 437 | { 438 | int m=1; 439 | args[0]=strtok(cmd_exec," "); 440 | while((args[m]=strtok(NULL," "))!=NULL) 441 | m++; 442 | args[m]=NULL; 443 | if (args[0] != NULL) 444 | { 445 | 446 | if (strcmp(args[0], "exit") == 0) 447 | exit(0); 448 | if (strcmp(args[0], "echo") != 0) 449 | { 450 | cmd_exec = skipcomma(new_cmd_exec1); 451 | int m=1; 452 | args[0]=strtok(cmd_exec," "); 453 | while((args[m]=strtok(NULL," "))!=NULL) 454 | m++; 455 | args[m]=NULL; 456 | 457 | } 458 | if(strcmp("cd",args[0])==0) 459 | { 460 | change_directory(); 461 | return 1; 462 | } 463 | else if(strcmp("pwd",args[0])==0) 464 | { 465 | parent_directory(); 466 | return 1; 467 | } 468 | 469 | } 470 | } 471 | return command(input, first, last, new_cmd_exec1); 472 | } 473 | 474 | 475 | void with_pipe_execute() 476 | { 477 | 478 | int i, n=1, input, first; 479 | 480 | input=0; 481 | first= 1; 482 | 483 | cmd_exec[0]=strtok(input_buffer,"|"); 484 | 485 | while ((cmd_exec[n]=strtok(NULL,"|"))!=NULL) 486 | n++; 487 | cmd_exec[n]=NULL; 488 | pipe_count=n-1; 489 | for(i=0; i')) 526 | { 527 | input_redirection=1; 528 | output_redirection=1; 529 | tokenise_redirect_input_output(cmd_exec); 530 | } 531 | else if (strchr(cmd_exec, '<')) 532 | { 533 | input_redirection=1; 534 | tokenise_redirect_input(cmd_exec); 535 | } 536 | else if (strchr(cmd_exec, '>')) 537 | { 538 | output_redirection=1; 539 | tokenise_redirect_output(cmd_exec); 540 | } 541 | if(output_redirection == 1) 542 | { 543 | output_fd= creat(output_redirection_file, 0644); 544 | if (output_fd < 0) 545 | { 546 | fprintf(stderr, "Failed to open %s for writing\n", output_redirection_file); 547 | return(EXIT_FAILURE); 548 | } 549 | dup2(output_fd, 1); 550 | close(output_fd); 551 | output_redirection=0; 552 | } 553 | if(input_redirection == 1) 554 | { 555 | input_fd=open(input_redirection_file,O_RDONLY, 0); 556 | if (input_fd < 0) 557 | { 558 | fprintf(stderr, "Failed to open %s for reading\n", input_redirection_file); 559 | return(EXIT_FAILURE); 560 | } 561 | dup2(input_fd, 0); 562 | close(input_fd); 563 | input_redirection=0; 564 | } 565 | if (strcmp(args[0], "export") == 0) 566 | { 567 | set_environment_variables(); 568 | return 1; 569 | } 570 | if (strcmp(args[0], "echo") == 0) 571 | { 572 | echo_calling(cmd_exec); 573 | } 574 | else if (strcmp(args[0], "history") == 0) 575 | { 576 | history_execute_with_constants(); 577 | } 578 | 579 | else if(execvp(args[0], args)<0) printf("%s: command not found\n", args[0]); 580 | exit(0); 581 | } 582 | else 583 | { 584 | waitpid(pid, 0, 0); 585 | } 586 | 587 | if (last == 1) 588 | close(mypipefd[0]); 589 | if (input != 0) 590 | close(input); 591 | close(mypipefd[1]); 592 | return mypipefd[0]; 593 | 594 | } 595 | void prompt() 596 | { 597 | char shell[1000]; 598 | if (getcwd(cwd, sizeof(cwd)) != NULL) 599 | { 600 | strcpy(shell, "My_shell:"); 601 | strcat(shell, cwd); 602 | strcat(shell, "$ "); 603 | 604 | printf("%s", shell); 605 | } 606 | else 607 | perror("getcwd() error"); 608 | 609 | } 610 | 611 | int main() 612 | { 613 | int status; 614 | char ch[2]={"\n"}; 615 | getcwd(current_directory, sizeof(current_directory)); 616 | signal(SIGINT, sigintHandler); 617 | while (1) 618 | { 619 | clear_variables(); 620 | prompt(); 621 | fgets(input_buffer, 1024, stdin); 622 | if(strcmp(input_buffer, ch)==0) 623 | { 624 | continue; 625 | } 626 | if(input_buffer[0]!='!') 627 | { 628 | fileprocess(); 629 | filewrite(); 630 | } 631 | len = strlen(input_buffer); 632 | input_buffer[len-1]='\0'; 633 | strcpy(his_var, input_buffer); 634 | if(strcmp(input_buffer, "exit") == 0) 635 | { 636 | flag = 1; 637 | break; 638 | } 639 | if(input_buffer[0]=='!') 640 | { 641 | fileprocess(); 642 | bang_flag=1; 643 | bang_execute(); 644 | } 645 | with_pipe_execute(); 646 | waitpid(pid,&status,0); 647 | 648 | } 649 | if(flag==1) 650 | { 651 | printf("Bye...\n"); 652 | exit(0); 653 | return 0; 654 | } 655 | return 0; 656 | } 657 | --------------------------------------------------------------------------------