Pipes
Esta aula explica o conceito de pipe (|) no shell Linux/Bash, como encadear comandos para construir pipelines complexas, e sua relação com a filosofia Unix. Inclui exemplos práticos e exercícios com respostas colapsáveis.
Pipes são um dos mecanismos mais poderosos do shell Linux/Bash, permitindo conectar a saída de um comando diretamente à entrada de outro. Eles são representados pelo símbolo | e formam a base para a construção de pipelines, que são sequências de comandos processando dados em etapas.
Dominar pipes é essencial para trabalhar de forma produtiva no terminal, pois evita a criação de arquivos temporários e permite combinar ferramentas simples para resolver problemas complexos. Nesta aula, vamos explorar o conceito, como encadear múltiplos comandos, a filosofia Unix por trás dessa abordagem, e exemplos práticos.
O conceito de pipe (|)
Um pipe conecta o fluxo de saída padrão (stdout) de um comando ao fluxo de entrada padrão (stdin) de outro comando. Isso significa que o que o primeiro comando imprime na tela é redirecionado para ser lido como entrada pelo segundo comando, sem passar por arquivos intermediários.
A sintaxe é simples: comando1 | comando2. O shell cria um canal de comunicação unidirecional entre os dois processos. Por exemplo, ls -l | grep .txt lista arquivos e filtra apenas os que contêm '.txt'. O pipe permite que a saída de ls -l seja processada linha a linha por grep.
É importante notar que pipes trabalham com dados em buffer, mas geralmente de forma eficiente, pois os comandos podem executar em paralelo: enquanto o primeiro comando produz saída, o segundo já pode começar a processá-la.
Encadeando comandos
Você pode encadear mais de dois comandos usando múltiplos pipes: comando1 | comando2 | comando3. Cada pipe conecta a saída de um comando à entrada do seguinte, formando um pipeline. O shell gerencia a execução concorrente e o fluxo de dados.
Por exemplo, para contar quantos arquivos .txt existem em um diretório: ls -l | grep .txt | wc -l. O ls -l lista os arquivos, grep .txt seleciona as linhas com '.txt', e wc -l conta as linhas. Cada comando é uma etapa do processamento.
É possível usar redirecionamentos junto com pipes, mas cuidado: comando1 > arquivo | comando2 redireciona a saída de comando1 para um arquivo, e o pipe fica vazio (comando2 recebe nada). A ordem correta para salvar a saída final é comando1 | comando2 > arquivo.
Exemplo prático: encontrar os 5 maiores arquivos em um diretório:
du -sh * | sort -rh | head -5Explicação: du -sh * mostra o tamanho de cada item, sort -rh ordena por tamanho humano reverso (maior primeiro), head -5 exibe as primeiras 5 linhas.
Filosofia Unix
A filosofia Unix, formulada por Ken Thompson e Dennis Ritchie, prega que cada programa deve fazer uma única coisa bem feita. Pipes são a cola que permite combinar esses programas para tarefas mais complexas. A saída de um programa serve como entrada para outro, criando uma cadeia de processamento.
Essa abordagem modular traz vantagens: reutilização de ferramentas, simplicidade, e facilidade de depuração. Em vez de um programa monolítico que faz tudo, você compõe soluções usando comandos padrão. Por exemplo, para extrair informações de um log, você pode usar grep, awk, sort, uniq, etc., todos conectados por pipes.
Pipes também incentivam o uso de texto como interface universal. Muitos comandos Unix produzem saída textual, que pode ser processada por outros comandos. Isso torna o shell um ambiente extremamente flexível para automação e análise de dados.
Exemplos
Vamos ver alguns exemplos práticos de uso de pipes em situações comuns do dia a dia.
Exemplo 1: Contar processos de um usuário
ps aux | grep usuario | wc -lLista todos os processos, filtra pela linha que contém o nome do usuário (cuidado: o próprio grep aparece na lista, então pode ser necessário usar grep -v grep para excluir).
Exemplo 2: Verificar portas abertas
netstat -tuln | grep LISTENMostra portas TCP e UDP em escuta.
Exemplo 3: Extrair IPs de um arquivo de log
cat access.log | awk '{print $1}' | sort | uniq -c | sort -rn | head -10Extrai o primeiro campo (IP) de cada linha, ordena, conta ocorrências únicas, ordena por contagem decrescente e mostra os 10 mais frequentes.
Exemplo 4: Converter maiúsculas para minúsculas
echo "HELLO WORLD" | tr 'A-Z' 'a-z'Usa o comando tr para traduzir caracteres.
Exemplo 5: Encontrar arquivos com permissão 755 e listar detalhes
find / -type f -perm 755 2>/dev/null | xargs ls -lhO find localiza os arquivos, e xargs monta a linha de comando para ls. O redirecionamento 2>/dev/null suprime erros de permissão.
Boas práticas
Ao usar pipes, lembre-se de que a saída de cada comando é passada adiante. Se um comando falhar, o pipeline pode ser interrompido (dependendo da configuração do shell). Use set -o pipefail para garantir que o pipeline retorne falha se qualquer comando falhar.
Evite pipes desnecessários: se um único comando pode fazer o trabalho, prefira ele. Por exemplo, grep 'padrao' arquivo é melhor que cat arquivo | grep 'padrao' (conhecido como Useless Use of Cat).
Para depuração, você pode inserir tee no pipeline para salvar saídas intermediárias: comando1 | tee arquivo_temporario | comando2.
Referências
- GNU Bash Manual: Pipelines
- POSIX Shell Command Language: Pipelines
- Wikipedia: Pipeline (Unix)
- Advanced Bash-Scripting Guide: Special Characters
- TLDP: I/O Redirection
- O'Reilly: Linux in a Nutshell
Exercícios
Escreva um comando que conte quantas linhas contêm a palavra "error" em um arquivo chamado
log.txt.✓ Resposta:grep 'error' log.txt | wc -lougrep -c 'error' log.txt(mais eficiente).Como listar apenas os 3 maiores arquivos (por tamanho) no diretório atual?
✓ Resposta:ls -lS | head -4(inclui o cabeçalho) oudu -sh * | sort -rh | head -3.Usando pipes, extraia o nome de usuário (primeiro campo) do arquivo
/etc/passwd, ordene alfabeticamente e exiba apenas os 5 primeiros.✓ Resposta:cut -d: -f1 /etc/passwd | sort | head -5Explique o que faz o comando:
ps aux | grep bash | grep -v grep✓ Resposta: Ele lista todos os processos (ps aux), filtra linhas que contêm "bash", e então remove a linha do próprio comandogrep bash(que aparece na lista porque o grep também contém "bash" em sua linha de comando). O resultado são apenas os processos bash reais.Crie um pipeline que encontre todos os arquivos .conf no diretório
/etc(e subdiretórios) e conte quantos são.✓ Resposta:find /etc -name '*.conf' 2>/dev/null | wc -loufind /etc -name '*.conf' 2>/dev/null | wc -l.