本節目標: exec替換進程映像 exec關聯函數組(execl、execlp、execle、execv、execvp) 一,exec替換進程映像 在進程的創建上Unix采用了一個獨特的方法,它將進程創建與加載一個新進程映象分離。這樣的好處是有更多的余地對兩種操作進行管理。 當我們創建了一個進程之后,通常將子進程替換成新的進程映象,這可以用exec系列的函數來進行。當然,exec系列的函數也可以將當前進程替換掉。 例如:在shell命令行執行ps命令,實際上是shell進程調用fork復制一個新的子進程,在利用exec系統調用將新產生的子進程完全替換成ps進程。 二,exec系列函數(execl、execlp、execle、execv、execvp) 包含頭文件<unistd.h> 功能: 用exec函數可以把當前進程替換為一個新進程,且新進程與原進程有相同的PID。exec名下是由多個關聯函數組成的一個完整系列, 頭文件<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[]); 參數: path參數表示你要啟動程序的名稱包括路徑名 arg參數表示啟動程序所帶的參數,一般第一個參數為要執行命令名,不是帶路徑且arg必須以NULL結束 返回值:成功返回0,失敗返回-1 注:上述exec系列函數底層都是通過execve系統調用實現: #include <unistd.h> int execve(const char *filename, char *const argv[],char *const envp[]); DESCRIPTION: execve() executes the program pointed to by filename. filename must be either a binary executable, or a script starting with a line of the form 以上exec系列函數區別: 1,帶l 的exec函數:execl,execlp,execle,表示后邊的參數以可變參數的形式給出且都以一個空指針結束。 示例:
#include <stdio.h> #include <stdlib.h> #include <unistd.h> int main(void) { printf("entering main process---\n"); execl("/bin/ls","ls","-l",NULL); printf("exiting main process ----\n"); return 0; }
利用execl將當前進程main替換掉,所有最后那條打印語句不會輸出
2,帶 p 的exec函數:execlp,execvp,表示第一個參數path不用輸入完整路徑,只有給出命令名即可,它會在環境變量PATH當中查找命令 示例: 當不帶p但沒給出完整路徑時: #include <stdio.h> #include <stdlib.h> #include <unistd.h> int main(void) { printf("entering main process---\n"); if(execl("ls","ls","-l",NULL)<0) perror("excl error"); return 0; }
結果顯示找不到,所有替換不成功,main進程繼續執行
現在帶p:
if(execlp("ls","ls","-l",NULL)<0)

替換成功
3,不帶 l 的exec函數:execv,execvp表示命令所需的參數以char *arg[]形式給出且arg最后一個元素必須 是NULL 示例: #include <stdio.h> #include <stdlib.h> #include <unistd.h> int main(void) { printf("entering main process---\n"); int ret; char *argv[] = {"ls","-l",NULL}; ret = execvp("ls",argv); if(ret == -1) perror("execl error"); printf("exiting main process ----\n"); return 0; }
替換成功
4,帶 e 的exec函數:execle表示,將環境變量傳遞給需要替換的進程 從上述的函數原型中我們發現: extern char **environ; 此處的environ是一個指針數組,它當中的每一個指針指向的char為“XXX=XXX” environ保存環境信息的數據可以env命令查看:
它由shell進程傳遞給當前進程,再由當前進程傳遞給替換的新進程
示例:execle.c #include <stdio.h> #include <stdlib.h> #include <unistd.h> int main(int argc, char *argv[]) { //char * const envp[] = {"AA=11", "BB=22", NULL}; printf("Entering main ...\n"); int ret; ret =execl("./hello", "hello", NULL); //execle("./hello", "hello", NULL, envp); if(ret == -1) perror("execl error"); printf("Exiting main ...\n"); return 0; } hello.c #include <unistd.h> #include <stdio.h> extern char** environ; int main(void) { printf("hello pid=%d\n", getpid()); int i; for (i=0; environ[i]!=NULL; ++i) { printf("%s\n", environ[i]); } return 0; }
可知原進程確實將環境變量信息傳遞給了新進程
那么現在我們可以利用execle函數自己給的需要傳遞的環境變量信息:
示例程序:execle.c #include <stdio.h> #include <stdlib.h> #include <unistd.h> int main(int argc, char *argv[]) { char * const envp[] = {"AA=11", "BB=22", NULL}; printf("Entering main ...\n"); int ret; //ret =execl("./hello", "hello", NULL); ret =execle("./hello", "hello", NULL, envp); if(ret == -1) perror("execl error"); printf("Exiting main ...\n"); return 0; } hello.c #include <unistd.h> #include <stdio.h> extern char** environ; int main(void) { printf("hello pid=%d\n", getpid()); int i; for (i=0; environ[i]!=NULL; ++i) { printf("%s\n", environ[i]); } return 0; }
確實將給定的環境變量傳遞過來了
http://bbs.csdn.net/topics/350057686

