1. 程式人生 > >管道之popen,pclose函式

管道之popen,pclose函式

 方法6popen,pclose函式:

#include <stdio.h>

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

int pclose(FILE *fp);

返回值:cmdstring(shell)的終止狀態,若出錯則返回-1

  popen函式: 

pipe---->fork---->exec :建立一個管道,呼叫fork產生一個子程序,關閉管道的不使用端,執行一個shell以執行命令.

執行fp = popen(cmdstring, “r”)函式的結果

type為’r’連線到cmdstring

標準輸出; 此時fp相當於管道的fd[0], stdout相當於管道的fd[1]. 

返回一個指向fd[1] 端的FILE檔案指標,然後從fd讀取該資料

type為’w’連線到cmdstring的標準輸入,此時fp相當於管道的fd[1], stdin相當於管道的fd[0].

         返回fp, fp寫,也就寫到了子程序的fd[0],把寫入的資料(命令)/bin/sh 執行.

 pclose 函式:  關閉標準i/o流,然後等待命令終止

     popen向分頁程式傳送檔案

#include "apue.h"

#include <sys/wait.h>

#define

 PAGER    "${PAGER:-more}"   /*PAGER若定義使用其值 , or default使用more */

intmain(int argc, char *argv[])

{

char    line[MAXLINE];

    FILE    *fpin, *fpout;

if(argc != 2) err_quit("usage: a.out <pathname>");

if((fpin = fopen(argv[1], "r")) == NULL)err_sys("can't open %s", argv[1]);

if((fpout = popen(PAGER, "w")

) == NULL)err_sys("popen error");

/* copy argv[1] to pager */

while(fgets(line, MAXLINE, fpin) != NULL)

    {

if(fputs(line, fpout) == EOF)  err_sys("fputs error to pipe");

    }

if(ferror(fpin))err_sys("fgets error");

if(pclose(fpout) == -1)err_sys("pclose error");

    exit(0);

}

執行:

 

popen,pclose函式的實現

1. #include <errno.h>

1. #include <fcntl.h>

2. #include <stdio.h>

3. #include <unistd.h>

4. static pid_t *childpid =NULL;

5. static int maxfd;

6. 

7. FILE *popen(const char *cmdstring,const char *type)

8. {

9. int i;

10. int pfd[2];

11.     pid_t pid;

12.     FILE *fp;

13. 

14. /* only allow "r"or"w"*/

15. if((type[0]!='r'&& type[0]!='w')|| type[1]!= 0)

16. {

17.         errno = EINVAL;/* required by POSIX */

18.         return(NULL);

19. }

20. 

21. if(childpid ==NULL)/* first time through */

22. {/* allocate zeroed out arrayfor child pids */

23.         maxfd =open_max();//返回最大檔案描述符個數,其裡面實現用sysconf(_SC_OPEN_MAX)

24. if((childpid = calloc(maxfd, sizeof(pid_t)))==NULL)

25.             return(NULL);

26. }

27. 

28. if(pipe(pfd)< 0) return(NULL);/* errno set by pipe()*/

29.     if (pfd[0] >= maxfd || pfd[1] >= maxfd  )

30.     { //maxfd < 管道檔案描述符,則認為很多檔案描述符是開啟的.

31.          close(pfd[0]);   close(pfd[1]);  errnp = EMFILE;  return (NULL);

32.     }

33. if((pid = fork())< 0)

34. {

35.         return(NULL);/* errno set by fork()*/

36. }

37. elseif(pid == 0)/* child */

38. {

39. if(*type =='r')

40. {

41.             close(pfd[0]);

42. if(pfd[1]!= STDOUT_FILENO)

43. {

44.       dup2(pfd[1], STDOUT_FILENO);

45.                 close(pfd[1]);

46. }

47. }

48. else

49. {

50.             close(pfd[1]);

51. if(pfd[0]!= STDIN_FILENO)

52. {

53.  dup2(pfd[0], STDIN_FILENO);

54.                 close(pfd[0]);

55. }

56. }

57. 

58. for(= 0; i < maxfd; i++)/* close all descriptors in childpid[]*/

59. if(childpid[i]> 0) close(i); //關閉呼叫open依舊開啟著的的檔案描述符.

60. 

61.   execl("/bin/sh","sh","-c", cmdstring,(char *)0);

62.         _exit(127);

63. }

64. 

65. if(*type =='r')/* parent continues...*/

66. {

67.         close(pfd[1]);

if((fp =fdopen(pfd[0], type))==NULL) return(NULL);//將檔案描述符轉化為FILE* 指標.

68. }

69. else

70. {

71.         close(pfd[0]);

72. if((fp =fdopen(pfd[1], type))==NULL)return(NULL);

73. }

74. 

75.     childpid[fileno(fp)]= pid;/* remember child pid for this fd */

76.     return(fp);

77. }

78. 

79. intpclose(FILE *fp)

