【Linux課程學習】:《簡易版shell實現和原理》 《哪些命令可以讓子進程執行,哪些命令讓shell執行(內鍵命令)?為什么?》

1.我們讓子進程執行cd ..命令的時候,為什么我們執行pwd命令的時候,還是和之前一樣,路徑沒有變化?

本質就是,我們更改的是子進程的環境變量pwd,沒有改變父進程的。當執行pwd時,這個進程的環境變量還是由父進程來的。而父進程的環境變量沒有改變,所以pwd出來的結果也沒有改變。

2.環境變量是由shell自己維護的。

3.在這個簡易版shell中,我們沒有維護這個環境變量,還是依靠系統的環境變量。當環境沒有修改,用的還是系統的環境變量,更改時才寫時拷貝。

4.echo命令也是內鍵命令,因為子進程不會繼承父進程的本地環境變量。所以要打印本地變量,只有由shell來做。

打印命令行提示符(PrintCommandLine):

啟動shell程序,就是創建-bash進程,本質就是一個進程。

首先看到命令行的提示符是這樣的:

包括: 1.用戶名。2.主機名。3.當前的路徑。4.命令行提示符。($)

【Linux課程學習】:《簡易版shell實現和原理》 《哪些命令可以讓子進程執行,哪些命令讓shell執行(內鍵命令)?為什么?》

1.USER和LOGNAME(用戶名):2.HOSTNAME和PWD:

通過環境變量獲取這些信息。

三個函數獲得用戶信息(GetLOGNAME),主機信息(GetHOSTNAME),當前路徑信息(GetPWD)。

通過String進行傳遞,如果要誰用c語言字符串,就通過c_str()進行獲得底層char

代碼語言:JavaScript代碼運行次數:0運行復制

  const size_t basesize=1024;    //獲取用戶名信息  string GetLOGNAME()  {      string log_name=getenv("LOGNAME");      return log_name.empty()?"None":log_name;  }    //獲取當前主機信息  string GetHSOTNAME()  {      string host_name=getenv("HOSTNAME");      return host_name.empty()?"None":host_name;  }    //獲取當前路徑信息  string GetPWD()  {          string pwd=getenv("PWD");          if(pwd.empty())              return "None";          string separator="/";          string sub_str=pwd.substr(pwd.find_last_of(separator)+1);          return sub_str;      }  //生成command_line字符串      string MakeCommandLine()                                                                                                                                                                                           {      //[kym@hcss-ecs-32c9 2024-11-26]$          char command_line[basesize];          snprintf(command_line,basesize,"[%s@%s %s]@",              GetLOGNAME().c_str(),                  GetHSOTNAME().c_str(),              GetPWD().c_str());        return command_line;  }    // //1.打印命令行提示符  void PrintCommandLine()  {      printf("%s",MakeCommandLine().c_str());      fflush(stdout);    }

獲取命令行信息(GetCommadLine)代碼語言:javascript代碼運行次數:0運行復制

bool  GetCommandLine(char command_buff[],size_t size){    char* result=fgets(command_buff,size,stdin);    if(result==NULL)        return false;    result[strlen(result)-1]=0;    return true;}

讀取失敗返回false,讀取成功把換行符覆蓋。

讀取時,處理換行符:

如果我們以一行來讀取字符串,那么最會就有換行符,換行符也會讀取進來。所以打印的時候,我們沒有加換行,也是來到了新的一行。

解決辦法:

在返回前,把n置為0。

代碼語言:javascript代碼運行次數:0運行復制

result[strlen(result)-1]=0;

解析命令行(ParseCommandLine)

通過strtok函數進行分解字符串。

【Linux課程學習】:《簡易版shell實現和原理》 《哪些命令可以讓子進程執行,哪些命令讓shell執行(內鍵命令)?為什么?》

代碼語言:javascript代碼運行次數:0運行復制

bool ParseCommandLine(char command_buff[],int len)    {        (void)len;        argc=0;     //初始化        memset(argv,0,sizeof(argv));            const char* sep=" ";            argv[argc++]=strtok(command_buff,sep);            while((bool)(argv[argc++]=strtok(nullptr,sep)));        argc--;            return false;    } 

sep表示分隔符,用來把字符串進行分解。但是在分解之前,我們需要把argc和argv進行初始化。每次執行新的命令。

strtok函數第一次調用的時候,str指向要分割的字符串。在后續的調用中傳NULL。因為strtok函數內部有靜態變量維護當前字符串的位置。


執行命令(ExecuteCommand)

通過子進程發生程序替換。當id==0,表示子進程。如果發生了程序替換,還執行了原來的exit,就表示發生錯誤。然后就是父進程子進程。

代碼語言:javascript代碼運行次數:0運行復制

bool ExecuteCommand()    {        pid_t id=fork();        if(id<0)            return false;        if(id==0)        {            execvp(argv[0],argv);            exit(1);        }        int status=0;        pid_t rid=waitpid(id,&status,0);        if(rid<0)        {            //等待失敗            }        else        {            return true;                                                                                                                                                                                                   }        return false;    }    

哪些命令可以讓子進程執行,哪些命令不能讓子進程執行?為什么

當執行cd命令時,為什么pwd沒有改變?

我們寫的超簡易版shell中,讓子進程去執行cd .. 。但是其他的進程不是由子進程產生的,不會繼承子進程的環境變量,還是去繼承父進程的環境變量。雖然在子進程中改了環境變量,但是沒有得到進程,所以不起作用。在真正的shell中,就是要去改變shell的環境變量。因為其他的進程都是bash的子進程。


通過getcwd獲取實時的cwd,通過putenv導入環境變量:代碼語言:javascript代碼運行次數:0運行復制

//獲取當前路徑信息string GetPWD(){    if(nullptr==getcwd(cwd,sizeof(cwd)))        return "None";    snprintf(pwdenv,sizeof(pwdenv),"PWD=%s",cwd);    //更新env    putenv(pwdenv);    return cwd;}
【Linux課程學習】:《簡易版shell實現和原理》 《哪些命令可以讓子進程執行,哪些命令讓shell執行(內鍵命令)?為什么?》

myshell維護自己的環境變量:

環境變量和本地變量是存在于shell中的一個表。這兩張表就是全局的char*數組。指向很多的字符串。后序我們碰見要導入環境變量的命令,我們直接在shell中的genv數組指向一個空間,然后把第一個為空的數組指向這個字符串。

為什么要新申請空間,然后拷貝,再指向?

因為我們每執行一個命令,argv都是會變化的。如果我們直接讓genv的元素指向argv的元素,以后會發生變化。這樣環境變量就找不到了。

? 版權聲明
THE END
喜歡就支持一下吧
點贊7 分享