要怎樣做才能正常執行(主要是execl函數運行php文件。),並輸入exit退出?
execl會載入你調用的程序,覆蓋原有代碼段,相當於你本來的程序的代碼段被替換成execl執行的了。
所以execl后面的都不會輸出了。
正確的應該是fork一個子進程,在子進程中調用execl。
如果我把execl 放到用pthread_create創建的線程是不是也一樣會覆蓋原有的代碼?
我測試過也是一樣會退出。。
一定要用fork 嗎?
execl是覆蓋進程的代碼段,所以如果你原來的程序還需要正常退出的話,就要fork一個子進程。
另外,如果需要execl調用的這個程序執行完成,就需要在父進程中等待,可以調用waitpid。
具體的你man一下看看。
如果用了fork 。執行execl 后會不會停止 子進程的呢?
fork以后,子進程拷貝父進程的幾乎所有特性,包括pc,也就是說,在子進程中,還是從你fork的地方開始運行的。然后你execl,覆蓋掉的是子進程的代碼段,與父進程無關。
pthread_create創建的子線程與父線程共用同一代碼段!只是寄存器和棧不同!
execl不是創建一個新進程,Linux只有fork能創建新進程
execl成功是不會返回的,會執行新的程序。
execl失敗才會返回
http://bbs.chinaunix.net/thread-4168834-1-1.html

我感覺execl的第一個參數和第二個參數有重疊,幫我 ... 如題,我學習了一下execl函數的用法: #include<unistd.h> int main() { execl("ls", "ls", "-al"); return 0; } OK,什么也不打印,於是我改了一下: #include<unistd.h> int main() { execl("/bin/ls", "ls", "-al", 0); return 0; } 很奇怪啊,execl第一個參數必須是path,我如果把調用語句改成execl("/bin", "ls", "-al", 0); 發現也不行。那豈不是說這個path參數必須包含可執行程序的名字本身? 可是這樣的話,execl的第二個參數就是文件名啊,第二個參數豈不是多余了? 非常疑惑,求解釋! path里面包含了file的名字,那還要第二個file參數干什么呢? 感覺多余? 第2個參數將傳給進程,也就是argv[0],進程可以通過查看面子有多大,就能看人下菜碟-哦是隨機應變了!。 果然是高手!我驗證了你的說法,第二個參數是argv[0],可以是任何東西,不必是可執行文件名。如下圖所示:
三,fcntl()函數中的FD_CLOEXEC標識在exec系列函數中的作用
#include <unistd.h>
#include <fcntl.h>
int fcntl(int fd, int cmd, ... /* arg */ );
File descriptor flags
The following commands manipulate the flags associated with a file
descriptor. Currently, only one such flag is defined: FD_CLOEXEC, the
close-on-exec flag. If the FD_CLOEXEC bit is 0, the file descriptor
will remain open across an execve(2), otherwise it will be closed.
//如果FD_CLOEXEC標識位為0,則通過execve調用后fd依然是打開的,否則為關閉的
F_GETFD (void)
Read the file descriptor flags; arg is ignored.
F_SETFD (long)
Set the file descriptor flags to the value specified by arg.
如:fcntl(fd, F_SETFD, FD_CLOEXEC);

1關閉(標准輸出關閉)ls -l無法將結果顯示在標准輸出
http://www.cnblogs.com/mickole/p/3187409.html