80. {

81. int fd, stat;

82.     pid_t pid;

83. 

84. if(childpid ==NULL)

85. {

86.         errno = EINVAL;

87.         return(-1);/* popen() has never been called */

88. }

89. 

90.     fd = fileno(fp);

91. if((pid = childpid[fd])== 0)//通過檔案描述符得到程序id.

92. {

93.         errno = EINVAL;

94.         return(-1);/* fp wasn't opened by popen()*/

95. }

96. 

97.     childpid[fd]= 0;

98. if(fclose(fp)== EOF) return(-1);

99. 

100. while(waitpid(pid,&stat, 0)< 0)

101. if(errno != EINTR) return(-1);/*error other than EINTR from waitpid()*/

102. /*核心不SIGCHLD資訊排隊,如果有b個子程序同時結束,父程序會收到1個訊號,訊號處理函式中while就會迴圈n次,

103. 把所有結束的子程序處理掉,直到沒有已經結束的程序。*/

104.     return(stat);/* return child's termination status */

105. }

Waitpid SIGCHLD訊號:

說明參考:

返回EINTR:

    1pclose的呼叫者已近註冊SIGCHLD訊號處理函式,呼叫pclose時,其內部的waitpid返回EINTR.

返回ECHILD:

   1popen的呼叫程序呼叫watpid獲取到popen子程序的退出狀態, 呼叫pclose時,其內部的waitpid返回ECHILD.

   2signal設定了忽略SIGCHLD訊號的情況下,核心會處理子程序的退出狀態並釋放子程序資源將,等父程序呼叫waitpid時,發現對應的pid進

    程已不存在,因而返回-1錯誤,errno為10(No child processes).

Popen實現的過濾器:

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

execl("/bin/sh", "sh", "-c", command, NULL);

它在從呼叫者繼承的環境中執行shell,並由shell解釋執行command。一個心懷不軌的使用者可以操縱這種環境,使得shell能以設定ID檔案模式所授予的提升了的許可權以及非預期的方式執行命令。

popen特別適用於構造簡單的過濾器程式,它變換執行命令的輸入或輸出。當命令希望構造它自己的管道線時,就是這種情形。

例項

考慮一個應用程式,它向標準輸出寫一個提示,然後從標準輸入讀1行。使用popen,可以在應用程式和輸入之間插入一個程式以便對輸入進行變換處理。圖15-7顯示了為此做的程序安排。


  15-7 popen對輸入進行變換處理

對輸入進行的變化可能是路徑名擴充,或者是提供一種歷史機制(記住以前輸入的命令)。

程式清單15-6是一個簡單的過濾程式,它只是將標準輸入複製到標準輸出,在複製時,將所有大寫字元變換為小寫字元。在寫了一行以後,對標準輸出進行了沖洗(用fflush),其理由可參考程序間通訊之協同程序。

程式清單15-6 將大寫字元轉換成小寫字元的過濾程式

#include "apue.h"

#include <ctype.h>

intmain(void)

{

int c;   

while((c = getchar()) != EOF)

    {

if(isupper(c))  c = tolower(c);

if(putchar(c) == EOF)    err_sys("output error");

if(c == '\n')fflush(stdout);

    }

    exit(0);

}

編譯該過濾程式,也就是編譯後的可執行檔名為myuclc,然後在程式清單15-7中用popen呼叫它們。

程式清單15-7 呼叫大寫/小寫過濾程式以讀取命令

#include "apue.h"

#include <sys/wait.h>

intmain(void)

