1. 程式人生 > >Linux下程序程式替換及簡單的shell的實現

Linux下程序程式替換及簡單的shell的實現

替換原理:

用fork建立程序後執行的是和父程序相同的程式(但有可能執行不同的程式碼分支),子程序往往要呼叫exec函式以執行另一個程式。當程序呼叫一種exec函式時,該程序的使用者空間程式碼和資料完全被新程式替換。從新程序的啟動例程開始執行,呼叫exec函式並不建立新程序,所以呼叫exec函式前後程序的id並未改變。

替換函式:

有六種以exec開頭的函式,統稱exec函式:

#include<unistd.h>

int execl(const char*path,const char*arg)

int execlp(const char*file,const char*arg)

int execle(const char*path,const char*arg,...,char const envp[])

int execv(const char*path,char *const argv[])

int execvp(const char*file,char*const argv[])

int execve(const char*path,char* const argv[],char*const envp[])

這些函式如果呼叫成功則載入新的程式從啟動程式碼開始執行,不再返回。

如果調用出錯則返回-1。

所以exec函式只有出錯的返回值而沒有成功的返回值。

這些函式原型看起來很容易混淆,但只要掌握了規律就很好記。

l(list):表示引數採用列表

v(vector):引數用陣列

p(path):有p自動搜素環境變數path

e(env):表示自己維護的環境變數

事實上只有execve是真正的系統呼叫,其他幾個函式最終都呼叫execve函式。

下面使用exec函式來實現一個簡單的shell

直接上程式碼

  1 //模擬shell寫一個咱們自己的微型shell
  2 //功能:myshell>ls
  3 //能夠執行各種命令
  4 #include<stdio.h>
  5 #include<unistd.h>
  6 #include<stdlib.h>
  7 #include<errno.h>
  8 #include<string.h>
  9 //1.獲取終端輸入
 10 //2.解析輸入(按空格解析到一個一個的命令引數)
 11 //3.建立一個子程序
 12 //          在子程序中經行程式替換,讓子程序執行命令
 13 //4.等待子程序執行完畢,收屍,獲取退出狀態碼
 14 int argc;
 15 char* argv[32];
 16 int param_parse(char *buff)
 17 {   
 18     if(buff==NULL)
 19     {   
 20         return -1;
 21     }
 22     char*ptr=buff;
 23     char*tmp=ptr;
 24     while((*ptr)!='\0')
 25     {   
 26         //當遇到空格,並且下一個位置不是空格的時候
 27         //將空格位置置‘\0’
 28         //不過我們將使用argv[argc]來儲存這個字串的位置
 29         if(*ptr==' '&&*(ptr+1)!=' ')
 30         {   
 31             *ptr='\0';
 32             argv[argc]=tmp;
 33             tmp=ptr+1;
 34             argc++;
 35         }
 36         ptr++;
 37     }
 38     argv[argc++]=tmp;
 39     argv[argc]=NULL;
 40 }
 41 int exec_cmd()
 42 {
 43     int pid=0;
 44     pid=fork();
 45     if(pid<0)
 46     {
 47         return -1;
 48     }
 49     else if(pid==0)
 50     {
 51         execvp(argv[0],argv);
 52         exit(0);
 53     }
 54     //父程序在這裡必須等待子程序退出,來看看子程序為什麼退出了
 55     //是不是出現了什麼錯誤,通過獲取狀態嗎,並且轉換一下退出碼所
 56     //對應的錯誤資訊進行列印
 57     int statu;
 58     wait(&statu);
 59     //判斷子程序是否是程式碼執行完畢退出
 60     if(WIFEXITED(statu))
 61     {
 62         //獲取子程序的退出碼,轉換為文字資訊列印
 63         printf("%s",strerror(WEXITSTATUS(statu)));
 64     }
 65     return 0;
 66 }
 67 int main()
 68 {
 69     while(1)
 70     {
 71         printf("myshell>");
 72         char buff[1024]={0};
 73         //%[^\n]獲取資料直到遇到\n為止
 74         //%*c   清空緩衝區,資料都不要了
 75         scanf("%[^\n]%*c",buff);
 76        // printf("%s\n",buff);
 77         param_parse(buff);
 78         exec_cmd();
 79     }
 80 
 81 }