在 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++ 程序中有效地調用系統命令,同時確保代碼的安全性和可靠性。