1. 程式人生 > >linux c程式設計:popen

linux c程式設計:popen

我們在執行shell命令比如cat /etc/group | grep root的時候,通過管道的機制將cat /etc/group的結果傳遞給grep root,然後將結果顯示出來
linux中提供了popen和pclose函式來達到這個目的。
FILE *popen(const char *command, const char *type);
int pclose(FILE *stream);
函式popen先執行fork,然後呼叫exec以執行command,並且返回一個要麼指向子程序的stdout,要麼指向stdin的檔案指標:若type是”r”,則檔案指標是連線到子程序執行command命令的標準輸出,如果type是”w”,則檔案指標連線到子程序執行command命令的標準輸入。那麼前面shell命令cat /etc/group | grep root就可以通過下面的程式來實現:
void chapter_15_5_3()
{
    FILE *fpr=NULL,*fpw=NULL;
    char buf[256];
    int ret;
    fpr=popen("cat /etc/group","r");
    fpw=popen("grep root","w");
    while((ret=fread(buf,1,sizeof(buf),fpr)) > 0)
    {
        fwrite(buf,1,ret,fpw);
    }
    pclose(fpr);
    pclose(fpw);
}
執行結果:

那麼popen函式是如何工作的呢:

(1) popen(comm, type)函式會建立一個管道,類似與pipe函式建立管道。fork一個子程序,在子程序中執行execX函式來執行comm命令(因為execX執行新程式後新程式的程序空間會覆蓋原程序的程序空間,所以開一個子程序來執行execX家族函式),然後想要返回stdout或者stdin的檔案指標(取決於type)

(2) 因為comm命令是通過子程序的執行的,那麼stdin或者stdout檔案指標也是子程序的程序片空間的,要將其返回給父程序,這就需要通過管道了;

(3) stdin是供程式寫資料的,

stdout是供程式讀資料的。這裡設計的巧妙之處在於,管道的讀端跟stdout繫結,管道的寫端跟stdin繫結;

(4) 讀寫管道操作的無非就是管道(檔案)fd(檔案描述符),這裡將fd封裝到檔案流指標fp中;

在上面的程式碼中

(1)popen首先建立一個管道,假設為fdfd[0]指向管道的讀端,fd[1]指向管道的寫端

(5) popen的type”r”返回的是stdout那麼關閉fd[0], 執行shell命令,並寫入fd[1]在父程序中關閉fd[1], fd[0]轉換為一個檔案描述符返回。表示建立一個管道且該管道檔案的讀端賦給fpr

。通過fopen可以從fpr中讀取資料存入buffer

 

(6) popen的type”w”返回的是stdin那麼關閉fd[1], 在父程序中關閉fd[0], fd[1]轉換為一個檔案描述符返回表示建立一個管道且該管道檔案的寫端賦給fpw。通過fwrite()可以從fpw

(7) 這樣子,讀fpr(管道的讀端)等於讀子程序的stdout,寫fpw(管道的寫端)等於寫子程序的stdin。