10.15.2015

execl(), execlp(), execle(), execv(), execvp(), execve(), system()

這一次要紀錄的心得是Linux C下面的函式:execl(), execlp(), execle(), execv(), execvp(), execve(), system()。因為這7個函式具有某種程度上的相關性,所以要一起記下來。首先,先看一下這些函式的原型:

功能說明:執行檔案;或是Shell命令。

標頭檔:

#include <unistd.h>
#include <stdlib.h>

函式宣告:

1. int execl(const char *path, const char *arg, ...);

2. int execlp(const char *file, const char *arg, ...);

3. int execle(const char *path, const char *arg, ..., const envp[]);

4. int execv(const char *path, char *const argv[]);

5. int execvp(const char *file, char *const argv[]);

6. int execve(const char *filename, char *const argv[], char *const envp[]);

7. int system(const char *string);

回傳值:

1. exec系列的函式執行成功不會返回;執行失敗則是回傳-1;
2. system()函式若是在執行/bin/sh時失敗,會回傳-127,若是其他失敗原因是回傳-1;執行成功會回傳該Shell命令的回傳值。

範例:
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>

int 
main(argc, argv, envp)
int argc;
char *argv[];
char **envp;
{
    int nArgv = atoi(argv[1]);
    char *szArgv[] = {"ls", "-al", "/etc/passwd", (char *)NULL};

    if (nArgv == 0)
        execl("/bin/ls", "ls", "-al", "/etc/passwd", (char *)NULL);
    else if (nArgv == 1)
        execlp("ls", "ls", "-al", "/etc/passwd", (char *)NULL);
    else if (nArgv == 2)
        execle("/bin/ls", "ls", "-al", "/etc/passwd", (char *)NULL, envp);
    else if (nArgv == 3)
        execv("/bin/ls", szArgv);
    else if (nArgv == 4)
        execvp("ls", szArgv);
    else if (nArgv == 5)
        execve("/bin/ls", szArgv, envp);
    else
        system("/bin/ls -al /etc/passwd");
    printf("DONE. \n");

    return 0;
}
函式說明:
1. exec*()系列的函式和system()函式的差異在於,exec*()會取代原本的程式 (所以執行成功不會有回傳值),而system()執行完之後會回到原本的程式 (所以會執行到printf())。

2. system()在執行時,是先呼叫/bin/sh (如/bin/bash),再去執行"/bin/ls -al",所以是執行2個動作;而exec*()系列是直接執行"/bin/ls -al"。就效能的角度而言,後者較佳。

3. execl*()和execv*()的差異在於execv*()系列是把*argv[] (Arguments Variable,參數變數)字串陣列的方式傳送進去。

4. execlp()和execvp()會在環境參數的目錄PATH中去尋找"ls"這一支程式在哪裡;這裡「環境參數的目錄」指的是:"echo $PATH"所列出的目錄。如:

[root@localhost]# echo $PATH
/usr/lib/qt-3.3/bin:/usr/kerberos/sbin:/usr/kerberos/bin:/usr/lib/ccache:/usr/local/arm_tools/bin:/usr/local/sbin:/usr/sbin:/sbin:/usr/local/bin:/usr/bin:/bin:/root/bin:/usr/local/arm_tools/bin/:/usr/local/bin/

若在/bin/沒有找到ls這一支程式,就會依序地到這些目錄下去尋找:

/usr/lib/qt-3.3/bin
/usr/kerberos/sbin
/usr/kerberos/bin
/usr/lib/ccache
/usr/local/arm_tools/bin
/usr/local/sbin
/usr/sbin
/sbin
/usr/local/bin
/usr/bin:/bin
/root/bin
/usr/local/arm_tools/bin/
/usr/local/bin/

所以,假如/bin/ls這一支程式原本就存在,基本上是不影響執行的效能;若是不存在,就多了一個「到各個目錄去尋找」的動作

5. execle()和execve()會把原本這一支程式的環境參數 (Environment Parameters, char **envp)傳給新的程式"/bin/ls"來使用;假如新的程式需要用到環境參數的話。

6. exec*()系列的函式最後面一定要加上一個結束字元:(char *)NULL;或是"\0"也行。

沒有留言:

張貼留言