Boost.Process é uma biblioteca C++ da Boost que facilita a criação e gerenciamento de processos externos, permitindo executar programas, capturar saídas e manipular entradas e erros de forma eficiente.
Ela oferece uma interface moderna e flexível para trabalhar com processos, encapsulando detalhes de implementação de sistemas operacionais e fornecendo funcionalidades como execução assíncrona, comunicação entre processos(IPC), controle de saída de streams e gerenciamento de ambiente de execução.
É ideal para aplicações que necessitam interagir com programas externos ou executar comandos do sistema de forma controlada e segura.
A Boost.Process foi criada para oferecer uma alternativa mais segura e flexível ao std::system()
, que tem várias limitações.
std::system
Com boost::process
, você pode:
std::system
não permite isso diretamente).std::system
é sempre bloqueante).O std::system()
executa comandos via um shell, o que pode ser perigoso se você estiver passando strings dinâmicas (risco de injeção de comandos).
Exemplo perigoso com std::system()
:
std::string user_input = "ls && rm -rf /"; // Se for injetado, pode ser catastrófico!
std::system(user_input.c_str());
Com Boost.Process, você passa argumentos separadamente, evitando problemas de injeção:
boost::process::child c("ls", "-l");
std::system()
depende do shell do sistema (cmd.exe
no Windows, /bin/sh
no Linux).boost::process
funciona de forma portável, sem depender do shell subjacente.std::system()
bloqueia a execução até que o processo termine.boost::process::child c("long_task");
c.detach(); // Continua a execução sem esperar
Com boost::process
, você pode redirecionar entrada/saída facilmente:
boost::process::ipstream out;
boost::process::child c("ls", boost::process::std_out > out);
std::string line;
while (std::getline(out, line)) {
std::cout << line << std::endl;
}
Com std::system()
, você precisaria de pipes manuais, o que é mais trabalhoso.
✅ Use Boost.Process se precisar de portabilidade, segurança, manipulação de I/O ou execução assíncrona.
⚠️ Use std::system()
apenas para comandos simples e rápidos onde segurança e controle não são problemas.
Para instalar a Boost.Process você pode seguir este artigo que nós fizemos que mostra tanto usando gerenciadores de pacotes, como também fazendo o download direto do endereço oficial da LibBoost: Conceito, Instalação e Exemplos de uso da biblioteca Boost
Nesse exemplo, mostra como rodar o comando ls
usando a Boost.Process:
Exemplo:
main.cpp
#include <boost/process.hpp>
#include <iostream>
#include <string>
namespace bp = boost::process;
int main() {
std::string output;
bp::ipstream pipe_stream; // Stream para capturar a saída
// Executa o comando "ls" e redireciona a saída para pipe_stream
bp::child c("ls", bp::std_out > pipe_stream);
// Lê a saída do comando linha por linha
std::string line;
while (std::getline(pipe_stream, line)) {
std::cout << line << std::endl;
}
c.wait(); // Aguarda o término do processo
return 0;
}
Para compilar não precisa de nenhuma flag adicional, basta compilar normalmente e rodar:
g++ main.cpp
./a.out
Se quiser usar com argumentos, substitua a linha: bp::child
por essa abaixo:
//bp::child c("ls", bp::std_out > pipe_stream);
bp::child c("ls", "-l", "*.md", bp::std_out > pipe_stream);
Em Shells que faz o uso de glob pode ser que você tenha um problema ao utilizar curingas, então use a bp::child
assim:
//bp::child c("ls", bp::std_out > pipe_stream);
bp::child c("/bin/sh", "-c", "ls -l *.md", bp::std_out > pipe_stream);
Isso lista com detalhes todos os arquivos com extensão Markdown no diretório que você executar o binário.
Esse exemplo exibe a versão do GNU GCC, caso você possua instalado no seu sistema, mas com um tratamento de falha mais adequado para o uso.
#include <boost/process.hpp>
#include <iostream>
#include <stdexcept>
using namespace boost::process;
int main() {
ipstream pipe_stream;
std::string line;
try {
child c("/usr/bin/gcc", args = { "--version" }, std_out > pipe_stream);
while (pipe_stream && std::getline(pipe_stream, line)) {
std::cerr << line << std::endl;
}
c.wait();
// Verifica se o processo foi bem sucedido
if (c.exit_code() != 0) {
throw std::runtime_error("Process failed with error code: " + std::to_string(c.exit_code()));
}
} catch (const std::exception& e) {
std::cerr << "Failed to execute command: " << e.what() << std::endl;
return 1;
}
return 0;
}
O ideal é informar o caminho completo do programa: /usr/bin/gcc
em vez de somente: gcc
, tente alterar e coloque só o comando do programa e veja que dará erro.
Assim como qualquer outra lib de subprocesso, alguns poucos comandos não funcionarão como esperado, pois pode ser um comando EMBUTIDO da Shell, como por exemplo: history
.
Nós já abordamos sobre isso nesse artigo: Usando C++ como Shell Script.
Apesar dele pode exibir o histórico, se você tentar limpar a sessão isso, com certeza, não vai funcionar. Isso acontece porque ele não é um executável separado. Quando você executa history -c
em um subprocesso, ele está em um novo shell que não compartilha o histórico da sua sessão principal.
Esse código abaixo não resulta em uma ação esperada:
#include <boost/process.hpp>
#include <iostream>
namespace bp = boost::process;
int main() {
std::string output;
bp::ipstream pipe_stream;
bp::child c("/bin/bash", "-c", "history -c && history -w", bp::std_out > pipe_stream);
std::string line;
while (std::getline(pipe_stream, line)) {
std::cout << line << std::endl;
}
c.wait();
return 0;
}
Caso ainda queira executar o comando, o código está correto(pode melhorar com tratamento de falhas como vimos), mas a saída não mostrará nada relevante, pois history -c
não gera saída e afeta apenas o subprocesso.
O comando history é um recurso embutido da Shell, e não um executável separado. Quando você executa
history -c
em um subprocesso, ele está em um novo shell que não compartilha o histórico da sua sessão principal.
Para mais informações consulte a documentação: https://www.boost.org/doc/libs/1_84_0/doc/html/process/reference.html.