DEV Community

Cover image for Execute Comandos da Shell com Boost.Process
Marcos Oliveira
Marcos Oliveira

Posted on

1

Execute Comandos da Shell com Boost.Process

Mais segurança, portabilidade e controle do que a std::system.


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.


Comparação com a std::system

1. Mais Controle sobre o Processo

Com boost::process, você pode:

  • Capturar saída e entrada (std::system não permite isso diretamente).
  • Definir variáveis de ambiente.
  • Trabalhar com processos assíncronos (std::system é sempre bloqueante).
  • Especificar diretórios de trabalho.

2. Segurança

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());  
Enter fullscreen mode Exit fullscreen mode

Com Boost.Process, você passa argumentos separadamente, evitando problemas de injeção:

boost::process::child c("ls", "-l");
Enter fullscreen mode Exit fullscreen mode

3. Portabilidade

  • 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.

4. Execução Assíncrona

  • std::system() bloqueia a execução até que o processo termine.
  • Com Boost, você pode rodar processos em paralelo sem travar seu programa:
boost::process::child c("long_task");
c.detach(); // Continua a execução sem esperar
Enter fullscreen mode Exit fullscreen mode

5. Manipulação Direta de Entrada/Saída

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;
}
Enter fullscreen mode Exit fullscreen mode

Com std::system(), você precisaria de pipes manuais, o que é mais trabalhoso.

Quando Usar Cada Um?

✅ 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.


Instalação e Exemplos de Uso

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

Exemplo básico

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;
}
Enter fullscreen mode Exit fullscreen mode

Para compilar não precisa de nenhuma flag adicional, basta compilar normalmente e rodar:

g++ main.cpp
./a.out
Enter fullscreen mode Exit fullscreen mode

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);
Enter fullscreen mode Exit fullscreen mode

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);
Enter fullscreen mode Exit fullscreen mode

Isso lista com detalhes todos os arquivos com extensão Markdown no diretório que você executar o binário.


Outro exemplo

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;
}
Enter fullscreen mode Exit fullscreen mode

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.


Limitações

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;
}
Enter fullscreen mode Exit fullscreen mode

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.

Hostinger image

Get n8n VPS hosting 3x cheaper than a cloud solution

Get fast, easy, secure n8n VPS hosting from $4.99/mo at Hostinger. Automate any workflow using a pre-installed n8n application and no-code customization.

Start now

Top comments (0)

Playwright CLI Flags Tutorial

5 Playwright CLI Flags That Will Transform Your Testing Workflow

  • 0:56 --last-failed: Zero in on just the tests that failed in your previous run
  • 2:34 --only-changed: Test only the spec files you've modified in git
  • 4:27 --repeat-each: Run tests multiple times to catch flaky behavior before it reaches production
  • 5:15 --forbid-only: Prevent accidental test.only commits from breaking your CI pipeline
  • 5:51 --ui --headed --workers 1: Debug visually with browser windows and sequential test execution

Learn how these powerful command-line options can save you time, strengthen your test suite, and streamline your Playwright testing experience. Click on any timestamp above to jump directly to that section in the tutorial!

Watch Full Video 📹️

👋 Kindness is contagious

Engage with a wealth of insights in this thoughtful article, valued within the supportive DEV Community. Coders of every background are welcome to join in and add to our collective wisdom.

A sincere "thank you" often brightens someone’s day. Share your gratitude in the comments below!

On DEV, the act of sharing knowledge eases our journey and fortifies our community ties. Found value in this? A quick thank you to the author can make a significant impact.

Okay