使用 popen 代替 system 函数执行系统命令
使用 popen 代替 system 函数执行系统命令
在 c/c++ 编程中常常需要执行一些系统命令,可以使用 system 函数,也可以采用 popen 的方式来实现,本文介绍 popen 的使用方法及优势。
system vs popen
| 特性 | system | popen |
|---|---|---|
| 获取输出 | ❌ 无法获取 | ✅ 可实时读取 |
| 灵活性 | ❌ 简单粗暴 | ✅ 逐行处理 |
| 错误处理 | ❌ 复杂 | ✅ 精确状态码 |
| 效率 | ❌ 低(启动shell) | ✅ 高(直接通信) |
实现详解
command.h
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
#ifndef COMMAND_H
#define COMMAND_H
#include <stdio.h>
#include <sys/wait.h>
#include <string>
#include <sstream>
#include <functional>
class Command {
public:
using Callback = std::function<void(const std::string &output)>;
public:
int execute(const std::string &command, const Callback &callback = nullptr) {
FILE *fp = nullptr;
std::stringstream output;
/// 使用 popen 执行命令并获取输出
fp = popen(command.c_str(), "r");
if (!fp) {
return -1;
}
char buffer[4096];
/// 读取命令输出,直到结束
while (nullptr != fgets(buffer, sizeof(buffer), fp)) {
output << buffer;
}
/// 调用回调函数处理输出
if (callback && !output.str().empty()) {
callback(output.str());
}
/// 关闭管道并获取命令执行状态
int status = pclose(fp);
fp = nullptr;
/// pclose 失败
if (-1 == status) {
return -2;
}
/// 命令未正常退出
if (!WIFEXITED(status)) {
return -3;
}
/// 返回命令退出状态码
return WEXITSTATUS(status);
}
};
#endif // COMMAND_H
main.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
#include "command.h"
#include <iostream>
int main() {
Command cmd;
int result = cmd.execute("ls -l", [](const std::string &output) {
std::cout << output;
});
if (result < 0) {
std::cerr << "Command execution failed with code: " << result << std::endl;
}
return 0;
}
代码说明
核心步骤
| 步骤 | 说明 |
|---|---|
| popen | 打开命令的标准输出管道 |
| fgets | 逐行读取输出 |
| Callback | 处理输出结果 |
| pclose | 关闭管道获取状态码 |
| WIFEXITED/WEXITSTATUS | 校验和提取退出状态 |
注意事项
- 命令注入:避免直接拼接用户输入,使用白名单验证
本文由作者按照 CC BY 4.0 进行授权