類比Linux的shell,類比Linuxshell

來源:互聯網
上載者:User

類比Linux的shell,類比Linuxshell

在學習了Linux的進程式控制制之後,學習了fork函數和exec函數族,通過這些個函數可以簡單的實現一份shell,就是實現一份命令列解譯器,當然是簡單版的,實現功能如下

還不能實現Regex,要實現這個我當前的代碼根本不能用,要重頭開始改寫。。。

下面貼代碼

  1 #include <stdio.h>  2 #include <unistd.h>  3 #include <string.h>  4 #include <sys/types.h>  5 #include <sys/wait.h>  6 #include <stdlib.h>  7 #include <pwd.h>  8 #include <sys/utsname.h>  9 #include <libgen.h> 10  11  12 void eatblank(char **buf) 13 { 14   while(**buf==' ') 15   { 16     (*buf)++; 17   } 18 } 19  20  21 void GetHostName(char *hostname,int length) 22 { 23   gethostname(hostname,length); 24   char *p=hostname; 25   while(*p!='\0') 26   { 27     if(*p=='.') 28     { 29       *p='\0'; 30     } 31     p++; 32   } 33 } 34  35 void Pipe(char **my_argv,char *buf); 36 void BuildCommand(char **my_argv,char *buf) 37 { 38   eatblank(&buf); 39   my_argv[0]=buf; 40   int index=1; 41   char *p=buf; 42       while(*p!='\0') 43       { 44         if(*p==' ') 45         { 46           *p='\0'; 47           p++; 48           eatblank(&p) ; 49           if(*p!='|') 50           { 51             my_argv[index++]=p; 52           } 53           continue; 54         } 55         else if(*p=='|') 56         { 57           p++; 58           //p++; 59           my_argv[index]=NULL; 60           Pipe(my_argv,p); 61         } 62         else 63         { 64           p++; 65         } 66       } 67      my_argv[index]=NULL; 68 } 69  70  71  72 void Pipe(char ** my_argv,char *buf) 73 { 74   int fd[2]; 75   pipe(fd); 76   pid_t id2=fork(); 77   if(id2==0) 78   { 79     close(1); 80     dup(fd[1]); 81     close(fd[1]); 82     close(fd[0]); 83     execvp(my_argv[0],my_argv); 84   } 85   else 86   { 87     waitpid(id2,NULL,0); 88     close(0); 89     dup(fd[0]); 90     close(fd[0]); 91     close(fd[1]); 92     BuildCommand(my_argv,buf); 93     execvp(my_argv[0],my_argv); 94   } 95   //在此處添加exec族函數 96 } 97  98  99 int main()100 {101   while(1)102   {103     char *my_argv[64];104       struct passwd *pwd=getpwuid(getuid());105       char hostname[256]={'\0'};106       char cwd[256]={'\0'};107       getcwd(cwd,256);108       GetHostName(hostname,256);109       printf("[%s@%s %s]#",pwd->pw_name,hostname,basename(cwd));110       fflush(stdout);111       char buf[1024];112       buf[0]='\0';113 114       int count=read(0,buf,sizeof(buf));115       buf[count-1]='\0';116       my_argv[0]=buf;    117     pid_t id=fork();118     if(id==0)119     {120       //child121      122       if(strncmp(buf,"cd",2)==0) 123       {124         exit(1);125       }126       BuildCommand(my_argv,buf);127      execvp(my_argv[0],my_argv);128      printf("if the process has some problem ,I should run here\n");129      exit(0);130     }131     else132     {133       //father134       int status=0;135       wait(&status);136       if(status==256)137       {138         my_argv[0]+=3;139         chdir(my_argv[0]);140       }141     }142   }143   return 0;144 }

通過gethostname擷取主機名稱,通過getcwd獲得當前工作目錄,通過getpwuid獲得當前登入的使用者資訊

這樣命令提示字元就完成了;

  • 普通命令的實現

普通命令的實現並不困難,我的目的是讓子進程來執行命令,也就是通常的讓fork產生的子進程執行exec族函數,然後自己死掉,通過父進程回收資源,迴圈並建立新的子進程,這就是shell的大架構,其中用execvp函數來實現命令的執行,函數原型就不多說了,查手冊就能查到,簡單解釋一下參數,第一個參數是命令列的字串,第二是參數是一個字串數組,從上到下依次存放,命令,參數(可能有多個,一個參數佔一個下標),最後用NULL佔據一個下標表示結束。

  • cd命令的實現

cd命令的實現有些問題,不是普通命令的實現,就是說簡單的使用execvp是不能實現的,因為就運算元進程改變了目錄之後也會把自己殺死,父進程和子進程之間是不通的(就是說父進程和子進程並不共用環境變數,子進程修改了當前工作目錄的環境變數對父進程也沒有什麼影響),後來使用system來執行系統調用,也失敗,因為更多時候shell會產生一個子進程來執行命令,因為shell本身執行會有風險,可能會因為使用者的錯誤操作把自己掛掉,所以使用子進程來執行命令,而這樣和剛才的結果是一樣的並不會影響到父進程,最後採用了chdir函數,他可以改變當前進程的環境變數中的工作目錄(就是專門change dir用的),讓父進程來執行,fork出來的子進程會有一份父進程環境變數的拷貝,這就完成了改變目錄,並將結果傳遞了下來

 1  else 2     { 3       //father 4       int status=0; 5       wait(&status); 6       if(status==256) 7       { 8         my_argv[0]+=3; 9         chdir(my_argv[0]);10       }11     }

 

  • 管道符的實現

管道符的實現很簡單,平常我們執行命令的時候,都是結果自動輸出到電腦螢幕上,這說明一般命令的輸出是write在標準輸出stdout的,而我們輸出命令的參數是通過鍵盤,這說明命令的輸入來源是標準輸入stdin,如果我們關閉了,標準輸出和標準輸入,而是通過一個管道,讓結果寫進管道,然後讓參數從管道中讀取(簡單的說就是讓管道的兩段代替標準輸入和標準輸出),管道符就實現了。

 1 void Pipe(char ** my_argv,char *buf) 2 { 3   int fd[2]; 4   pipe(fd); 5   pid_t id2=fork(); 6   if(id2==0) 7   { 8     close(1); 9     dup(fd[1]);10     close(fd[1]);11     close(fd[0]);12     execvp(my_argv[0],my_argv);13   }14   else15   {16     waitpid(id2,NULL,0);17     close(0);18     dup(fd[0]);19     close(fd[0]);20     close(fd[1]);21     BuildCommand(my_argv,buf);22     execvp(my_argv[0],my_argv);23   }

 

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.