天天看點

程序控制-程序程式替換(exec函數簇)

1.系統調用exec系列

exec功能:将一個新程式裝入調用程序的記憶體空間,來改變調用程序的執行代碼,進而形成新程序。

如果exec調用成功,目前程序将被覆寫,然後開始執行新程式,并且不會傳回原程序,這樣就産生了一個新程序,但是它的程序辨別符與調用程序相同。這說明什麼?說明exec并沒有像fork()一樣建立一個與調用程序并發執行的新程序,而是用新程序取代了原來的程序。是以,exec調用成功後,沒有任何傳回資料。調用失敗傳回-1;

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

頭檔案: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 env

p[]);

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

不帶字母p(表⽰path)的exec函數 ,第⼀個參數必須是程式的相對路徑或絕對路徑,例如

“/bin/ls“或”./a.out”,⽽不能 是”ls”或”a.out”。對于帶字母p的函數,如果參數中包含/,則将其視為路徑名。否則視為不帶路徑的程式名,在PATH環境變量的⽬錄清單中搜尋這個程式。

帶有字母l(表⽰list)的exec函數,要求将新程式的每個指令⾏參數都當作⼀個參數傳給它,指令⾏ 參數的個數是可變的,是以函數原型中有…,…中的最後⼀個可變參數應該是NULL, 起sentinel的作⽤。

帶有字母v(表⽰vector)的函數,則應該先構造⼀個指向各參數的指針數 組,然後将該數組的⾸位址當作參數傳給它,數組中的最後⼀個指針也應該是NULL,就像main函數 的argv參數或者環境變量表⼀樣。

對于以e(表⽰environment)結尾的exec函數,可以把⼀份新的環境變量表傳給它,其他exec函數仍使⽤目前的環境變量表執⾏新程式。

運用執行個體:

char *const ps_argv[] ={"ps", "-o", "pid,ppid,pgrp,session,tpgid,comm", NULL};
char *const ps_envp[] ={"PATH=/bin:/usr/bin", "TERM=console", NULL}; execl("/bin/
ps", "ps", "-o", "pid,ppid,pgrp,session,tpgid,comm", NULL);
execv("/bin/ps", ps_argv);
execle("/bin/ps", "ps", "-o", "pid,ppid,pgrp,session,tpgid,comm", NULL, ps_envp);
execve("/bin/ps", ps_argv, ps_envp);
execlp("ps", "ps", "-o", "pid,ppid,pgrp,session,tpgid,comm", NULL); execvp("ps", ps_argv);
           
程式控制-程式程式替換(exec函數簇)

2.對exec傳送變量的通路

任何被 exec 調用所執行的程式,都可以通路 exec 調用中的參數。這些參數是調用 exec的程式傳送給它的。我們可以通過定義程式 main()函數的參數來使用這些參數,方法如下:main( int argc, char* argv[] );

這對于大多數人來說應該是熟悉的,這種方法就是 C 語言程式通路指令行參數的方法。這也顯示了 shell 本身就是使用 exec 啟動程序的。

執行個體:

test.c中,生成一個可執行檔案為test

#include <stdio.h>
main(int argc,char* argv[])
{
while(--argc>)
{
    printf("%s ",*(++argv));
    printf("\n");]
    }
}
           

fun.c中

#include<stdio.h>
#include<unistd.h>
int main()
{
    char* argin[]={"./test", "hello", "world", NULL};
    execvp(argin[],argin);
    exit();
}
           

執行fun後會列印出來

hello

world