首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> C語言 >> C >> 關於C

C語言進程間通信:偽管道 popen/pclose 實現命令輸出捕獲

     編輯:關於C

popen() / pclose() 被稱為「偽管道」,因其本質是啟動 Shell 進程執行命令,通過匿名管道連接調用進程與命令的標準輸入/輸出。雖性能不如 pipe(),但極適合「執行命令、捕獲輸出」場景。本文詳細演示 popen("env","r") 讀取環境變量 → popen("grep bash","w") 過濾的管道鏈代碼。

API 詳解

#include 

FILE *popen(const char *command, const char *mode);
// command: Shell 命令字符串(如 "ls -l", "grep foo")
// mode: "r" 從命令 stdout 讀取;"w" 向命令 stdin 寫入
// 返回: 文件流指針,可用 fread/fwrite/fgets 等操作

int pclose(FILE *stream);
// 關閉流,等待命令結束,返回命令退出碼

核心邏輯:雙向管道鏈

int main() {
    char buffer[BUFSIZ+1] = {0};
    int read_count = 0;
    FILE *p_read, *p_write;

    // 1. 以「讀」模式打開 env 命令:我們從 env 的 stdout 讀取
    p_read = popen("env", "r");
    if (!p_read) { perror("popen env"); return 1; }

    // 2. 以「寫」模式打開 grep 命令:我們向 grep 的 stdin 寫入
    p_write = popen("grep bash", "w");
    if (!p_write) { perror("popen grep"); pclose(p_read); return 1; }

    // 3. 從 env 讀取,寫入 grep,形成管道鏈
    while ((read_count = fread(buffer, 1, BUFSIZ, p_read)) > 0) {
        fwrite(buffer, 1, read_count, p_write);
    }

    // 4. 關閉(順序不影響正確性,但先關寫端讓 grep 見到 EOF)
    pclose(p_write);  // grep 讀到 EOF,輸出匹配行並退出
    pclose(p_read);   // 回收 env 進程

    return 0;
}

模式 "r"/"w" 的直觀理解

記憶口訣:mode 表示調用進程對管道的操作。"r" = 我讀管道 = 命令寫管道 = 命令輸出。"w" = 我寫管道 = 命令讀管道 = 命令輸入。

運行結果

SHELL=/bin/bash

與 Shell 直接執行 env | grep bash 完全一致。

等價 Shell 命令對比

$ env | grep bash
SHELL=/bin/bash

性能與局限性

調用進程操作mode命令進程對應端數據流向
讀取命令輸出"r"stdout命令 → 管道 → 調用進程
向命令輸入數據"w"stdin調用進程 → 管道 → 命令
優點缺點
API 簡單,自動處理 fork/exec/管道創建啟動 Shell 開銷大(fork+exec /bin/sh)
支持任意 Shell 命令(管道、重定向、通配符)非線程安全(環境變量、信號處理衝突)
返回 FILE* 兼容標準 I/O 函數無法分別獲取 stdout/stderr(合併輸出)
自動處理命令退出碼回收命令注入風險(用戶輸入拼接 command)

安全建議

  • 避免拼接用戶輸入構造 command,防止命令注入。
  • 需分離 stdout/stderr 時,用 pipe()+fork()+exec() 手工實現。
  • 高性能場景優先 pipe() 或共享內存。

總結

popen 是「調用 Shell 命令」的便捷封裝,以文件流抽象屏蔽了 fork/exec/pipe 細節。理解 "r"/"w" 模式對應調用進程視角,構建 p_read → p_write 管道鏈,即可實現命令輸出的流式處理。但請牢記:它是重量級操作,高頻調用請改用輕量級 IPC。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved