1.exec家族一共有六個函數,分別是:
(1)int execl(const char *path, const char *arg, ......);
(2)int execle(const char *path, const char *arg, ...... , char * const envp[]);
(3)int execv(const char *path, char *const argv[]);
(4)int execve(const char *filename, char *const argv[], char *const envp[]);
(5)int execvp(const char *file, char * const argv[]);
(6)int execlp(const char *file, const char *arg, ......);
其中只有execve是真正意義上的系統調用,其它都是在此基礎上經過包裝的庫函數。
exec函數族的作用是根據指定的文件名找到可執行文件,並用它來取代調用進程的內容,換句話說,就是在調用進程內部執行一個可執行文件。這里的可執行文件既可以是二進制文件,也可以是任何Linux下可執行的腳本文件。
與一般情況不同,exec函數族的函數執行成功后不會返回,因為調用進程的實體,包括代碼段,數據段和堆棧等都已經被新的內容取代,只留下進程ID等一些表面上的信息仍保持原樣,頗有些神似"三十六計"中的"金蟬脫殼"。看上去還是舊的軀殼,卻已經注入了新的靈魂。只有調用失敗了,它們才會返回一個-1,從原程序的調用點接着往下執行。
2.它們之間的區別:
1)前四個取路徑名做為參數,后兩個取文件名做為參數,如果文件名中不包含 “/” 則從PATH環境變量中搜尋可執行文件, 如果找到了一個可執行文件,但是該文件不是連接編輯程序產生的可執行代碼文件,則當做shell腳本處理。
2)前兩個和最后一個函數中都包括“ l ”這個字母 ,而另三個都包括“ v ”, " l "代表 list即表 ,而" v "代表 vector即矢量,也是是前三個函數的參數都是以list的形式給出的,但最后要加一個空指針,如果用常數0來表示空指針,則必須將它強行轉換成字符指針,否則有可能出錯。,而后三個都是以矢量的形式給出,即數組。
3)與向新程序傳遞環境變量有關,如第二個和第四個以e結尾的函數,可以向函數傳遞一個指向環境字符串指針數組的指針。即自個定義各個環境變量,而其它四個則使用進程中的環境變量。
3.實例:
(1)在平時的編程中,如果用到了exec函數族,一定記得要加錯誤判斷語句。先判斷execl的返回值,如果出錯,可以用perror( )函數打印出錯誤信息。
如:if (execl(“path”,”..””(char *)0) < 0)
{
perror(“execl error!”);
}
如果調用出錯,可輸出:execl error!: 錯誤原因 這樣可方便查找出錯原因
(2)注意下面書寫格式:
先定義一個指針數組:char *argv[]={“ls”,”-l”,(char *)0}
用execv調用ls: execv(“/bin/ls”,argv)
如果用execvp
execvp(“ls”,argv) //直接寫ls就可以了
注意:
execl調用shell 時,要在shell腳本中指明使用的shell版本:#!/bin/bash。在命令行下執行shell腳本,系統為它自動打開一個shell,在程序中沒有shell,在調用shell腳本時,會出錯,所以要在shell腳本中先打開shell。
(3)
1 #ifdef HAVE_CONFIG_H 2 #include <config.h> 3 #endif 4 5 #include <stdio.h> 6 #include <stdlib.h> 7 #include <unistd.h> 8 #include <string.h> 9 #include <errno.h> 10 11 int main(int argc, char *argv[]) 12 { 13 //以NULL結尾的字符串數組的指針,適合包含v的exec函數參數 14 char *arg[] = {"ls", "-a", NULL}; 15 16 /** 17 * 創建子進程並調用函數execl 18 * execl 中希望接收以逗號分隔的參數列表,並以NULL指針為結束標志 19 */ 20 if( fork() == 0 ) 21 { 22 // in clild 23 printf( "1------------execl------------\n" ); 24 if( execl( "/bin/ls", "ls","-a", NULL ) == -1 ) 25 { 26 perror( "execl error " ); 27 exit(1); 28 } 29 } 30 31 /** 32 *創建子進程並調用函數execv 33 *execv中希望接收一個以NULL結尾的字符串數組的指針 34 */ 35 if( fork() == 0 ) 36 { 37 // in child 38 printf("2------------execv------------\n"); 39 if( execv( "/bin/ls",arg) < 0) 40 { 41 perror("execv error "); 42 exit(1); 43 } 44 } 45 46 /** 47 *創建子進程並調用 execlp 48 *execlp中 49 *l希望接收以逗號分隔的參數列表,列表以NULL指針作為結束標志 50 *p是一個以NULL結尾的字符串數組指針,函數可以DOS的PATH變量查找子程序文件 51 */ 52 if( fork() == 0 ) 53 { 54 // in clhild 55 printf("3------------execlp------------\n"); 56 if( execlp( "ls", "ls", "-a", NULL ) < 0 ) 57 { 58 perror( "execlp error " ); 59 exit(1); 60 } 61 } 62 63 /** 64 *創建子里程並調用execvp 65 *v 望接收到一個以NULL結尾的字符串數組的指針 66 *p 是一個以NULL結尾的字符串數組指針,函數可以DOS的PATH變量查找子程序文件 67 */ 68 if( fork() == 0 ) 69 { 70 printf("4------------execvp------------\n"); 71 if( execvp( "ls", arg ) < 0 ) 72 { 73 perror( "execvp error " ); 74 exit( 1 ); 75 } 76 } 77 78 /** 79 *創建子進程並調用execle 80 *l 希望接收以逗號分隔的參數列表,列表以NULL指針作為結束標志 81 *e 函數傳遞指定參數envp,允許改變子進程的環境,無后綴e時,子進程使用當前程序的環境 82 */ 83 if( fork() == 0 ) 84 { 85 printf("5------------execle------------\n"); 86 if( execle("/bin/ls", "ls", "-a", NULL, NULL) == -1 ) 87 { 88 perror("execle error "); 89 exit(1); 90 } 91 } 92 93 /** 94 *創建子進程並調用execve 95 * v 希望接收到一個以NULL結尾的字符串數組的指針 96 * e 函數傳遞指定參數envp,允許改變子進程的環境,無后綴e時,子進程使用當前程序的環境 97 */ 98 if( fork() == 0 ) 99 { 100 printf("6------------execve-----------\n"); 101 if( execve( "/bin/ls", arg, NULL ) == 0) 102 { 103 perror("execve error "); 104 exit(1); 105 } 106 } 107 return EXIT_SUCCESS; 108 }
結果:
1 1------------execl------------ 2 . .. .deps exec exec.o .libs Makefile 3 2------------execv------------ 4 . .. .deps exec exec.o .libs Makefile 5 3------------execlp------------ 6 . .. .deps exec exec.o .libs Makefile 7 4------------execvp------------ 8 . .. .deps exec exec.o .libs Makefile 9 5------------execle------------ 10 . .. .deps .libs Makefile exec exec.o 11 6------------execve----------- 12 . .. .deps .libs Makefile exec exec.o 13 按回車繼續!