歡迎來到Linux教程網
Linux教程網
Linux教程網
Linux教程網
Linux教程網 >> Linux基礎 >> Linux技術 >> 老生常談exec函數族

老生常談exec函數族

日期:2017/3/3 12:28:27   编辑:Linux技術

1.exec函數說明

fork函數是用於創建一個子進程,該子進程幾乎是父進程的副本,而有時我們希望子進程去執行另外的程序,exec函數族就提供了一個在進程中啟動另一個程序執行的方法。它可以根據指定的文件名或目錄名找到可執行文件,並用它來取代原調用進程的數據段、代碼段和堆棧段,在執行完之後,原調用進程的內容除了進程號外,其他全部被新程序的內容替換了。另外,這裡的可執行文件既可以是二進制文件,也可以是Linux下任何可執行腳本文件。

2.在Linux中使用exec函數族主要有以下兩種情況

當進程認為自己不能再為系統和用戶做出任何貢獻時,就可以調用任何exec 函數族讓自己重生。

如果一個進程想執行另一個程序,那麼它就可以調用fork函數新建一個進程,然後調用任何一個exec函數使子進程重生。

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是真正意義上的系統調用,其它都是在此基礎上經過包裝的庫函數。它們之間的區別:

第一個區別是:

前四個取路徑名做為參數,後兩個取文件名做為參數,如果文件名中不包含 “/” 則從PATH環境變量中搜尋可執行文件, 如果找到了一個可執行文件,但是該文件不是連接編輯程序產生的可執行代碼文件,則當做shell腳本處理。

第二個區別:

前兩個和最後一個函數中都包括“ l ”這個字母 ,而另三個都包括“ v ”, " l "代表 list即表 ,而" v "代表 vector即矢量,也是是前三個函數的參數都是以list的形式給出的,但最後要加一個空指針,如果用常數0來表示空指針,則必須將它強行轉換成字符指針,否則有可能出錯。,而後三個都是以矢量的形式給出,即數組。

最後一個區別:

與向新程序傳遞環境變量有關,如第二個和第四個以e結尾的函數,可以向函數傳遞一個指向環境字符串指針數組的指針。即自個定義各個環境變量,而其它四個則使用進程中的環境變量。

3.實例講解:

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);

#ifdef HAVE_CONFIG_H
#include <config.h>
#endif

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <errno.h>

int main(int argc, char *argv[])
{
  //以NULL結尾的字符串數組的指針,適合包含v的exec函數參數
  char *arg[] = {"ls", "-a", NULL};
  
  /**
   * 創建子進程並調用函數execl
   * execl 中希望接收以逗號分隔的參數列表,並以NULL指針為結束標志
   */
  if( fork() == 0 )
  {
    // in clild 
    printf( "1------------execl------------\n" );
    if( execl( "/bin/ls", "ls","-a", NULL ) == -1 )
    {
      perror( "execl error " );
      exit(1);
    }
  }
  
  /**
   *創建子進程並調用函數execv
   *execv中希望接收一個以NULL結尾的字符串數組的指針
   */
  if( fork() == 0 )
  {
    // in child 
    printf("2------------execv------------\n");
    if( execv( "/bin/ls",arg) < 0)
    {
      perror("execv error ");
      exit(1);
    }
  }
  
  /**
   *創建子進程並調用 execlp
   *execlp中
   *l希望接收以逗號分隔的參數列表,列表以NULL指針作為結束標志
   *p是一個以NULL結尾的字符串數組指針,函數可以DOS的PATH變量查找子程序文件
   */
  if( fork() == 0 )
  {
    // in clhild 
    printf("3------------execlp------------\n");
    if( execlp( "ls", "ls", "-a", NULL ) < 0 )
    {
      perror( "execlp error " );
      exit(1);
    }
  }
  
  /**
   *創建子裡程並調用execvp
   *v 望接收到一個以NULL結尾的字符串數組的指針
   *p 是一個以NULL結尾的字符串數組指針,函數可以DOS的PATH變量查找子程序文件
   */
  if( fork() == 0 )
  {
    printf("4------------execvp------------\n");
    if( execvp( "ls", arg ) < 0 )
    {
      perror( "execvp error " );
      exit( 1 );
    }
  }
  
  /**
   *創建子進程並調用execle
   *l 希望接收以逗號分隔的參數列表,列表以NULL指針作為結束標志
   *e 函數傳遞指定參數envp,允許改變子進程的環境,無後綴e時,子進程使用當前程序的環境
   */
  if( fork() == 0 )
  {
    printf("5------------execle------------\n");
    if( execle("/bin/ls", "ls", "-a", NULL, NULL) == -1 )
    {
      perror("execle error ");
      exit(1);
    }
  }
  
  /**
   *創建子進程並調用execve
   * v 希望接收到一個以NULL結尾的字符串數組的指針
   * e 函數傳遞指定參數envp,允許改變子進程的環境,無後綴e時,子進程使用當前程序的環境
   */
  if( fork() == 0 )
  {
    printf("6------------execve-----------\n");
    if( execve( "/bin/ls", arg, NULL ) == 0)
    {
      perror("execve error ");
      exit(1);
    }
  }
  return EXIT_SUCCESS;
}

Copyright © Linux教程網 All Rights Reserved