Linux學習筆記14 ——execl

1,原型

前面我們提到,可以用fork創建一個子進程。但是,這個子進程與原先的父進程共享程序段。也就是說兩個進程執行的是同一段代碼。這好像並沒有太大的用處。正常來說,我們希望的不是創建的新進程可以執行完全不同的功能嗎?這要怎麼做呢?

這就要用到我們今天講的exec系列函數。

通常的做法是,先用fork起一個子進程,再調用execXXX函數將子進程替換成一個指定的程序。這樣狸貓換太子之後,新的程序就獲得了原先子進程的pid和父進程。完全頂包了原先的子進程。

exec系列共有7個函數。今天的例子以最簡單的execl爲例子。7個函數的原型如下:

#include<unistd.h>
int execl(const char* pathname, const char* arg0, ...); //arg以空指針結尾
int execv(const char* pathname, char* const argv[]);
int execle(const char* pathname,const char* arg0, ...);//arg以空指針結尾,再接環境變量
int execve(const char* pathname, char* const argv[], char* const envp[]);
int execlp(const char* filename, const char* arg0, ...); //arg以空指針結尾
int execvp(const char* filename, char* const argv[]);
int fexecve(int fd, char* const argv[], char* const envp[]);

返回值:出錯返回-1,成功不返回。

2,例子:

2.1 hello程序

先裝備好一個簡單的hello程序做狸貓,便於待會被exec用來換太子。

先新建一個hello.c:

#include <stdio.h>
#include <stdlib.h>
int main(int argc, char* argv[]){
    printf("Hello");
    if (argc > 0){
        printf(", %s!\n", argv[0]);
    } else {
        printf("\n");
    }
}

它只是簡單滴打印第一個輸入參數,並在前面加上一個hello而已。

將其編譯成hello,就放在當前目錄下。

 

2.2 入正題

有了狸貓,開始準備太子。在study_Linux.c下寫入以下代碼。

int main(){
    pid_t pid;
    //用fork產生一個與自己一模一樣的子進程
    if((pid = fork()) < 0) {
        printf("fork error!\n");
		exit(1); 
    } else if(pid == 0){ //注意,是在子進程內調用execl
        //將子進程替換成hello,並給hello傳遞輸入參數Bihan,注意最後一個輸入參數一定是NULL
        if(execl("./hello", "Bihan", NULL) < 0){
            printf("execle error!\n");
		    exit(1); 
        }
    } 
    
    printf("parent process\n");
    //這裏waitpid還能等到hello,說明hello的pid就是原先子進程的pid,
    //父進程就把hello當自己的子進程,狸貓換太子成功
    if(waitpid(pid, NULL, 0) < 0){
        printf("wait error!\n");
		exit(1); 
    }else{
        printf("wait end\n");
    }

    return 0;
}

執行結果:

➜  code ./study_linux                                       
parent process
Hello, Bihan!
wait end
 

可以看到hello被執行,輸入參數也被傳遞,最後hello終止時父進程還能wait到。

注意一個細節。通常,當我們在命令行裏調用hello的時候,比如這樣:

➜  code ./hello Bihan
則hello的main函數的argv[0]並不是Bihan,而是“./hello”,當前程序名。所以剛纔的執行效果是這樣的:

➜  code ./hello Bihan
Hello, ./hello!
 

而我們在exec中指定hello的輸入參數時,argv[0]就是“Bihan”,沒有當前程序名自動成爲argv[0]這一說法了。

3,7個exec之間的關係

注意:只有execve是系統調用,其他的只是庫函數。其他6個最終也是通過調用execve實現的。

這組函數的名字是有規律的:

  1. 除了最後一個,其他都以exec開頭;
  2. l代表list,表示狸貓的輸入參數要一個一個列出來;與之相對,v代表vector,表示狸貓的輸入參數是個數組;
  3. e代表environment,環境 變量,表示重新設定狸貓的環境變量而不使用當前的環境變量;
  4. p代表exec的第一個輸入參數不是路徑而是文件名,其會在環境變量path的指定下去尋找該文件名的文件,p代表path;
  5. 最後一個的f代表文件描述符。所以總結起來指定狸貓有文件名、路徑名、文件描述符三種方法。
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章