---
title: "Módulo std::process em Rust"
url: "https://rustlang.com.br/stdlib/process-module/"
markdown_url: "https://rustlang.com.br/stdlib/process-module.MD"
description: "Referência completa do módulo std::process em Rust: Command, arg, output, spawn, status, piping stdin/stdout/stderr, exit e abort."
date: "2026-02-23"
author: "Equipe Rust Brasil"
---

# Módulo std::process em Rust

Referência completa do módulo std::process em Rust: Command, arg, output, spawn, status, piping stdin/stdout/stderr, exit e abort.


# Módulo std::process em Rust

O módulo `std::process` permite executar programas externos, capturar sua saída, enviar dados via stdin, verificar o código de saída e controlar o ciclo de vida de processos filhos. O tipo central é `Command`, que fornece um builder para construir e executar comandos do sistema operacional.

## Visão geral e tipos-chave

### Command

`Command` é o builder principal para executar processos. Permite configurar:
- O programa a executar e seus argumentos
- Variáveis de ambiente
- Diretório de trabalho
- Redirecionamento de stdin, stdout e stderr

### Formas de execução

| Método | Bloqueia? | Retorno | Uso |
|---|---|---|---|
| `output()` | Sim | `io::Result<Output>` | Captura toda saída (stdout + stderr) |
| `status()` | Sim | `io::Result<ExitStatus>` | Apenas código de saída |
| `spawn()` | Não | `io::Result<Child>` | Processo filho assíncrono |

### Tipos auxiliares

- **`Output`** — contém `stdout: Vec<u8>`, `stderr: Vec<u8>` e `status: ExitStatus`
- **`ExitStatus`** — código de saída (`.success()`, `.code()`)
- **`Child`** — processo filho em execução (`.wait()`, `.kill()`, handles de I/O)
- **`Stdio`** — configuração de stdin/stdout/stderr (`piped()`, `null()`, `inherit()`)

## Padrões comuns com código

### Executar comando e capturar saída

```rust
use std::process::Command;
use std::io;

fn main() -> io::Result<()> {
    // output() executa e captura tudo
    let saida = Command::new("ls")
        .arg("-la")
        .arg("/tmp")
        .output()?;

    if saida.status.success() {
        let stdout = String::from_utf8_lossy(&saida.stdout);
        println!("Saída:\n{}", stdout);
    } else {
        let stderr = String::from_utf8_lossy(&saida.stderr);
        eprintln!("Erro (código {:?}):\n{}", saida.status.code(), stderr);
    }

    Ok(())
}
```

### Verificar apenas o status

```rust
use std::process::Command;
use std::io;

fn main() -> io::Result<()> {
    // status() descarta a saída, retorna apenas o código
    let status = Command::new("cargo")
        .args(["build", "--release"])
        .status()?;

    if status.success() {
        println!("Build concluído com sucesso");
    } else {
        eprintln!("Build falhou com código: {:?}", status.code());
        std::process::exit(1);
    }

    Ok(())
}
```

### Processo em background com spawn

```rust
use std::process::Command;
use std::io;

fn main() -> io::Result<()> {
    // spawn() retorna imediatamente com handle do processo filho
    let mut filho = Command::new("sleep")
        .arg("5")
        .spawn()?;

    println!("Processo filho PID: {}", filho.id());
    println!("Fazendo outras coisas enquanto espera...");

    // Esperar o processo terminar
    let status = filho.wait()?;
    println!("Processo terminou com: {:?}", status.code());

    Ok(())
}
```

## Tabela de métodos e funções

### Command (builder)

| Método | Descrição |
|---|---|
| `Command::new(programa)` | Cria comando para o programa |
| `arg(valor)` | Adiciona um argumento |
| `args(valores)` | Adiciona múltiplos argumentos |
| `env(chave, valor)` | Define variável de ambiente |
| `envs(pares)` | Define múltiplas variáveis |
| `env_remove(chave)` | Remove variável de ambiente |
| `env_clear()` | Remove todas as variáveis herdadas |
| `current_dir(path)` | Define diretório de trabalho |
| `stdin(cfg)` | Configura stdin (Stdio) |
| `stdout(cfg)` | Configura stdout (Stdio) |
| `stderr(cfg)` | Configura stderr (Stdio) |
| `output()` | Executa e captura saída |
| `status()` | Executa e retorna status |
| `spawn()` | Inicia processo e retorna Child |

