【问题标题】:boost::process environment not being propagatedboost::process 环境没有被传播
【发布时间】:2022-10-04 20:43:43
【问题描述】:

我正在尝试运行一个使用环境变量进行身份验证的外部命令。

为此,我使用boost::process

namespace bp = boost::process;

std::string exec_bp(const std::string& cmd)
{
    bp::ipstream pipe;
    bp::child c(cmd, bp::std_out > pipe, boost::this_process::environment());

    return std::string(std::istreambuf_iterator<char>(pipe), {});
}

然而,这不起作用。我得到一个异常execve failed,因为我试图运行的命令找不到它需要的环境变量。

如果我只使用popen 运行命令并读取它的标准输出(per this answer),它就可以工作。

std::string exec_popen(const std::string& cmd)
{
    std::array<char, 128> buffer;
    std::string result;
    std::unique_ptr<FILE, decltype(&pclose)> pipe(popen(cmd.c_str(), "r"), pclose);
    if (!pipe)
        throw std::runtime_error("popen() failed!");
    while (fgets(buffer.data(), buffer.size(), pipe.get()) != nullptr)
        result += buffer.data();
    return result;
}

例如,我在这里运行aws 命令行客户端来列出 S3 中的一些文件:

const std::string cmd = "aws s3 ls s3://foo/bar";

try
{
    auto s = exec_bp(cmd);
    std::cout << "exec_bp:\n" << s << '\n';
}
catch(const std::exception& e)
{
    std::cout << "exec_bp failed; " << e.what() << '\n';
}

try
{
    auto s = exec_popen(cmd);
    std::cout << "exec_popen:\n" << s << '\n';
}
catch(const std::exception& e)
{
    std::cout << "exec_popen failed; " << e.what() << '\n';
}

输出:

$ ./a.out  | head
exec_bp failed; execve failed: Permission denied
exec_popen:
2021-07-05 17:35:08    2875777 foo1.gz
2021-07-05 17:35:09    4799065 foo2.gz
2021-07-05 17:35:10    3981241 foo3.gz
  • 为什么将boost::this_process::environment() 传递给boost::process::child 不会传播我的进程环境?
  • 如何使用boost::process 来执行我的命令?

【问题讨论】:

  • 我看到你得到异常执行失败,但是我没有看到任何迹象表明因为我试图运行的命令找不到它需要的环境变量.如果 execve 失败,则根本不会执行命令,因此它没有机会检查环境变量。您应该尝试启动进程正确分离可执行名称和参数,例如bp::child c(bp::search_path("aws"), "s3" ...);

标签: c++ boost boost-process


【解决方案1】:

要模仿 shell 的搜索路径行为,请使用 boost::process::search_path

要模仿外壳,请使用例如

bp::child c("/usr/bin/bash",
    std::vector<std::string>{"-c", "aws s3 ls s3://foo/bar"},
    // ...

请注意,这通常不利于安全。相反,考虑更直接的

bp::child c("/usr/local/bin/aws",
    std::vector<std::string>{"s3", "ls", "s3://foo/bar"},
    // ...

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2021-05-19
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-12-15
    • 2021-11-16
    • 2017-06-25
    相关资源
    最近更新 更多