如何在使用POSIX的C++中执行命令并获取命令输出?

592

我正在寻找一种方法,在C++程序内运行命令并获取其输出。我已经尝试使用system()函数,但那只会执行一个命令。以下是我想要的示例:

std::string result = system("./some_command");

我需要运行任意命令并获取其输出。我查看了boost.org,但是我没有找到能够满足我的需求的内容。


3
请参考以下问题的答案:https://dev59.com/6lQK5IYBdhLWcg3wQdvI。该问题的回答扩展了下面这个很好的答案,提供了获取return codestderr和本回答已经解释的stdout的方法。请注意,不要更改原始意思,并尽可能使翻译通俗易懂。 - code_fodder
8
@code_fodder,您可以创建一个指向https://dev59.com/6lQK5IYBdhLWcg3wQdvI的链接。 - Jonas Stein
1
以下是5个关于C和/或C++的问题和答案,似乎涉及到这个主题:1)如何在C中从stdout读取,2)C:运行系统命令并获取输出?,3)如何从C运行外部程序并解析其输出?,4)最优地捕获system()命令的stdout,5)(本问题)。 - Gabriel Staples
12个回答

5

运行脚本后,您可以使用管道获取输出。当我们想要子进程的输出时,我们使用管道。

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中,然后你可以将所有内容从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和进程控制 获取更多信息。

4
C++流的实现,参考自waqas的答案:
#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

如果您想要同时捕获 stdoutstderr,则命令应该如下所示:
sh -c '<your-command>' 2>&1

需要添加 #include <array> 并移除 , fd 以使其编译。 - truf

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接