1. 程式人生 > >實現mybash

實現mybash

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