exec族函數函數的作用:
我們用fork函數建立新程序後,經常會在新程序中調用exec函數去執行另外一個程式。
當程序調用exec函數時,該程序被完全替換為新程式。
因為調用exec函數并不建立新程序。
(簡單說就是,在執行一個主程式跑到一半的時候,可以調用另一個程式執行,原程式就不執行了)
exec族函數
功能:
在調用程序内部執行一個可執行檔案。可執行檔案既可以是二進制檔案,也可以是任何Linux下可執行的腳本檔案。
函數族:
exec函數族分别是:execl, execlp, execle, execv, execvp, execvpe
函數原型:
#include <unistd.h>
extern char **environ;
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 execvpe(const char *file, char *const argv[],char *const envp[]);//不常見,對環境變量修改
傳回值:
exec函數族的函數執行成功後不會傳回,調用失敗時,會設定errno并傳回-1,然後從原程式的調用點接着往下執行。 可以調用perror()函數傳回報錯原因
參數說明:
path:可執行檔案的路徑名字
arg:可執行程式所帶的參數,第一個參數為可執行檔案名字,沒有帶路徑且arg必須以NULL結束
file:如果參數file中包含/,則就将其視為路徑名,否則就按 PATH環境變量,在它所指定的各目錄中搜尋可執行檔案。
exec族函數參數極難記憶和分辨,函數名中的字元會給我們一些幫助:
l : 使用參數清單
p:使用檔案名,并從PATH環境進行尋找可執行檔案
v:應先構造一個指向各參數的指針數組,然後将該數組的位址作為這些函數的參數。
e:多了envp[]數組,使用新的環境變量代替調用程序的環境變量
一、帶l的一類exac函數(l表示list),包括execl、execlp、execle,要求将新程式的每個指令行參數都說明為 一個單獨的參數。這種參數表以空指針結尾。
以execl函數為例子來說明:
//檔案execl.c//gcc編譯成execl
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
//函數原型:int execl(const char *path, const char *arg, ...);
int main(void)
{
printf("before execl\n");
if(execl("./bin/echoarg","echoarg","abc",NULL) == -1)
{
printf("execl failed!\n");
}
printf("after execl\n");
return 0;
}
//檔案echoarg.c//gcc編譯成echoarg檔案
#include <stdio.h>
int main(int argc,char *argv[])
{
int i = 0;
for(i = 0; i < argc; i++)
{
printf("argv[%d]: %s\n",i,argv[i]);
}
return 0;
}
運作結果:
ubuntu:~/test/exec_test$ ./execl
before execl
argv[0]: echoarg
argv[1]: abc
我們先用gcc編譯echoarg.c,生成可執行檔案echoarg并放在目前路徑bin目錄下。檔案echoarg的作用是列印指令行參數。然後再編譯execl.c并執行execl可執行檔案。用execl 找到并執行echoarg,将目前程序main替換掉,是以”after execl” 沒有在終端被列印出來。
二、帶p的一類exac函數,包括execlp、execvp、execvpe,如果參數file中包含/,則就将其視為路徑名,否則就按 PATH環境變量,在它所指定的各目錄中搜尋可執行檔案。舉個例子,PATH=/bin:/usr/bin
//檔案execlp.c
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
//函數原型:int execlp(const char *file, const char *arg, ...);
int main(void)
{
printf("before execlp\n");
if(execlp("ps","ps","-l",NULL) == -1)//execlp與execl的差別就是execlp可以不加具體路徑,按PATH環境變量指定的目錄搜尋到ps檔案
{
printf("execlp failed!\n");
}
printf("after execlp*****\n");
return 0;
}
運作結果:
ubuntu:~/test/exec_test$ gcc execlp.c -o execlp
ubuntu:~/test/exec_test$ ./execlp
before execlp
F S UID PID PPID C PRI NI ADDR SZ WCHAN TTY TIME CMD
0 R 1048 35976 74920 0 80 0 - 2860 - pts/4 00:00:00 ps
0 S 1048 74920 74916 0 80 0 - 7579 wait pts/4 00:00:00 bash
三、帶v不帶l的一類exac函數,包括execv、execvp、execve,應先構造一個指向各參數的指針數組,然後将該數組的位址作為這些函數的參數。
如char *arg[]這種形式,且arg最後一個元素必須是NULL,例如char *arg[] = {“ls”,”-l”,NULL};
下面以execvp函數為例說明:
//檔案execvp.c
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
//函數原型:int execvp(const char *file, char *const argv[]);
int main(void)
{
printf("before execlp\n");
char *argv[] = {"ps","-l",NULL};
if(execvp("ps",argv) == -1)
{
printf("execvp failed!\n");
}
printf("after execlp*****\n");
return 0;
}
運作結果:
ubuntu:~/test/exec_test$ gcc execvp.c -o execvp
ubuntu:~/test/exec_test$ ./execvp
before execlp****
F S UID PID PPID C PRI NI ADDR SZ WCHAN TTY TIME CMD
0 R 1048 63491 74920 0 80 0 - 2860 - pts/4 00:00:00 ps
0 S 1048 74920 74916 0 80 0 - 7579 wait pts/4 00:00:00 bash
四、帶e的一類exac函數,包括execle、execvpe,可以傳遞一個指向環境字元串指針數組的指針。 參數例如char env_init[] = {“AA=aa”,”BB=bb”,NULL}; 帶e表示該函數取envp[]數組,而不使用目前環境。
下面以execle函數為例:
//檔案execle.c
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
//函數原型:int execle(const char *path, const char *arg,..., char * const envp[]);
char *env_init[] = {"AA=aa","BB=bb",NULL};
int main(void)
{
printf("before execle\n");
if(execle("./bin/echoenv","echoenv",NULL,env_init) == -1)
{
printf("execle failed!\n");
}
printf("after execle*****\n");
return 0;
}
//檔案echoenv.c
#include <stdio.h>
#include <unistd.h>
extern char** environ;
int main(int argc , char *argv[])
{
int i;
char **ptr;
for(ptr = environ;*ptr != 0; ptr++)
printf("%s\n",*ptr);
return 0;
}
運作結果:
ubuntu:~/test/exec_test$ gcc execle.c -o execle
ubuntu:~/test/exec_test$ ./execle
before execle
AA=aa
BB=bb
我們先寫一個顯示全部環境表的程式,命名為echoenv.c,然後編譯成可執行檔案放到./bin目錄下。然後再運作可執行檔案execle,發現我們設定的環境變量确實有傳進來。
推薦原文學習參考連接配接
exec函數配合fork函數使用
#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <string.h>
#include <stdlib.h>
int main()
{
pid_t pid;
int data = 0;
while(1){
printf("input your data\n");
scanf("%d", &data);
if(data == 1){ //輸入1,建立程序
pid = fork(); //建立程序
if(pid > 0){ //父程序等待子程序
wait(NULL);
}else if(pid == 0){ //子程序執行execl函數,運作另一個程式檔案,運作完傳回本程式
exexl("./bin/echoarg","echoarg","abc",NULL);
}
}else{
printf("do nothing\n");
}
}
return 0;
}
//檔案echoarg.c//gcc編譯成echoarg檔案
#include <stdio.h>
int main(int argc,char *argv[])
{
int i = 0;
for(i = 0; i < argc; i++)
{
printf("argv[%d]: %s\n",i,argv[i]);
}
return 0;
}