popen() 封裝了 pipe()、fork()、exec(),以文件流 (FILE*) 形式提供單向管道,極大簡化「程序執行命令並讀取/寫入輸出」的開發。
#include
FILE *popen(const char *command, const char *type); // type: "r" 讀命令輸出, "w" 寫命令輸入
int pclose(FILE *stream); // 關閉流,等待子進程結束,返回狀態
"r" 模式)
#include
#include
#include
#define BUFSZ 4096
int main() {
char buf[BUFSZ];
FILE *fp = popen("ls -la", "r"); // 執行命令,獲取輸出流
if (!fp) { perror("popen"); return 1; }
while (fgets(buf, BUFSZ, fp)) {
fputs(buf, stdout); // 直接轉發到標準輸出
}
int status = pclose(fp);
if (status == -1) perror("pclose");
else printf("Command exited with status %d\n", WEXITSTATUS(status));
return 0;
}
"w" 模式)
FILE *fp = popen("sort", "w"); // sort 從 stdin 讀取,排序後輸出到 stdout (終端)
if (fp) {
fprintf(fp, "delta\nalpha\nepsilon\nbeta\ngamma\n");
pclose(fp); // 關閉寫端,sort 收到 EOF 開始排序並輸出
}
popen() **只支援單向** ("r" 或 "w")。若需雙向 (同時讀寫),需手動 pipe() + fork() + dup2() + exec(),或使用 socketpair() / pty (偽終端)。
pclose) → 死鎖。解決:非阻塞讀、多線程讀、或限制命令輸出量。command 經 /bin/sh -c 執行,用戶輸入若含 ; rm -rf / 等將被執行。**嚴禁**未過濾的用戶輸入拼接進 command。pclose() 回收子進程,否則產生殭屍進程。popen 可能衝突,高併發場景建議自行管理管道。system() vs popen() vs 手動管道| 函數 | 返回值 | 交互能力 | 適用場景 |
|---|---|---|---|
system() | 命令退出狀態 | 無 (輸出直接到終端) | 簡單執行無需捕獲輸出 |
popen() | FILE* 流 | 單向 (讀或寫) | 需捕獲輸出/提供輸入 |
手動 pipe/fork/exec | 自定義 | 雙向、多管道、重定向控制 | 複雜 IPC、高性能、安全要求高 |