### Child (processo filho)

| Método | Descrição |
|---|---|
| `id()` | PID do processo |
| `wait()` | Espera terminar, retorna ExitStatus |
| `wait_with_output()` | Espera e captura saída |
| `kill()` | Envia SIGKILL (encerra forçado) |
| `try_wait()` | Verifica sem bloquear |
| `stdin` | `Option<ChildStdin>` — pipe de entrada |
| `stdout` | `Option<ChildStdout>` — pipe de saída |
| `stderr` | `Option<ChildStderr>` — pipe de erro |

### Stdio

| Construtor | Descrição |
|---|---|
| `Stdio::piped()` | Cria pipe entre pai e filho |
| `Stdio::null()` | Descarta (equivale a /dev/null) |
| `Stdio::inherit()` | Herda do processo pai (padrão) |

### Funções de controle do processo

| Função | Descrição |
|---|---|
| `process::exit(code)` | Encerra com código (roda destrutores) |
| `process::abort()` | Aborta imediatamente (sem destrutores) |
| `process::id()` | PID do processo atual |

## Exemplos práticos

### Exemplo 1: Piping entre processos (equivale a `cmd1 | cmd2`)

```rust
use std::io::{self, Write};
use std::process::{Command, Stdio};

fn main() -> io::Result<()> {
    // Equivalente a: echo "olá mundo\nrust é legal\nadeus" | grep "rust"

    let mut echo = Command::new("echo")
        .arg("olá mundo\nrust é legal\nadeus")
        .stdout(Stdio::piped())
        .spawn()?;

    let echo_stdout = echo.stdout.take().expect("stdout não capturado");

    let grep = Command::new("grep")
        .arg("rust")
        .stdin(echo_stdout) // stdin do grep = stdout do echo
        .output()?;

    echo.wait()?;

    let resultado = String::from_utf8_lossy(&grep.stdout);
    println!("Resultado do pipe: {}", resultado.trim());

    Ok(())
}
```

### Exemplo 2: Enviar dados para stdin do processo filho

```rust
use std::io::{self, Write};
use std::process::{Command, Stdio};

fn executar_python(codigo: &str) -> io::Result<String> {
    let mut processo = Command::new("python3")
        .arg("-c")
        .arg(codigo)
        .stdout(Stdio::piped())
        .stderr(Stdio::piped())
        .spawn()?;

    let saida = processo.wait_with_output()?;

    if saida.status.success() {
        Ok(String::from_utf8_lossy(&saida.stdout).to_string())
    } else {
        let erro = String::from_utf8_lossy(&saida.stderr);
        Err(io::Error::new(
            io::ErrorKind::Other,
            format!("Python falhou: {}", erro),
        ))
    }
}

fn alimentar_stdin(programa: &str, dados: &str) -> io::Result<String> {
    let mut filho = Command::new(programa)
        .stdin(Stdio::piped())
        .stdout(Stdio::piped())
        .stderr(Stdio::piped())
        .spawn()?;

    // Escrever dados no stdin do processo filho
    if let Some(mut stdin) = filho.stdin.take() {
        stdin.write_all(dados.as_bytes())?;
        // stdin é fechado automaticamente quando sai de escopo (drop)
    }

    let saida = filho.wait_with_output()?;
    Ok(String::from_utf8_lossy(&saida.stdout).to_string())
}

fn main() -> io::Result<()> {
    // Executar código Python
    match executar_python("print(sum(range(100)))") {
        Ok(resultado) => println!("Python diz: {}", resultado.trim()),
        Err(e) => eprintln!("Erro: {}", e),
    }

    // Enviar dados para sort via stdin
    let dados = "banana\nmaça\nuva\nabacaxi\nlaranja\n";
    let ordenado = alimentar_stdin("sort", dados)?;
    println!("Ordenado:\n{}", ordenado);

    Ok(())
}
```

