Pipes: conectando comandos com |
1. O que é um Pipe e como funciona
O operador | (pipe) no Bash é um dos mecanismos mais poderosos e elegantes do Unix/Linux. Ele permite conectar a saída padrão (stdout) de um comando diretamente à entrada padrão (stdin) de outro comando, criando um fluxo contínuo de processamento de dados.
A metáfora do encanamento (pipe em inglês) é perfeita: assim como canos transportam água de um ponto a outro, os pipes no terminal transportam dados entre comandos. Cada comando no pipeline processa os dados recebidos e os passa adiante, criando uma cadeia de transformações.
O fluxo básico funciona da seguinte forma:
comando1 | comando2
Neste caso, tudo que comando1 escreve na saída padrão é automaticamente redirecionado para a entrada padrão de comando2, sem a necessidade de arquivos temporários.
2. Sintaxe básica e exemplos simples
A estrutura fundamental de um pipe é simples e direta:
comando1 | comando2
Exemplo clássico — listar apenas arquivos .txt no diretório atual:
ls -l | grep .txt
Aqui, ls -l lista todos os arquivos, e grep .txt filtra apenas as linhas que contêm ".txt".
Encadeamento de múltiplos pipes — você pode conectar quantos comandos desejar:
cat /var/log/syslog | grep "error" | head -10
Este comando:
1. Lê o arquivo de log (cat)
2. Filtra linhas com "error" (grep)
3. Mostra apenas as 10 primeiras ocorrências (head)
Exemplo prático — contar quantos usuários únicos estão logados:
who | cut -d' ' -f1 | sort | uniq | wc -l
3. Combinando Pipes com Redirecionamento
É importante entender a diferença entre | (pipe) e > (redirecionamento):
- | conecta a saída de um comando à entrada de outro
- > redireciona a saída para um arquivo
Uso simultâneo — é perfeitamente possível combinar ambos:
ps aux | grep apache > processos_apache.txt
Aqui, o pipe envia a saída de ps aux para grep apache, e o redirecionamento > salva o resultado filtrado em um arquivo.
Redirecionamento de stderr com pipes — por padrão, o pipe captura apenas stdout. Para incluir stderr:
comando 2>&1 | filtro
Ou de forma mais concisa no Bash 4+:
comando |& filtro
Exemplo prático:
find /proc -name "status" 2>&1 | grep -v "Permission denied" | head -5
4. Comandos frequentemente usados com Pipes
Alguns comandos são especialmente úteis em pipelines:
grep — filtra linhas que correspondem a um padrão:
dmesg | grep -i "usb"
sort — ordena as linhas recebidas:
cat notas.txt | sort -n
uniq — remove linhas duplicadas consecutivas (geralmente usado após sort):
cat palavras.txt | sort | uniq
wc — conta linhas, palavras e caracteres:
ls -1 | wc -l
Combinando tudo — um pipeline completo:
cat access.log | grep "404" | awk '{print $1}' | sort | uniq -c | sort -rn | head -10
Este comando analisa um log de acesso web, encontra erros 404, extrai IPs, conta ocorrências únicas e mostra os 10 IPs mais frequentes.
5. Pipes e Variáveis Especiais
Capturando saída com $() e pipes internos:
total_linhas=$(cat arquivo.txt | wc -l)
echo "Total de linhas: $total_linhas"
Uso de $? após cadeias de pipes — o status de saída de um pipeline é o do último comando executado:
grep "erro" log.txt | wc -l
echo "Status de saída: $?"
Para verificar o status de todos os comandos no pipeline:
set -o pipefail
grep "erro" log.txt | wc -l
echo "Status (pipefail): $?"
Diferença entre |, && e ||:
- |: executa comandos em paralelo, conectando saída/entrada
- &&: executa o próximo comando apenas se o anterior teve sucesso (exit code 0)
- ||: executa o próximo comando apenas se o anterior falhou
# Pipe: sempre executa
ls /tmp | grep arquivo
# AND: executa apenas se ls for bem-sucedido
ls /tmp && echo "Diretório existe"
# OR: executa apenas se ls falhar
ls /tmp || echo "Diretório não encontrado"
6. Técnicas Avançadas com Pipes
Pipe para xargs — converte stdin em argumentos de linha de comando:
find . -name "*.log" | xargs rm -f
Isso encontra todos os arquivos .log e os remove. Cuidado com nomes contendo espaços:
find . -name "*.log" -print0 | xargs -0 rm -f
Pipe para tee — divide o fluxo, enviando para a tela e para um arquivo simultaneamente:
ls -la | tee lista_completa.txt | grep ".sh"
Isso salva toda a listagem em lista_completa.txt e mostra apenas arquivos .sh na tela.
Named pipes (FIFOs) — pipes que existem como arquivos no sistema de arquivos:
# Criar um named pipe
mkfifo meu_pipe
# Em um terminal:
cat > meu_pipe
# Em outro terminal:
cat < meu_pipe
Named pipes são úteis para comunicação entre processos independentes ou scripts separados.
7. Erros Comuns e Boas Práticas
Esquecer de escapar caracteres especiais:
# Erro: o asterisco será expandido pelo shell
grep erro arquivo* | wc -l
# Correto: escapar ou usar aspas
grep "erro" arquivo* | wc -l
Pipes com comandos que não leem stdin:
# Erro: rm ignora stdin
ls | rm
# Correto: usar xargs
ls | xargs rm
Useless Use of Cat (UUOC) — usar cat desnecessariamente:
# Ineficiente
cat arquivo.txt | grep "padrão"
# Eficiente
grep "padrão" arquivo.txt
Verificar permissões e caminhos antes do pipe:
# Pode falhar silenciosamente
cat /etc/sombra | grep root
# Melhor: verificar antes
[ -r /etc/sombra ] && cat /etc/sombra | grep root || echo "Sem permissão"
Boas práticas:
- Sempre teste pipelines com dados de exemplo
- Use set -o pipefail em scripts para detectar falhas intermediárias
- Prefira grep "padrão" arquivo a cat arquivo | grep "padrão"
- Documente pipelines complexos com comentários
- Considere o uso de $() para capturar saídas intermediárias
Referências
- GNU Bash Manual - Pipelines — Documentação oficial do Bash sobre pipelines, incluindo sintaxe e comportamento
- Linux man page: pipe(7) — Manual completo sobre pipes no Linux, incluindo named pipes e FIFOs
- Advanced Bash-Scripting Guide - Pipes — Guia avançado de scripting Bash com exemplos detalhados de pipes
- Linux Journey - Pipes and Redirection — Tutorial interativo sobre pipes e redirecionamento para iniciantes
- Shell Scripting Tutorial - Pipes — Tutorial prático focado em pipes no shell scripting
- IBM Developer - Linux pipes and filters — Guia da IBM sobre pipes e filtros no Linux, com exemplos práticos
- Bash Hackers Wiki - Pipelines — Wiki comunitária com explicações técnicas sobre pipelines e redirecionamento no Bash