我正在寻找一种方法来获得命令的输出,当它从c++程序中运行时。我已经看到了使用system()函数,但它只会执行一个命令。以下是我正在寻找的一个例子:
std::string result = system("./some_command");
我需要运行任意命令并获得其输出。我在boost.org上找过了,但是我还没有找到任何能满足我需要的东西。
我正在寻找一种方法来获得命令的输出,当它从c++程序中运行时。我已经看到了使用system()函数,但它只会执行一个命令。以下是我正在寻找的一个例子:
std::string result = system("./some_command");
我需要运行任意命令并获得其输出。我在boost.org上找过了,但是我还没有找到任何能满足我需要的东西。
当前回答
#include <cstdio>
#include <iostream>
#include <memory>
#include <stdexcept>
#include <string>
#include <array>
std::string exec(const char* cmd) {
std::array<char, 128> buffer;
std::string result;
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;
}
Pre-C + + 11版:
#include <iostream>
#include <stdexcept>
#include <stdio.h>
#include <string>
std::string exec(const char* cmd) {
char buffer[128];
std::string result = "";
FILE* pipe = popen(cmd, "r");
if (!pipe) throw std::runtime_error("popen() failed!");
try {
while (fgets(buffer, sizeof buffer, pipe) != NULL) {
result += buffer;
}
} catch (...) {
pclose(pipe);
throw;
}
pclose(pipe);
return result;
}
对于Windows,用_popen和_pclose替换popen和pclose。
其他回答
您可以在使用管道运行脚本后获得输出。当我们需要子进程的输出时,我们使用管道。
int my_func() {
char ch;
FILE *fpipe;
FILE *copy_fp;
FILE *tmp;
char *command = (char *)"/usr/bin/my_script my_arg";
copy_fp = fopen("/tmp/output_file_path", "w");
fpipe = (FILE *)popen(command, "r");
if (fpipe) {
while ((ch = fgetc(fpipe)) != EOF) {
fputc(ch, copy_fp);
}
}
else {
if (copy_fp) {
fprintf(copy_fp, "Sorry there was an error opening the file");
}
}
pclose(fpipe);
fclose(copy_fp);
return 0;
}
这就是你要运行的脚本。将它与脚本所接受的参数一起放在命令变量中(如果没有参数,就什么都没有)。以及您想要捕获脚本输出的文件,将其放在copy_fp中。
popen运行你的脚本并将输出放到fpipe中然后你可以将所有内容复制到输出文件中。
通过这种方式,您可以捕获子流程的输出。
另一个过程是你可以直接把>运算符放在命令中。因此,如果我们在运行命令时将所有内容都放在一个文件中,则不需要复制任何内容。
在这种情况下,不需要使用管道。您可以只使用system,它将运行命令并将输出放在该文件中。
int my_func(){
char *command = (char *)"/usr/bin/my_script my_arg > /tmp/my_putput_file";
system(command);
printf("everything saved in my_output_file");
return 0;
}
你可以阅读YoLinux教程:Fork, Exec和进程控制了解更多信息。
命令类使用system(“cmd > stdout 2> stderr”)为用户提供标准输出和标准输出,以及退出码。
测试运行:
./a.out 'ls .'
exit code: 0
stdout: HelloWorld
HelloWorld.c
HelloWorld.cpp
HelloWorld.dSYM
a.out
gcc_container.bash
linuxsys
macsys
test.sh
stderr:
#include <iostream>
#include <fstream>
#include <sstream>
#include <unistd.h>
using namespace std;
class Command {
public:
Command() {
exit_code_ = -1;
}
int GetExitCode() { return exit_code_;}
string GetStdOutStr() {return stdout_str_;}
string GetStdErrStr() {return stderr_str_;}
int Run(const char* cmd) {
return Run(string(cmd));
}
/**
* @brief run a given command
*
* @param cmd: command string
* @return int: the exit code of running the command
*/
int Run(string cmd) {
// create temp files
char tmp_dir[] = "/tmp/stdir.XXXXXX";
mkdtemp(tmp_dir);
string stdout_file = string(tmp_dir) + "/stdout";
string stderr_file = string(tmp_dir) + "/stderr";
// execute the command "cmd > stdout_file 2> stderr_file"
string cli = cmd + " > " + stdout_file + " 2> " + stderr_file;
exit_code_ = system(cli.c_str());
exit_code_ = WEXITSTATUS(exit_code_);
stdout_str_ = File2Str(stdout_file);
stderr_str_ = File2Str(stderr_file);
// rid of the temp files
remove(stdout_file.c_str());
remove(stderr_file.c_str());
remove(tmp_dir);
return exit_code_;
}
private:
int exit_code_;
string stderr_str_;
string stdout_str_;
/**
* @brief read a file
*
* @param file_name: file path
* @return string the contents of the file.
*/
string File2Str(string file_name) {
ifstream file;
stringstream str_stream;
file.open(file_name);
if (file.is_open()) {
str_stream << file.rdbuf();
file.close();
}
return str_stream.str();
}
};
int main(int argc, const char* argv[]) {
Command command;
command.Run(argv[1]);
cout << "exit code: " << command.GetExitCode() << endl;
cout << "stdout: " << command.GetStdOutStr() << endl;
cout << "stderr: " << command.GetStdErrStr() << endl;
return command.GetExitCode();
}
两种可能的方法:
我不认为popen()是c++标准的一部分(从内存来看,它是POSIX的一部分),但它在我使用过的每个UNIX上都可用(您似乎针对的是UNIX,因为您的命令是./some_command)。 在不存在popen()的情况下,您可以使用system("。/some_command >/tmp/some_command.out");,然后使用正常的I/O函数处理输出文件。
waqas的答案的c++流实现:
#include <istream>
#include <streambuf>
#include <cstdio>
#include <cstring>
#include <memory>
#include <stdexcept>
#include <string>
class execbuf : public std::streambuf {
protected:
std::string output;
int_type underflow(int_type character) {
if (gptr() < egptr()) return traits_type::to_int_type(*gptr());
return traits_type::eof();
}
public:
execbuf(const char* command) {
std::array<char, 128> buffer;
std::unique_ptr<FILE, decltype(&pclose)> pipe(popen(command, "r"), pclose);
if (!pipe) {
throw std::runtime_error("popen() failed!");
}
while (fgets(buffer.data(), buffer.size(), pipe.get()) != nullptr) {
this->output += buffer.data();
}
setg((char*)this->output.data(), (char*)this->output.data(), (char*)(this->output.data() + this->output.size()));
}
};
class exec : public std::istream {
protected:
execbuf buffer;
public:
exec(char* command) : std::istream(nullptr), buffer(command, fd) {
this->rdbuf(&buffer);
}
};
这段代码通过stdout捕获所有输出。如果你只想捕获stderr,那么像这样传递你的命令:
sh -c '<your-command>' 2>&1 > /dev/null
如果你想同时捕获stdout和stderr,那么命令应该是这样的:
sh -c '<your-command>' 2>&1
#include <cstdio>
#include <iostream>
#include <memory>
#include <stdexcept>
#include <string>
#include <array>
std::string exec(const char* cmd) {
std::array<char, 128> buffer;
std::string result;
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;
}
Pre-C + + 11版:
#include <iostream>
#include <stdexcept>
#include <stdio.h>
#include <string>
std::string exec(const char* cmd) {
char buffer[128];
std::string result = "";
FILE* pipe = popen(cmd, "r");
if (!pipe) throw std::runtime_error("popen() failed!");
try {
while (fgets(buffer, sizeof buffer, pipe) != NULL) {
result += buffer;
}
} catch (...) {
pclose(pipe);
throw;
}
pclose(pipe);
return result;
}
对于Windows,用_popen和_pclose替换popen和pclose。