實現mybash
阿新 • • 發佈:2018-11-25
stdin void || amp 偽代碼 passwd myba argv 分配
20165212實現mybash
要求
- 使用fork,exec,wait實現mybash
- 寫出偽代碼,產品代碼和測試代碼
- 發表知識理解,實現過程和問題解決的博客(包含代碼托管鏈接)
學習相關知識
fork函數
查看幫助文檔可以知道fork函數的頭文件,函數原型,以及函數的功能等,如下圖
- fork()函數通過系統調用創建一個與原來進程幾乎完全相同的進程,也就是兩個進程可以做完全相同的事,但如果初始參數或者傳入的變量不同,兩個進程也可以做不同的事。
- 一個進程調用fork()函數後,系統先給新的進程分配資源。
- fork調用一次,卻能夠返回兩次,它可能有三種不同的返回值。
- 在父進程中,fork返回新創建子進程的進程ID;
- 在子進程中,fork返回0;
- 如果出現錯誤,fork返回一個負值。
我們可以通過fork返回的值來判斷當前進程是子進程還是父進程。
源代碼:
#include <unistd.h> #include <stdio.h> int main () { pid_t fpid; //fpid表示fork函數返回的值 int count=0; fpid=fork(); if (fpid < 0) printf("error in fork!"); else if (fpid == 0) { printf("i am the child process, my process id is %d\n",getpid()); printf("我是子進程\n");// count++; } else { printf("i am the parent process, my process id is %d\n",getpid()); printf("我是父進程\n"); count++; } printf("統計結果是: %d\n",count); return 0; }
問題:為什麽count值沒有受到影響呢? 解決:因為在創建了新進程之後,所有變量都存在不同的地址中,不是共用的,所有各有各的增減變化,互不影響。
exec函數族
- exec函數族提供了一個在進程中啟動另一個程序執行的方法。 - 以根據指定的文件名或目錄名找到可執行文件,並用它來取代原調用進程的數據段、代碼段和堆棧段。 - 可執行文件既可以是二進制文件,也可以是Linux下任何可執行腳本文件。 - 在該函數族中使用execl、execv、execlp、execvp函數使執行碼重生時,Shell進程會將所有環境變量復制給生成的新進程;而使用execle、execve時新進程不繼承任何Shell進程的環境變量,而由envp[]數組自行設置環境變量。
ls源代碼
#include<unistd.h> main() { char *argv[ ]={"ls", NULL}; char *envp[ ]={"PATH=/bin", NULL}; execve("/bin/ls", argv, envp); }
運行結果
wait函數 wait()會暫時停止現在進程的執行,直到有信號來到或子進程結束。假如在調用wait()時子進程已結束,則wait()會立即返回子進程結束狀態值。 waitpid提供了一個 wait的非阻塞版本,有時希望取得一個子進程的狀態, 但不想進程阻塞。 mybash實現 偽代碼:
while(1) { 輸出用戶的ID,等數據; 用戶輸入命令; 將命令分割; 調用fork; 調用exec函數; }
源代碼:
#include <stdio.h> #include <stdlib.h> #include <unistd.h> #include <pwd.h> #include <sys/wait.h> #define N 100 #define order_length 128 #define order_num 64 #define empty 0 #define chars 1 void main() { while(1) { struct passwd *my_info; char path[N]; my_info = getpwuid(getuid()); getcwd(path, sizeof(path)); printf("[%s@%s]$ ", my_info->pw_name, path); char str[N]; char a[N]; char *argv[N]={NULL}; char *envp[]={0,NULL}; int i,j = 0, flag=1; fgets(str,N,stdin); str[N - 1] = ‘\0‘; if(feof(stdin)) { printf("error"); exit(0); } for(i=0;str[i]!=‘\0‘&&i<N&&j<N;i++) { if(str[i] == ‘ ‘ || str[i] == ‘\n‘) { flag=1; str[i] = ‘\0‘; } else if(flag==1) { argv[j++] = &str[i]; flag=0; } } if(fork() != 0) wait(NULL); else { execvp(argv[0], argv); perror("execlp error"); exit(0); } } }
實驗結果:
實驗感想
上課的時候認真看老師演示了fork函數和execute函數,登堂入室;課下參考了不少學長學姐的博客,進一步復習fork函數和execute,實現了mybash,課余時間我會繼續學習時間fork函數和execute函數,增加mybash的功能
實現mybash