在c ++中从实例化进程获取输出的可靠方法是什么?

问题描述 投票:0回答:1

基本上我想要做的是在Linux shell中实例化一个程序,并将它发出的输出到stdout到字符串或字符串列表中(每行,取决于)。我想在我的c ++应用程序中运行的程序只是一个ps aux

  • 我发现的所有“解决方案”并没有完全解决我的问题。其中大多数都属于this answer所描述的错误。基本上popen失败,并且不会从shell执行返回完整的输出。为了这个问题,我们称之为“错误1”。

到目前为止我尝试过的:

1)使用boost,我按照他们的documentation尝试了这个:

#include <boost/process.hpp>
namespace bp = boost::process;
bool is_process_running(std::string p_name){
    string cmd = "ps aux";
    bp::ipstream out;
    std::string line;
    bp::child c(cmd, bp::std_out > out);

    // the while is supposed to read each line of the output
    // but the execution doesn't even enter the while
    while(c.running() && std::getline(out, line) && !line.empty())
    {
        if(line.find(p_name) != std::string::npos)
        {
            return true;
        }
    }
    c.wait();
    return false;
}

2)我也尝试过:

bool is_process_running(std::string p_name){
    string cmd = "ps aux";
    std::array<char, 256> buffer;
    std::shared_ptr<FILE> pipe(popen(cmd.c_str(), "r"), pclose);
    if (!pipe) throw std::runtime_error("popen() failed!");
    while (!feof(pipe.get())) {
        if (fgets(buffer.data(), 256, pipe.get()) != nullptr)
        {
            // here the line comes incomplete
            std::string line(buffer.data());
            if(line.find(p_name) != std::string::npos)
            {
                return true;
            }

        }
    }
    return false;
}

但最后一个也陷入了“错误1”。

3)This code snippet落入“错误1” 4)This one也陷入了“错误1” 我不是这个有必要把3)和4)的代码放在一起,因为它确实是这些答案中的内容,我没有改变任何东西,但如果你们需要我可以编辑我的问题。所以我的问题就是这个,如何以一种有效的方式获得命令输出?提前致谢。

编辑:我尝试过提供的代码剪切:

bool is_process_running(std::string p_name)
    FILE* p = popen(cmd.c_str(), "r");
    if (!p) { cerr << "oops"; return 2; }
    char line[500];
    while (fgets(line, 500, p))
    {
        std::string linha(line);
        if(linha.find(p_name) != std::string::npos)
            return true;
    }
    fclose(p);
    return false;
}

在这种情况下,这是popen / fgets截断输出的示例:

[fabio ~]$ ps aux | grep 391
root       391  0.0  0.1  48580 12864 ?        Ss   Sep03   0:06 /usr/lib/systemd/systemd-journald
fabio 15435  0.0  0.0 112548   960 pts/2    S+   15:40   0:00 grep --color=auto 391

流程391的行与此一样,但在运行时它只返回"root 391 0.0 0.1 48580 12856 ? Ss Sep03 0:06 /usr/lib/system\n"

c++ centos7 c++17
1个回答
2
投票

直接使用相关的系统调用:pipe(2)fork(2)dup2(2)close(2)execve(2)waitpid(2)。阅读一些很好的Linux编程书(也许是旧的ALP,它有几个与你的问题相关的章节)。寻找其他自由软件程序的源代码的灵感来源于管道(例如sash等一些简单的shell)和/或libc代码中的musl-libc(或popen,它具有非常易读的代码)。

我们没有足够的空间和时间来详细解释,但您可以在Web上找到许多资源,ALP可以免费下载;当然,execve是最后一次在子进程中运行的系统调用,因为它正在重新初始化虚拟地址空间。

从管道读取而不限制线路长度。要么手动使用read(2)(并关心缓冲),要么考虑getline(3)(另见fdopen(3)

您可能对POCOQt等框架感兴趣。

你可能想要避免popen(3)(你不需要使用/bin/sh的东西,除非你的命令需要扩展为globbing;参见glob(7))。

注意signal(7)signal-safety(7)(也许poll(2) ......)


我想在我的c ++应用程序中运行的程序只是一个ps aux

然后你可能应该not运行任何外部过程,但直接访问/proc/(请参阅proc(5);你需要opendir(3)readdir(3)等...)或者可能通过一些libproc。当然ps aux本身正在访问/proc/(因此除了通过运行ps的一些简单性之外你不会获得任何东西,并且通过使用它会失去一些性能和一些稳健性)。另见thisthisthisthisthis答案。

在你提到的评论中

我需要知道某些进程是否正在运行,同时给出它的名称和参数。

这是以编程方式访问/proc/的一个很好的例子:使用/proc/循环opendir目录,循环readdirenddir。对于readdir给出的每个条目,检查它是否有数字名称(以数字开头),否则跳过它。使用该数字名称(例如1234)构造一个像/proc/1234/cmdlineopen it then parse its content(它已经分离NUL字节)的路径。这可能不比启动ps aux进程,获取和解析其输出更难,并且肯定更有效。 (要了解细节,请运行od -cx /proc/self/cmdline然后od -cx /proc/$(pidof systemd-journald)/cmdline并了解其输出)。

© www.soinside.com 2019 - 2024. All rights reserved.