1. 使用fork,exec,wait實現mybash 2. 寫出僞代碼,產品代碼和測試代碼 3. 發表知識理解,實現過程和問題解決的博客(包含代碼託管連接)
fork()
函數:1. 一個進程,包括代碼、數據和分配給進程的資源。 2. fork() 函數經過系統調用建立一個與原來進程幾乎徹底相同的進程,也就是兩個進程能夠作徹底相同的事,但若是初始參數或者傳入的變量不一樣,兩個進程也能夠作不一樣的事。 3. 一個進程調用fork() 函數後,系統先給新的進程分配資源,例如存儲數據和代碼的空間。而後把原來的進程的全部值都複製到新的新進程中,只有少數值與原來的進程的值不一樣。至關於克隆了一個本身。
在fork函數執行完畢後,若是建立新進程成功,則出現兩個進程,一個是子進程,一個是父進程。 fork調用的一個奇妙之處就是它僅僅被調用一次,卻可以返回兩次,它可能有三種不一樣的返回值: 1)在父進程中,fork返回新建立子進程的進程ID; 2)在子進程中,fork返回0; 3)若是出現錯誤,fork返回一個負值; 咱們能夠經過fork返回的值來判斷當前進程是子進程仍是父進程
有以下代碼:git
#include <unistd.h> #include <stdio.h> int main(void) { int i=0; printf("i son/pa ppid pid fpid/n"); //ppid指當前進程的父進程pid //pid指當前進程的pid, //fpid指fork返回給當前進程的值 for(i=0;i<2;i++){ pid_t fpid=fork(); if(fpid==0) printf("%d child %4d %4d %4d/n",i,getppid(),getpid(),fpid); else printf("%d parent %4d %4d %4d/n",i,getppid(),getpid(),fpid); } return 0; }
運行結果以下:數組
分析:
第一次fork後,p3224(父進程)的變量爲i=0,fpid=3225(fork函數在父進程中返向子進程id)p3225(子進程)的變量爲i=0,fpid=0(fork函數在子進程中返回0)
第二步建立了兩個進程p3226,p3227,這兩個進程執行完printf函數後就結束了,由於這兩個進程沒法進入第三次循環,沒法fork,該執行return 0;了,其餘進程也是如此。bash
exec
函數:1. fork函數是用於建立一個子進程,該子進程幾乎是父進程的副本,而有時咱們但願子進程去執行另外的程序,exec函數族就提供了一個在進程中啓動另外一個程序執行的方法。 2. 它能夠根據指定的文件名或目錄名找到可執行文件,並用它來取代原調用進程的數據段、代碼段和堆棧段,在執行完以後,原調用進程的內容除了進程號外,其餘所有被新程序的內容替換了。 3. 這裏的可執行文件既能夠是二進制文件,也能夠是Linux下任何可執行腳本文件。
exec函數族使用注意點:
在使用exec函數族時,必定要加上錯誤判斷語句。由於exec很容易執行失敗,其中最多見的緣由有:
① 找不到文件或路徑,此時errno被設置爲ENOENT。
② 數組argv和envp忘記用NULL結束,此時errno被設置爲EFAULT。
③ 沒有對應可執行文件的運行權限,此時errno被設置爲EACCES。函數
在Linux中使用exec函數族主要有如下兩種狀況 :測試
若是一個進程想執行另外一個程序,那麼它就能夠調用fork函數新建一個進程,而後調用任何一個exec函數使子進程重生。 當進程認爲本身不能再爲系統和用戶作出任何貢獻時,就能夠調用任何exec 函數族讓本身重生。
execlp.c文件以下:ui
#include <stdio.h> #include <unistd.h> int main() { if(fork()==0){ if(execlp("/usr/bin/env","env",NULL)<0) { perror("execlp error!"); return -1 ; } } return 0 ; }
執行結果如圖:
3d
由執行結果看出,execlp函數使執行碼重生時繼承了Shell進程的全部環境變量,其餘三個不以e結尾的函數同理。code
wait()
函數:1. wait()會暫時中止目前進程的執行, 直到有信號來到或子進程結束. 2. 若是在調用wait()時子進程已經結束, 則wait()會當即返回子進程結束狀態值. 3. 子進程的結束狀態值會由參數status 返回, 而子進程的進程識別碼也會一快返回
部分代碼展現,所有代碼在碼雲裏blog
int main() { char cmdline[MAX]; while(1){ printf("bsetixx@besrixx-VirtualBox:~/XINAN/mybash/$ "); fgets(cmdline,MAX,stdin); if(feof(stdin)) { printf("error"); exit(0); } eval(cmdline); } } void eval(char *cmdline) { char *argv[MAX]; char buf[MAX]; int bg; pid_t pid; strcpy(buf,cmdline); bg = parseline(buf,argv); if(argv[0]==NULL) return; if(!builtin_command(argv)) { if((pid=fork()) == 0) { if(execvp(argv[0],argv) < 0) { printf("%s : Command not found.\n",argv[0]); exit(0); } } if(!bg){ int status; if(waitpid(-1,&status,0) < 0) printf("waitfg: waitpid error!"); } else printf("%d %s",pid, cmdline); return; } }
代碼提交截圖
代碼提交鏈接繼承