最新下载
热门教程
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
C++怎样执行系统命令并获取输出结果
时间:2026-07-27 17:12:53 编辑:袖梨 来源:一聚教程网
std::system只能执行命令并返回退出码,无法捕获stdout/stderr;推荐用popen(POSIX)或_popen(Windows)读取stdout,但需注意单向通信、必须pclose、缓冲区安全及shell注入风险。
用 std::system 只能执行命令,拿不到输出
很多人一上来就写 std::system("ls -l"),发现程序能运行命令,但 stdout 完全看不到——std::system 本质是 fork + exec + wait,输出直接打到终端,不经过你的程序。想捕获结果,必须换路子。
推荐方案:用 popen(POSIX)读取 stdout
popen 是最轻量、最常用的方式,适用于 Linux/macOS;Windows 上可用 _popen(需 <cstdio>,行为基本一致)。它返回 FILE*,可像读文件一样读命令输出。
注意点:
- 只支持单向通信:开
"r"模式读 stdout,开"w"模式写 stdin(极少用) - 必须调用
pclose(),否则子进程变成僵尸,且资源泄漏 - 输出是文本流,含换行符,需自己处理截断(如
fgets或fread) - 命令本身不能含未转义的 shell 元字符(如
$、`),否则有注入风险;若需拼接变量,务必做白名单校验或用exec系列替代
简单示例:
立即学习“C++免费学习笔记(深入)”;
#include <cstdio>#include <string>#include <vector><p>std::string exec(const char<em> cmd) {FILE</em> pipe = popen(cmd, "r");if (!pipe) return "";char buffer[128];std::string result;while (fgets(buffer, sizeof(buffer), pipe) != nullptr) {result += buffer;}pclose(pipe);return result;}</p><p>// 用法:auto out = exec("ps aux | grep myapp");
跨平台更稳的做法:用 fork + pipe + exec
当需要精确控制(比如同时捕获 stdout/stderr、设置超时、避免 shell 解析)时,popen 不够用。这时得手动建 pipe、fork 子进程、重定向 fd、再 exec。Windows 对应是 CreateProcess + ReadFile,逻辑更啰嗦。
关键细节:
- 父进程要
close写端 fd,否则read不会 EOF - 子进程必须在
exec前dup2把 pipe 写端复制成STDOUT_FILENO(和STDERR_FILENO,如果也要捕获) - 别忘了
waitpid获取退出码,否则子进程残留 - C++17 后可考虑封装成 RAII 类管理 pipe fd 和生命周期,但标准库没提供现成工具
别踩这些坑
常见翻车点:
- 用
std::string::c_str()传给popen,但字符串临时对象生命期短于popen调用——结果未定义行为;应先存为局部std::string变量再取c_str() - 误以为
popen支持 Windows 的 cmd 内置命令(如dir),实际需要写"cmd /c dir";Linux 下ls可直接用,因为/bin/sh默认存在 - 读取缓冲区太小(如只开 16 字节),遇到长行就截断;建议至少 1024 字节,或改用
getline配合std::istream包装 - 忽略命令执行失败:
popen返回nullptr表示 fork/exec 失败(如命令不存在),不是输出为空
真正难的从来不是“怎么调用”,而是“怎么安全地拼命令、怎么可靠地收数据、怎么不卡死、怎么清理干净”。尤其在线程里用,fd 和信号处理稍不注意就崩。