首页 > 解决方案 > 如果命令的结果很长,`boost::process::child` 将挂起

问题描述

我有一个简单的 C++ 程序,用于boost::process:child接收终端命令并执行它,然后打印出结果。但是,如果我执行类似的命令ps aux,整个程序将没有响应。我不确定如何解决。我试过调试它,调试器只会停在cp.wait().

try{
        child cp(cmd+" "+param, (std_out & std_err) > pipe);
        cp.wait();
        return_code = cp.exit_code();
}catch (process_error e){
        return_code = -1;
}

标签: c++boost

解决方案


您需要消耗管道。管道连接到什么(换句话说,谁在使用它?)。

如果看起来确实如此,您对输出根本不感兴趣,只需重定向到 null 设备:

作为旁注,我强烈反对using namespace boost::process,因为它看起来像你正在做的。该命名空间中有许多名称很容易与 C/标准库名称发生冲突。例如,是pipe局部变量吗?是类型boost::process::pipe吗?是 POSIX 系统库调用::pipe吗?

使固定

住在科利鲁

#include <boost/process.hpp>
#include <iostream>

int main()
{
    namespace bp    = boost::process;
    std::string cmd = "cat", param = "/etc/dictionaries-common/words";
    //bp::pipe pipe;

    int return_code = -1;
    try {
        bp::child cp(cmd + " " + param, (bp::std_out & bp::std_err) > bp::null);
        cp.wait();
        return_code = cp.exit_code();
    } catch (bp::process_error const& e) {
        return_code = -1;
    }

    std::cout << "return_code: " << return_code << "\n";
    return return_code;
}

请注意,它会1在 Coliru 上返回,因为该字典不存在。在我的系统上它正确返回0(没有阻塞。

安全

请注意,将命令拼凑成字符串可能非常容易出错并引发安全漏洞(如果传入的文件名是“foot.txt; rm -rf *”怎么办?)。

我会使用参数向量样式:

    std::string              cmd = "cat";
    std::vector<std::string> params{"-n", "--",
                                    "/etc/dictionaries-common/words"};

    bp::child cp(bp::search_path(cmd), params,
                 (bp::std_out & bp::std_err) > bp::null);

更安全的是不使用search_path,但它要求 exe 是完全指定的路径(如/bin/cator ./bin/myexe)。

请注意,现在接受来自外部输入的文件名已经足够安全了:

    std::vector<std::string> params{"-n", "--"};
    params.insert(end(params), argv + 1, argv + argc);

作为画龙点睛的一笔,让我们关闭子进程的标准输入(这样我们就不会在那里泄露隐私,如果命令行上没有列出文件也不会挂起......):

住在科利鲁

#include <boost/process.hpp>
#include <iostream>

int main(int argc, char** argv)
{
    namespace bp    = boost::process;
    int return_code = -1;

    try {
        std::string              cmd = "/bin/cat";
        std::vector<std::string> params{"-n", "--"};
        params.insert(end(params), argv + 1, argv + argc);

        bp::child cp(cmd, params,        //
                     bp::std_in.close(), //
                     (bp::std_out & bp::std_err) > bp::null);

        cp.wait();
        return_code = cp.exit_code();
    } catch (bp::process_error const& e) {
        return_code = -1;
    }

    std::cout << "return_code: " << return_code << "\n";
    return return_code;
}

现在它打印return_code: 0了,因为文件实际上存在于 Coliru 上。


推荐阅读