### Exemplo 3: Executor de comandos com timeout

```rust
use std::io;
use std::process::Command;
use std::time::{Duration, Instant};
use std::thread;

struct ResultadoComando {
    stdout: String,
    stderr: String,
    codigo: Option<i32>,
    duracao: Duration,
    timeout: bool,
}

fn executar_com_timeout(
    programa: &str,
    args: &[&str],
    timeout: Duration,
) -> io::Result<ResultadoComando> {
    let inicio = Instant::now();

    let mut filho = Command::new(programa)
        .args(args)
        .stdout(std::process::Stdio::piped())
        .stderr(std::process::Stdio::piped())
        .spawn()?;

    // Verificar periodicamente se terminou
    loop {
        match filho.try_wait()? {
            Some(status) => {
                let saida = filho.wait_with_output()?;
                return Ok(ResultadoComando {
                    stdout: String::from_utf8_lossy(&saida.stdout).to_string(),
                    stderr: String::from_utf8_lossy(&saida.stderr).to_string(),
                    codigo: status.code(),
                    duracao: inicio.elapsed(),
                    timeout: false,
                });
            }
            None => {
                if inicio.elapsed() > timeout {
                    filho.kill()?;
                    filho.wait()?;
                    return Ok(ResultadoComando {
                        stdout: String::new(),
                        stderr: format!("Timeout após {:?}", timeout),
                        codigo: None,
                        duracao: inicio.elapsed(),
                        timeout: true,
                    });
                }
                thread::sleep(Duration::from_millis(100));
            }
        }
    }
}

fn main() -> io::Result<()> {
    let resultado = executar_com_timeout("ls", &["-la", "/"], Duration::from_secs(5))?;

    if resultado.timeout {
        eprintln!("Comando excedeu o timeout!");
    } else {
        println!("Saída ({:?}, código {:?}):", resultado.duracao, resultado.codigo);
        println!("{}", resultado.stdout);
    }

    Ok(())
}
```

### Exemplo 4: Build script que executa múltiplos comandos

```rust
use std::io;
use std::process::{Command, ExitStatus};

fn executar(descricao: &str, programa: &str, args: &[&str]) -> io::Result<ExitStatus> {
    println!("\n--- {} ---", descricao);
    println!("$ {} {}", programa, args.join(" "));

    let status = Command::new(programa)
        .args(args)
        .status()?;

    if !status.success() {
        eprintln!("FALHA: {} retornou {:?}", programa, status.code());
    }

    Ok(status)
}

fn pipeline_build(projeto: &str) -> io::Result<bool> {
    let passos: Vec<(&str, &str, Vec<&str>)> = vec![
        ("Verificar formatação", "cargo", vec!["fmt", "--check"]),
        ("Analisar código", "cargo", vec!["clippy", "--", "-D", "warnings"]),
        ("Executar testes", "cargo", vec!["test"]),
        ("Build de release", "cargo", vec!["build", "--release"]),
    ];

    println!("=== Pipeline de build para '{}' ===", projeto);

    for (descricao, programa, args) in &passos {
        let status = executar(descricao, programa, args)?;
        if !status.success() {
            eprintln!("\nPipeline falhou em: {}", descricao);
            return Ok(false);
        }
    }

    println!("\n=== Pipeline concluído com sucesso ===");
    Ok(true)
}

fn main() {
    match pipeline_build("meu_projeto") {
        Ok(true) => std::process::exit(0),
        Ok(false) => std::process::exit(1),
        Err(e) => {
            eprintln!("Erro no pipeline: {}", e);
            std::process::exit(2);
        }
    }
}
```

### Exemplo 5: Capturar saída em tempo real (streaming)

