在 Linux 中,C++ 可以通过多种方式调用系统命令。以下是几种常用的方法:
system()
函数system()
是最简单的方法之一,它直接在子 shell 中执行指定的命令。
#include <cstdlib>
int main() {
int ret = system("ls -l");
return ret;
}
注意:
system()
会创建一个新的 shell 来执行命令,这可能会带来安全风险,尤其是当命令字符串来自不可信的输入时。popen()
和 pclose()
popen()
打开一个指向命令的管道,并允许读取命令的输出或向其写入输入。
读取命令输出示例:
#include <cstdio>
#include <iostream>
#include <memory>
#include <stdexcept>
#include <string>
std::string exec(const char* cmd) {
std::array<char, 128> buffer;
std::string result;
// 使用 unique_ptr 管理 FILE* 的生命周期
std::unique_ptr<FILE, decltype(&pclose)> pipe(popen(cmd, "r"), pclose);
if (!pipe) {
throw std::runtime_error("popen() failed!");
}
while (fgets(buffer.data(), buffer.size(), pipe.get()) != nullptr) {
result += buffer.data();
}
return result;
}
int main() {
try {
std::string output = exec("ls -l");
std::cout <<(output);
} catch (const std::runtime_error& e) {
std::cerr << "Error: " << e.what() << std::endl;
return EXIT_FAILURE;
}
return EXIT_SUCCESS;
}
向命令写入输入示例:
#include <cstdio>
#include <iostream>
#include <memory>
#include <stdexcept>
#include <string>
int exec(const char* cmd, const char* input) {
int pipefd[2];
if (pipe(pipefd) == -1) {
throw std::runtime_error("pipe() failed!");
}
pid_t pid = fork();
if (pid == -1) {
throw std::runtime_error("fork() failed!");
} else if (pid == 0) { // 子进程
close(pipefd[0]); // 不需要读取端
// 将标准输入重定向到管道写端
dup2(pipefd[1], STDIN_FILENO);
close(pipefd[1]);
// 执行命令
execl("/bin/sh", "sh", "-c", cmd, (char*)NULL);
// 如果 execl 返回,表示失败
perror("execl");
exit(EXIT_FAILURE);
} else { // 父进程
close(pipefd[1]); // 不需要写入端
char buffer[128];
ssize_t count;
while ((count = read(pipefd[0], buffer, sizeof(buffer)-1)) > 0) {
buffer[count] = '\0';
std::cout << buffer;
}
if (count == -1) {
throw std::runtime_error("read() failed!");
}
int status;
waitpid(pid, &status, 0); // 等待子进程结束
if (WIFEXITED(status)) {
return WEXITSTATUS(status);
}
}
return EXIT_SUCCESS;
}
int main() {
try {
std::string output = exec("grep Hello", "Hello\nWorld\nHello C++");
std::cout <<(output);
} catch (const std::runtime_error& e) {
std::cerr << "Error: " << e.what() << std::endl;
return EXIT_FAILURE;
}
return EXIT_SUCCESS;
}
fork()
和 exec()
系列函数通过 fork()
创建子进程,并使用 exec()
系列函数在子进程中执行命令。这种方法提供了更高的灵活性,但实现起来更复杂。
#include <iostream>
#include <unistd.h>
#include <sys/wait.h>
int main() {
pid_t pid = fork();
if (pid == -1) {
// 创建子进程失败
perror("fork");
return EXIT_FAILURE;
} else if (pid == 0) { // 子进程
// 执行命令,例如 ls -l
execl("/bin/ls", "ls", "-l", (char*)NULL);
// 如果 execl 返回,表示失败
perror("execl");
return EXIT_FAILURE;
} else { // 父进程
int status;
// 等待子进程结束
waitpid(pid, &status, 0);
if (WIFEXITED(status)) {
std::cout << "子进程退出,状态码:" << WEXITSTATUS(status) << std::endl;
}
}
return EXIT_SUCCESS;
}
std::filesystem
(适用于文件系统操作)虽然 std::filesystem
不是直接用于执行系统命令,但它提供了丰富的文件和目录操作功能,可以减少对系统命令的依赖。
#include <iostream>
#include <filesystem>
namespace fs = std::filesystem;
int main() {
for (const auto& entry : fs::directory_iterator("/path/to/directory")) {
std::cout << entry.path() << std::endl;
}
return EXIT_SUCCESS;
}
根据具体需求选择合适的方法:
system()
。popen()
或 fork()
+ exec()
。fork()
+ exec()
系列函数。std::filesystem
。通过合理选择和使用这些方法,可以在 C++ 程序中有效地调用系统命令,同时确保代码的安全性和可靠性。