{

char    line[MAXLINE];

    FILE    *fpin;

if((fpin = popen("/home/zhu/apue/myuclc", "r")) == NULL)err_sys("popen error");

for(;;)

    {

        fputs("prompt> ", stdout);

        fflush(stdout);

if(fgets(line, MAXLINE, fpin) == NULL)    /* read from pipe */

相關推薦

管道popen,pclose函式

 方法6的popen,pclose函式: #include <stdio.h> FILE *popen(const char *cmdstring, const char *type

linux c通過popenpclose函式建立管道執行shell 執行命令使用總結

1、函式介紹  popen 和 pclose 函式        操作是建立一個管道連結到另一個程序,然後讀其輸出或向其輸入端傳送資料。標準 I/O 庫提供了兩個函式 popen 和 pclose 函式,這兩個函式實現的操作是:建立一個管道,呼叫 fork 建立一個子程序

基於管道popenpclose函式

基於管道的popen和pclose函式 https://my.oschina.net/renhc/blog/35116   標準I/O函式庫提供了popen函式,它啟動另外一個程序去執行一個shell命令列。 這裡我們稱呼叫popen的程序為父程序,由popen啟動的程序稱

popen()函式執行指令碼,要用pclose()函式關閉

就像百度百科中所說popen()函式通過建立一個管道,呼叫fork()產生一個子程序,執行一個shell以執行命令來開啟一個程序。這個管道必須由pclose()函式關閉。 其中”必須由pclose()函式關閉“是一個容易被忽視的點,這不光光浪費資源的問題,更涉及到子程序的週

程序間通訊--popen函式pclose函式blog.chinaunix.net/xmlrpc.php?r=blog/article&uid=25940216&id=3206312

因為一個普遍的操作是為另一個程序建立一個管道,或者讀它的輸出或向它傳送輸入,所以標準I/O庫歷史上提供了popen和pclose函式。這兩 個函式處理我們自己一直在做的髒活:建立一個管道、fork一個子程序、關閉管道無用的端,執行一個外殼來執行這個命令,等待命令終止。 #include <st

Linux popenpclose函式

popen和pclose 標頭檔案 #include <stdio.h> 函式原型 FILE *popen(const char *command, const char *type)

Linux函式popen/pclose學習

本文針對專案中用到的幾個函式進行詳細分析,並儘可能的新增示例進行驗證學習。比如fcntl/ioctl函式、system/exec函式、popen/pclose函式、mmap函式等。 重點參考了《UNP》和《Linux程式設計》第四版。 一、概念

javascript高階程式設計--自執行函式

什麼是自執行函式? 顧名思義.就是不用呼叫,自己自動就會執行的函式; 為什麼要用自執行函式? 自執行函式內部是一個獨立的作用域,這樣就保持了一個相對獨立的名稱空間,避免汙染全域性作用域 怎麼建立自執行函式? 寫法一:(function(param){…})(re—param)

Djangoviews檢視函式

views檢視函式屬於MTV中邏輯處理的部分檢視函式包含著兩個物件,HttpRequest物件和HttpResponse物件 一.HttpRequest物件 HttpRequest物件在Django中會預設傳到views函式中作為第一個引數 HttpRequest的屬性:

邁向大神路 day8 函式(一)……

檔案補充 操作檔案 讀寫 內部連結 read 一次讀取 readline 一行一行度 不知道在哪結束 readlines 一次讀取 修改檔案的原理 (檔案是不能修改的,實在一個檔案修改完成後刪除 原始檔 並改名) with open('1.txt',

makemakefile 十 函式庫檔案

一、簡單的靜態庫書寫編譯和測試 檔案目錄如下所示: . ├── Makefile ├── MakefileTest ├── include.c ├── include.h └── main.c 0 directories, 5 files 其中main.c函式裡面會呼叫includ

Python路-Day06函式

P## 函式的定義 程式設計裡面的函式定義是:def作為關鍵字 def test(x) : "The function definitions" x+=1 return x def:定義函式的關金子 test:函式名 ():內可定義的形參 "文件描述(非

萬惡源 - Python函式進階

函式引數-動態引數 之前我們說過傳參,如果我們在傳引數的時候不很清楚有哪些的時候,或者說給一個函式傳了很多引數,我們就要寫很多,很麻煩怎麼辦呢,我們可以考慮使用動態引數 形參的第三種:動態引數 動態引數分為兩種: 1.動態接受位置引數 首先我們來回顧下位置引數

python遞迴函式,二分查詢

遞迴函式 遞迴函式一直都是我們所覺得難理解的以一種方式,但其實,也很好理解的,遞迴函式就是自己呼叫自己。就是在重複的做同一件事情。只是有的時候,也最好不要使用遞迴函式,因為你的函式一旦呼叫,就要開闢新的記憶體空間。不利於程式的執行。python對你記憶體一個保護機制,預設只能遞迴到998

python自定義函式、傳參、作用域

一、函式的作用域:表示函式執行時的範圍 注意:返回函式名稱,即返回一個地址;簡單說就是:函式名稱即指代該函式地址,在呼叫函式時,需在函式名稱後面加括號:函式名稱() 如上面圖片中那樣的情況,再最後加兩行程式碼: dz3=dz2()   #---接收foo2()函式執行的返回

SparkSQL自定義函式UDF和UDAF

SparkSQL中有兩種自定函式,在我們使用自帶的函式時無法滿足自己的需求時,可以使用自定義函式,SparkSQL中有兩種自定義函式,一種是UDF,另一種是UDAF,和Hive 很類似,但是hive中還有UDTF,一進多出,但是sparkSQL中沒有,這是因為spark中用 flatMap這

我的Python成長路---Day11-函式的使用及名稱空間和作用域

1.昨天函式的引數內容的補充 命名關鍵字引數: 在定義函式時,*與**之間引數稱之為命名關鍵字引數特點: 在呼叫函式時,命名關鍵字引數必須按照key=value的形式傳值 def func(x,*,y=1,z): 在這裡*後邊的y和z都是命名關鍵字引數,y像預設引數一樣被事先

我的Python成長路---Day10-函式的基本使用

一、函式的使用原則 函式的使用應該分為兩個明確的階段1. 定義階段:只檢測語法,不執行函式體程式碼 def func():     print('from func')2. 呼叫階段:會觸發函式體程式碼的執行 func() 函式使用的原則: 先定義後呼叫

JavaSE路10--函式

什麼是函式(必會): 完成特定功能的程式碼塊 看一個示例: //定義了一個函式p1,列印金字塔 public static void p1(){ System.out.println(" *"); System.out.println(" ***"); System.out.printl

pythonpandas的函式排序

import numpy as np import pandas as pd s1 = pd.Series(np.random.randint(-5,10,10)) s2 = pd.DataFrame(np.random.uniform(-5,10,(3,4)),index=list('