Linux調用可執行程序

在C/C++程序中,經常需要調用其它的程序來先成某項任務,例如其它的C/C++程序、操作系統命令或Shell腳本,C/C++提供了exec函數族和system函數來實現這個功能。

一、exce函數族

exec函數族提供了一個在進程中啓動另一個程序執行的方法。它可以根據指定的文件名或目錄名找到可執行文件,並用它來取代原調用進程的數據段、代碼段和堆棧段,在執行完之後,原調用進程的內容除了進程號外,其他全部被新的進程替換了。還有,這裏的可執行文件既可以是二進制文件,也可以是Linux下任何可執行的腳本文件。

exec函數族的聲明如下:

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

參數說明:

path:要執行的程序路徑。可以是絕對路徑或者是相對路徑。在execv、execl和execle這三個函數中,使用帶路徑名的文件名作爲參數。

file:要執行的程序名稱。如果該參數中包含“/”字符,則視爲路徑名直接執行;否則視爲單獨的文件名,系統將根據PATH環境變量指定的路徑順序搜索指定的文件。

argv:命令行參數的數組。

envp:帶有該參數的exec函數可以在調用時指定一個環境變量數組。其他不帶該參數的exec函數則使用調用者進程的環境變量。

arg:程序的第0個參數,即程序名自身。相當於argv[0]。

:命令行參數列表。調用相應程序時有多少命令行參數,就需要有多少個輸入參數項。注意:在使用此類函數時,在所有命令行參數的最後應該增加一個空的參數項(NULL),表明命令行參數結束。

如果執行失敗則直接返回-1,失敗原因存於errno 中。

如果執行成功則函數不會返回, 這句話可能難以理解,當在主程序中成功調用execl後,被調用的程序將取代調用者程序,也就是說,execl函數之後的代碼都不會被執行。

在實際開發中,最常用的是execl函數,其它的極少使用,我就不介紹了,如果大家認爲execl滿足不了實際開發的需求,再去研究其它幾個函數。

示例(book266.cpp)

/*
 * 程序名:book266.cpp,此程序用於演示用execl函數執行程序。
 * 作者:C語言技術網(www.freecplus.net) 日期:20190525
*/
#include <stdio.h>
#include <string.h>
#include <errno.h>
#include <unistd.h>

int main()
{
  int iret=execl("/bin/lss","/bin/ls","-l","/usr/include/stdio.h",0);   // /bin/lss不存在,執行不能成功。
  // int iret=execl("/bin/ls","/bin/ls","-l","/usr/include/stdio.h",0); // 可以調用成功的代碼。

  printf("iret=%d\n",iret);
  if (iret==-1) printf("%d:%s\n",errno,strerror(errno));

}

我們測試執行失敗的情況,啓用以下代碼。

  int iret=execl("/bin/lss","/bin/ls","-l","/usr/include/stdio.h",0);   // /bin/lss不存在,執行不能成功。

運行效果

再測試執行成功的情況,啓用以下代碼。

 int iret=execl("/bin/ls","/bin/ls","-l","/usr/include/stdio.h",0); // 可以調用成功的代碼。

運行效果

從book266執行的結果可以看出,主程序中成功調用execl後,execl函數之後的代碼都不會被執行。

二、system函數

system函數提供了另一種簡單的執行程序的方法,把需要執行的命令用一個參數傳給system函數。

system函數的聲明如下:

int system(const char * string);

system會調用fork產生子進程,由子進程來調用/bin/sh-c string來執行參數string字符串所代表的命令,此命令執行完後隨即返回原調用的進程。在調用system期間SIGCHLD 信號會被暫時擱置,SIGINT和SIGQUIT 信號則會被忽略。

如果fork失敗 返回-1,出現錯誤。

如果execl失敗,表示不能執行shell,返回值相當於shell執行了exit(127)。

如果執行成功則返回子shell的終止狀態。

如果system在調用/bin/sh時失敗則返回127,其他失敗原因返回-1。若參數string爲空指針(NULL),僅當命令處理程序可用時,返回非零值。如果system調用成功則最後會返回執行shell命令後的返回值,但是此返回值也有可能爲 system調用/bin/sh失敗所返回的127,因此最好能再檢查errno 來確認執行成功。

示例(book269.cpp)

/*
 * 程序名:book269.cpp,此程序用於演示用system函數執行程序。
 * 作者:C語言技術網(www.freecplus.net) 日期:20190525
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>

int main()
{
  int iret;

  // 調用不成功的代碼。
  iret=system("/bin/lss -l /usr/include/stdio.h");
  printf("iret=%d\n",iret);
  if (iret==-1) printf("%d:%s\n",errno,strerror(errno));

  // 可以調用成功的代碼。
  iret=system("/bin/ls -l /usr/include/stdio.h");
  printf("iret=%d\n",iret);
  if (iret==-1) printf("%d:%s\n",errno,strerror(errno));
}
運行效果

 

三、版權聲明

C語言技術網原創文章,轉載請說明文章的來源、作者和原文的鏈接。

作者:C語言技術網(www.freecplus.net

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章