1. 程式人生 > >Linux中的popen函式和system函式

Linux中的popen函式和system函式

說在前面:在實際程式設計中儘量減少使用system函式。

int system(const char *command);

說明: system()通過呼叫/ bin / sh -c命令執行命令中指定的命令,並在命令完成後返回。在執行該命令期間,SIGCHLD將被阻塞,並且SIGINT和SIGQUIT將被忽略。

返回值:

實際上system呼叫了三個函式:fork()、exec()、waitpid()。因此有三種返回值:

1>fork()失敗或者waitpid()返回除了EINTR之外的出錯,則system返回-1.而且errno

中設定了錯誤型別值。

2>如果exec失敗(表示不能執行shell),則其返回值如同shell執行了exit(127)一樣

3>如果三個函式都執行成功,並且system的返回值是shell的終止狀態,其格式已在已在waitpid中說明。

system的實現:

int system(const char * cmdstring)  
{   
  pid_t pid;   
  int status;   
  if(cmdstring == NULL)  
    {   
      return (1);   
    }   
  if((pid = fork())<0)  
    {   
      status = -1;   
    }   
  else if(pid = 0)  
    {  
       execl("/bin/sh", "sh", "-c", cmdstring, (char *)0); -exit(127); //子程序正常執行則不會執行此語句 }   
  else  
    {   
       while(waitpid(pid, &status, 0) < 0)  
    {  
  if(errno != EINTER){ status = -1; break;   
    }   
   }  
  }   
  return status;   
}   

簡單的使用:

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

int main()
{
  int status = 0;
  status = system("ls -a");
  if(-1 == status)
  {
    perror("system");
    exit(1);
  }
  if(WIFEXITED(status) != 0)  //正常退出
  {
    if(WEXITSTATUS(status) == 0)  //操作正確
    {
      printf("run command success\n");
    }
    else
    {
      printf("run error\n");
    }
  }
  else      //異常退出
  {
    printf("exit error is %d\n", WEXITSTATUS(status));
  }
  return 0;
}

通過上面的程式碼我們可以看到,system在使用時的一個弊端,由於返回值太多,要安全的使用它就要進行許多步的出錯處理。

所以,不太建議使用system。

使用system需要注意:

1、建議system()函式只用來執行shell命令,因為一般來講,system()返回值不是0就說明出錯了; 2、監控一下system()函式的執行完畢後的errno值,爭取出錯時給出更多有用資訊; 

建議使用popen函式取代system();

FILE *popen(const char *command, const char *type);

int pclose(FILE *stream);返回值: command的終止狀態, 出錯返回-1

popen()函式較於system()函式的優勢在於使用簡單,popen()函式只返回兩個值:
成功返回子程序的status,使用WIFEXITED相關巨集就可以取得command的返回結果;
失敗返回-1,我們可以使用perro()函式或strerror()函式得到有用的錯誤資訊。

popen先執行fork,然後呼叫exec以執行command並返回一個標準I/O檔案指標。如果type是“r”,則檔案指標連結到command的標準輸出。如果type是“w”,則檔案指標連結到command的標準輸入。將popen和fopen進行類比,方便記憶其最後一個引數及其作用,如果type是“r”,則返回檔案指標是刻度的,如果type是是“w”,則是可寫的。

 

簡單使用:

#include <stdio.h>
#include <stdlib.h>

int main()
{
  FILE* fp = NULL;
  char buf[1024] = {0};
  fp = popen("ls -a", "r");
  if(NULL == fp)
  {
    perror("popen");
    exit(1);
  }
  while(fgets(buf, 1024, fp) != NULL)
  {
   fprintf(stdout, "%s", buf); 
  }
  pclose(fp);

  return 0;
}

注意,popen絕不應該由設定使用者ID或設定組ID程式呼叫。當它執行命令

popen等同於execl("/bin/sh", "sh", "-c", command

,NULL);

它在從呼叫者繼承的環境中執行shell,並由shell解釋執行command。一個心懷不軌的使用者可以

操縱這種環境,使得shell能以設定ID檔案模式所授予的提升了

的許可權以及非預期的方式執行命令。

popen特別適用於構造簡單的過濾程式,它變換執行命令的輸入或輸出。

當命令希望構建自己的管道線時就是這種情形。