```rust
use std::io::{self, BufRead, BufReader};
use std::process::{Command, Stdio};

fn executar_streaming(programa: &str, args: &[&str]) -> io::Result<i32> {
    let mut filho = Command::new(programa)
        .args(args)
        .stdout(Stdio::piped())
        .stderr(Stdio::piped())
        .spawn()?;

    // Ler stdout em tempo real
    let stdout = filho.stdout.take().expect("stdout não capturado");
    let stderr = filho.stderr.take().expect("stderr não capturado");

    let stdout_thread = std::thread::spawn(move || {
        let leitor = BufReader::new(stdout);
        for linha in leitor.lines() {
            if let Ok(l) = linha {
                println!("[STDOUT] {}", l);
            }
        }
    });

    let stderr_thread = std::thread::spawn(move || {
        let leitor = BufReader::new(stderr);
        for linha in leitor.lines() {
            if let Ok(l) = linha {
                eprintln!("[STDERR] {}", l);
            }
        }
    });

    let status = filho.wait()?;
    stdout_thread.join().unwrap();
    stderr_thread.join().unwrap();

    Ok(status.code().unwrap_or(-1))
}

fn main() -> io::Result<()> {
    println!("Executando 'cargo test' com saída em tempo real:");
    let codigo = executar_streaming("cargo", &["test"])?;
    println!("\nProcesso terminou com código: {}", codigo);
    Ok(())
}
```

## Padrões de tratamento de erro para I/O

### Programa não encontrado

```rust
use std::io;
use std::process::Command;

fn executar_seguro(programa: &str, args: &[&str]) -> io::Result<String> {
    match Command::new(programa).args(args).output() {
        Ok(saida) => {
            if saida.status.success() {
                Ok(String::from_utf8_lossy(&saida.stdout).to_string())
            } else {
                let stderr = String::from_utf8_lossy(&saida.stderr);
                Err(io::Error::new(
                    io::ErrorKind::Other,
                    format!("{} falhou ({}): {}", programa, saida.status, stderr.trim()),
                ))
            }
        }
        Err(e) if e.kind() == io::ErrorKind::NotFound => {
            Err(io::Error::new(
                io::ErrorKind::NotFound,
                format!(
                    "Programa '{}' não encontrado. Verifique se está instalado e no PATH.",
                    programa
                ),
            ))
        }
        Err(e) if e.kind() == io::ErrorKind::PermissionDenied => {
            Err(io::Error::new(
                io::ErrorKind::PermissionDenied,
                format!("Sem permissão para executar '{}'", programa),
            ))
        }
        Err(e) => Err(e),
    }
}
```

### exit() vs abort()

```rust
use std::process;

fn encerrar_limpo() {
    // exit() roda destrutores e handlers de saída
    // Código 0 = sucesso, != 0 = erro
    process::exit(0);
}

fn encerrar_emergencia() {
    // abort() termina imediatamente — sem destrutores, sem cleanup
    // Use apenas em situações críticas (corrupção de memória, etc.)
    process::abort();
}
```

## Dicas de desempenho

- **Use `status()` se não precisar da saída** — evita alocações de `Vec<u8>` para stdout/stderr.
- **Feche o stdin** do processo filho o mais cedo possível (via `drop()`) — alguns programas esperam EOF no stdin para começar a processar.
- **Para múltiplos comandos encadeados**, considere executar via `sh -c "cmd1 | cmd2"` em vez de construir pipes manualmente.
- **Prefira `spawn()` + `wait_with_output()`** a `output()` quando precisar enviar dados para stdin — `output()` não permite acesso ao stdin.

## Veja também

- [Módulo std::io](/stdlib/io-module/) — traits usadas pelos handles de I/O do processo
- [stdin, stdout e stderr](/stdlib/stdin-stdout/) — I/O padrão do próprio processo
- [Módulo std::env](/stdlib/env-module/) — variáveis de ambiente e argumentos CLI
- [Ler Argumentos CLI](/receitas/ler-argumentos-cli/) — receita para parsing de argumentos
- Documentação oficial: [`std::process`](https://doc.rust-lang.org/std/process/)
