Pipes
Esta aula explica o conceito de pipes (|) no shell Linux/Bash, mostrando como conectar a saída de um comando à entrada de outro para processamento de dados em pipeline. Aborda a filosofia Unix de composição de ferramentas simples e fornece exemplos práticos e exercícios.
Pipes são um dos recursos mais poderosos do shell Linux/Bash, permitindo conectar a saída padrão (stdout) de um comando diretamente à entrada padrão (stdin) de outro comando. Isso possibilita a criação de cadeias de processamento de dados de forma simples e eficiente, sem a necessidade de arquivos temporários ou intervenção manual.
Nesta aula, vamos explorar o conceito de pipe, como encadear múltiplos comandos, a filosofia Unix que inspira esse design e diversos exemplos práticos para você dominar essa técnica essencial.
O conceito de pipe (|)
O pipe é representado pelo caractere | (barra vertical) e atua como um canal de comunicação entre processos. Quando você escreve comando1 | comando2, o shell redireciona a saída de comando1 para a entrada de comando2. Isso significa que o segundo comando processa os dados gerados pelo primeiro, como se fossem digitados diretamente no teclado.
Por exemplo, o comando ls lista arquivos do diretório atual. Se você quiser filtrar apenas os arquivos que contêm a palavra "doc", pode usar ls | grep doc. O grep recebe a lista de nomes e imprime apenas aqueles que correspondem ao padrão. O pipe elimina a necessidade de criar um arquivo intermediário com a saída de ls.
$ ls | grep doc
documento.txt
foto_doc.jpg
É importante notar que o pipe opera apenas entre comandos que usam stdin e stdout. Comandos que leem diretamente de arquivos ou escrevem em dispositivos especiais podem não se comportar como esperado. Além disso, o pipe é unidirecional: os dados fluem da esquerda para a direita.
Encadeando comandos
Você pode encadear quantos comandos desejar usando pipes consecutivos. Cada comando recebe a saída do anterior e produz uma saída que é passada adiante. Isso forma um pipeline de processamento, onde cada etapa transforma os dados de forma incremental.
Por exemplo, para contar quantos arquivos .txt existem no diretório atual, você pode combinar ls, grep e wc:
$ ls | grep '\.txt$' | wc -l
5
Nesse pipeline, ls lista todos os arquivos, grep filtra apenas os que terminam com .txt e wc -l conta o número de linhas (que corresponde ao número de arquivos). O resultado é o número 5, indicando cinco arquivos .txt.
Outro exemplo comum é ordenar e exibir as últimas linhas de um arquivo grande:
$ cat /var/log/syslog | sort | tail -n 10
Aqui, cat exibe o conteúdo do arquivo, sort ordena as linhas alfabeticamente e tail -n 10 mostra apenas as últimas 10 linhas. A ordem dos comandos importa: se você trocar sort e tail, o resultado será diferente.
Filosofia Unix
O uso de pipes está profundamente ligado à filosofia Unix, que defende a criação de ferramentas pequenas, especializadas e que fazem uma única coisa bem. Cada comando deve ser projetado para funcionar como um filtro, lendo de stdin e escrevendo em stdout, permitindo que sejam combinados livremente.
Essa abordagem modular traz vantagens como reutilização, simplicidade e flexibilidade. Em vez de criar um programa monolítico que realiza múltiplas tarefas, você pode compor funcionalidades usando comandos existentes. Por exemplo, para encontrar os 5 processos que mais usam CPU, você pode usar ps, sort e head:
$ ps aux | sort -nrk 3 | head -n 5
A filosofia Unix também incentiva o uso de texto como interface universal, pois a maioria dos comandos lida com texto, facilitando a conexão entre eles.
Exemplos
Abaixo estão alguns exemplos práticos que ilustram o poder dos pipes em situações do dia a dia.
Exemplo 1: Contar palavras únicas em um arquivo
$ cat palavras.txt | tr ' ' '\n' | sort | uniq -c | sort -nr
Este pipeline quebra o arquivo em palavras (uma por linha), ordena, conta ocorrências únicas e ordena numericamente de forma reversa, mostrando as palavras mais frequentes primeiro.
Exemplo 2: Verificar portas abertas no sistema
$ ss -tln | awk 'NR>1 {print $4}' | cut -d: -f2 | sort -n | uniq
Extrai números de portas TCP em escuta, ordena e remove duplicatas.
Exemplo 3: Backup com compressão e data
$ tar cf - /home/user | gzip > backup_$(date +%Y%m%d).tar.gz
Embora não use pipe diretamente para entrada/saída, mostra combinação com redirecionamento. O pipe envia o arquivo tar para o gzip, que comprime e salva em um arquivo com data.
Exemplo 4: Monitorar log em tempo real filtrando erros
$ tail -f /var/log/syslog | grep -i error
Exibe continuamente novas linhas do log que contenham "error" (case insensitive).
Exemplo 5: Encontrar arquivos grandes e ordenar
$ find . -type f -size +1M | xargs ls -lhS | head -20
Encontra arquivos maiores que 1MB, lista-os com tamanho humano e ordena por tamanho, mostrando os 20 maiores.
Boas práticas e observações finais
Ao usar pipes, lembre-se de que cada comando em um pipeline é executado em um subshell separado, mas o shell gerencia a comunicação entre eles. Erros (stderr) não passam pelo pipe por padrão; para redirecionar stderr junto, use 2>&1 antes do pipe. Além disso, tenha cuidado com comandos que modificam o estado do sistema, pois o pipe pode processar dados inesperados.
Pipes são fundamentais para a produtividade no terminal. Pratique combinando comandos para resolver problemas do cotidiano. Quanto mais você usa, mais natural se torna.
Referências
- GNU Bash Manual: Pipelines
- POSIX Shell Command Language: Pipelines
- Wikipedia: Pipeline (Unix)
- Advanced Bash-Scripting Guide: Pipes
- TLDP: I/O Redirection
- Catonmat: Simple Obvious Unix Pipeline
Exercícios
Escreva um comando usando pipes para listar todos os arquivos do diretório atual, filtrar apenas aquivos com extensão .sh, ordená-los alfabeticamente e exibir os 3 primeiros.
✓ Resposta:ls | grep '\.sh$' | sort | head -n 3Crie um pipeline que exiba o número total de linhas de todos os arquivos .txt do diretório atual (use
wc -lcombinado comcatoufind).✓ Resposta:cat *.txt | wc -lUsando pipes, mostre os 5 processos que mais usam memória (coluna %MEM) com o comando
ps aux.✓ Resposta:ps aux | sort -nrk 4 | head -n 5Escreva um pipeline que leia o arquivo /etc/passwd, extraia apenas os nomes de usuário (primeiro campo separado por :) e ordene-os em ordem reversa.
✓ Resposta:cat /etc/passwd | cut -d: -f1 | sort -rUtilizando pipes, conte quantas vezes a palavra "error" aparece em um arquivo de log (case insensitive).
✓ Resposta:grep -oi 'error' arquivo.log | wc -l