Ubuntu Pipes e xargs
O pipe (|, "cano" em inglês) liga a saída de um comando à entrada do próximo. Com ele, comandos pequenos viram uma linha de montagem: um lista, outro filtra, outro conta. É uma das ideias mais poderosas do Linux.
- Como o
|conecta dois comandos, e a diferença entre|e>. - A montar um pipe de várias etapas uma etapa por vez, conferindo cada resultado.
- A ver e gravar ao mesmo tempo com
tee. - A transformar linhas em argumentos com
xargs, para comandos que não leem a entrada.
A ideia: saída de um vira entrada do outro
Na aula de Redirecionamento você viu que todo comando tem uma entrada (canal 0) e uma saída (canal 1). O pipe encaixa os dois:
comando1 ── saída ──► | ── entrada ──► comando2 ──► tela
O comando1 não mostra nada na tela. Tudo o que ele produziria vai direto para o comando2, que trabalha em cima disso.
Seu primeiro pipe
Quantos arquivos há na pasta Downloads? O ls lista, e o wc -l conta linhas.
- ls Downloads
- Lista os arquivos, um por linha (quando a saída não é a tela).
- |
- O pipe: entrega essa lista ao próximo comando.
- wc -l
- Conta as linhas que recebeu (word count, opção
-lde lines).
$ ls Downloads foto.jpg fotos-viagem.zip manual.pdf musica.mp3 ubuntu-26.04-desktop-amd64.iso $ ls Downloads | wc -l 5 « 5 linhas = 5 arquivos
O símbolo | fica, na maioria dos teclados brasileiros, na tecla ao lado do Z ou do Backspace, junto com a barra invertida: aperte Shift + essa tecla.
Montando um pipe passo a passo
Ninguém escreve um pipe longo de uma vez. O jeito profissional é acrescentar uma etapa, rodar, olhar o resultado, e só então acrescentar a próxima. Vamos responder: qual fruta aparece mais vezes em frutas.txt?
-
Veja os dados brutos.
$ cat frutas.txt banana maçã laranja banana uva maçã banana
-
Ordene, para que as frutas iguais fiquem juntas.
$ sort frutas.txt banana banana banana laranja maçã maçã uva
-
Conte as repetições. O
uniq -cjunta linhas iguais vizinhas e escreve quantas eram. Por isso osortveio antes.$ sort frutas.txt | uniq -c 3 banana 1 laranja 2 maçã 1 uva -
Ordene pela contagem, do maior para o menor:
-ncompara como número,-rinverte.$ sort frutas.txt | uniq -c | sort -nr 3 banana 2 maçã 1 uva 1 laranja -
Fique só com a primeira linha.
$ sort frutas.txt | uniq -c | sort -nr | head -n 1 3 banana « a resposta
- sort frutas.txt
- Ordena, juntando as linhas iguais.
- | uniq -c
- Conta cada grupo de linhas iguais.
- | sort -nr
- Ordena pelo número, do maior para o menor.
- | head -n 1
- Mostra só a primeira linha.
Esse mesmo "molde" responde muitas perguntas do dia a dia: quais IPs mais acessaram um site, quais comandos você mais usa, quais extensões de arquivo dominam uma pasta.
Missão: monte o pipe acima etapa por etapa, rodando cada versão. No fim, grave o ranking completo (sem o head) no arquivo ranking.txt. Dica: use as setas ↑ para trazer o comando anterior e só acrescentar a próxima etapa.
Outro exemplo: quem mais acessou o site?
O arquivo Documentos/acesso.log tem uma linha por acesso, e o primeiro "campo" é o IP do visitante:
$ head -n 2 Documentos/acesso.log
192.168.0.10 - - [15/Oct/2026:09:01:12] "GET / HTTP/1.1" 200
192.168.0.23 - - [15/Oct/2026:09:01:40] "GET /contato HTTP/1.1" 200
$ cut -d " " -f 1 Documentos/acesso.log | sort | uniq -c | sort -nr
3 192.168.0.10
2 192.168.0.23
1 192.168.0.57
O cut -d " " -f 1 corta cada linha nos espaços (-d, de delimiter) e fica com o campo 1 (-f, de field). O resto é o mesmo molde. Veja mais sobre cut em sort, uniq, cut, wc, tr.
Missão: (1) descubra qual IP mais acessou, montando o pipe aos poucos. (2) Use grep para mostrar só as linhas do log com o código 404 (página não encontrada).
Filtrar a saída de qualquer comando
O grep é o parceiro mais comum do pipe: ele deixa passar só as linhas que contêm um texto.
$ ls -l Documentos | grep txt
-rw-rw-r-- 1 ana ana 71 Oct 14 17:40 notas.txt
$ history | grep mkdir
12 mkdir jan fev mar
15 mkdir -p loja/{src,docs}
Cuidado: o grep encontra a si mesmo
Um uso clássico é procurar um programa na lista de processos. Repare na última linha:
$ ps aux | grep chrome ana 2210 5.4 6.8 1100800 1093000 ? Sl 08:00 0:16 /snap/chromium/3554/usr/lib/chromium-browser/chrome --password-store ana 2251 2.0 3.9 636000 629000 ? Sl 08:00 0:06 /snap/chromium/3554/usr/lib/chromium-browser/chrome --type=renderer ana 3150 0.0 0.0 9144 2304 pts/0 S+ 10:30 0:00 grep --color=auto chrome « o próprio grep
O grep chrome também é um processo, e a linha de comando dele contém "chrome". Duas soluções:
pgrep -a chrome, que foi feito para isso (veja ps, pgrep, top);ps aux | grep "[c]hrome". O padrão[c]hromecasa com "chrome", mas o texto do próprio grep agora é "[c]hrome", que não casa.
Ver e gravar ao mesmo tempo: tee
Com >, a saída vai para o arquivo e some da tela. O tee (nome de uma conexão hidráulica em forma de "T") divide o fluxo em dois: grava num arquivo e passa adiante.
comando ──► tee arquivo.txt ──► tela (ou próximo comando)
│
▼
arquivo.txt
- ls Documentos
- O comando.
- | tee lista.txt
- Grava em
lista.txte repete na tela.
$ ls Documentos | tee lista.txt acesso.log notas.txt projetos relatorio.odt $ cat lista.txt acesso.log notas.txt projetos relatorio.odt
Com -a (de append), o tee acrescenta em vez de substituir, como o >>.
O uso mais importante: escrever em arquivos do sistema
Como você viu em Redirecionamento, sudo echo … > /etc/arquivo falha. Com tee, quem abre o arquivo é o próprio tee, e ele pode rodar com sudo:
$ echo "vm.swappiness=10" | sudo tee /etc/sysctl.d/99-swap.conf [sudo: authenticate] Senha: vm.swappiness=10 $ echo "vm.swappiness=10" | tee /etc/sysctl.d/99-swap.conf /etc/sysctl.d/99-swap.conf: Permission denied (os error 13) « sem sudo: negado
Se você não quer o eco na tela, descarte-o: … | sudo tee arquivo > /dev/null.
xargs: transformar linhas em argumentos
Alguns comandos leem a entrada (sort, grep, wc). Outros não: mkdir, rm, cp e touch só aceitam nomes como argumentos. Mandar algo para eles por pipe não funciona:
$ cat pastas.txt fotos videos musicas $ cat pastas.txt | mkdir erro: os seguintes argumentos obrigatórios não foram fornecidos: <dirs>... « faltou o nome das pastas Usage: mkdir [OPÇÃO]... DIRETÓRIO... Para obter mais informações, use '--help'.
O mkdir recebeu a lista pela entrada, mas não lê a entrada. Para ele, foi como digitar só mkdir, sem nome nenhum.
O xargs resolve isso: ele lê as linhas e as coloca no fim do comando, como se você tivesse digitado.
- cat pastas.txt
- Produz os nomes, um por linha.
- | xargs
- Lê esses nomes da entrada…
- mkdir
- …e roda
mkdir fotos videos musicas.
$ cat pastas.txt | xargs mkdir $ ls -d fotos videos musicas fotos musicas videos
Ver o comando que o xargs montou: -t
A opção -t mostra o comando antes de rodar. É ótima para aprender e para conferir:
$ cat pastas.txt | xargs -t mkdir -p mkdir -p fotos videos musicas
Um item por vez: -n 1 e -I {}
Por padrão, o xargs coloca todos os itens num comando só. Com -n 1, roda uma vez para cada item. Com -I {}, você escolhe onde o item entra no comando:
$ cat pastas.txt | xargs -n 1 echo "criando:"
criando: fotos
criando: videos
criando: musicas
$ cat pastas.txt | xargs -I {} mkdir {}-2026
$ ls -d *-2026
fotos-2026 musicas-2026 videos-2026
Nomes com espaço: -d '\n' e -0
O xargs separa os itens por espaços. Um nome como "Meus Projetos" vira dois:
$ echo "Meus Projetos" | xargs mkdir $ ls Meus Projetos « duas pastas, não uma
Use xargs -d '\n' para separar só por linha. Com o find, o par mais seguro é find … -print0 | xargs -0, que usa um separador invisível que nunca aparece em nomes:
$ find . -name "*.tmp" -print0 | xargs -0 rm -v removido './cache 1.tmp' removido './cache 2.tmp'
Antes de qualquer | xargs rm, rode o pipe sem o rm (ou com xargs -t echo rm) e confira a lista. Um padrão errado no find apaga arquivos que você não queria.
Missão: o arquivo pastas.txt já tem três nomes. Veja o conteúdo com cat e crie as três pastas usando xargs. Experimente também o -t para ver o comando montado.
O que um pipe devolve
O código de saída ($?) de um pipe é o do último comando. Os erros das etapas anteriores ficam escondidos:
$ cat nada.txt | wc -l cat: nada.txt: No such file or directory 0 $ echo $? 0 « o wc deu certo, então o pipe "deu certo"
Em scripts, ligue set -o pipefail: assim, se qualquer etapa falhar, o pipe inteiro devolve erro.
$ set -o pipefail $ cat nada.txt | wc -l cat: nada.txt: No such file or directory 0 $ echo $? 1
Repare também que a mensagem do cat apareceu na tela, e não foi para o wc. O pipe só leva o canal 1 (saída). Para levar os erros junto, use 2>&1 | ou o atalho |&.
Formas diferentes de contar linhas
| Forma | Exemplo | Observação |
|---|---|---|
| Arquivo como argumento | wc -l frutas.txt | Mostra o número e o nome. |
| Redirecionamento | wc -l < frutas.txt | Só o número; ótimo em scripts. |
| Pipe com cat | cat frutas.txt | wc -l | Funciona, mas o cat é desnecessário. |
| Saída de outro comando | ls Downloads | wc -l | Aqui o pipe é necessário: os dados vêm de um comando. |
| grep | grep -c banana frutas.txt | Conta só as linhas que casam. |
Quando não funciona
$ ls > wc $ ls Documentos Downloads … wc
O que aconteceu: foi usado > no lugar de |. O > manda a saída para um arquivo; o | manda para um comando.
Como resolver: apague o arquivo (rm wc) e use ls | wc -l.
$ find . -name "*.tmp" | rm rm: falta operando Tente "rm --help" para mais informações.
O que aconteceu: o rm não lê a entrada; ele espera nomes como argumentos.
Como resolver: coloque o xargs no meio, find . -name "*.tmp" -print0 | xargs -0 rm, ou use o próprio find . -name "*.tmp" -delete.
$ ps aux | grep firefox ana 3170 0.0 0.0 9144 2304 pts/0 S+ 10:31 0:00 grep --color=auto firefox
O que aconteceu: a única linha é o próprio grep. O Firefox não está aberto, ou o processo tem outro nome. No caso do Chromium instalado pelo Snap, o processo se chama chrome.
Como resolver: rode cada etapa sozinha. Primeiro ps aux, depois procure com outro termo, como ps aux | grep -i chrom. Veja o caso completo em ps, pgrep, top.
Se o xargs criou "Meus" e "Projetos" separados, use xargs -d '\n' ou, com o find, -print0 | xargs -0.
Referência
| Recurso | O que faz | Exemplo |
|---|---|---|
a | b | Saída de a vira entrada de b | ls | wc -l |
a |& b | Saída e erros de a para b | make |& less |
tee arq | Grava e repassa | ls | tee lista.txt |
tee -a arq | Acrescenta e repassa | date | tee -a log.txt |
| sudo tee arq | Grava em arquivo do root | echo x | sudo tee /etc/a.conf |
xargs cmd | Linhas da entrada viram argumentos | cat lista | xargs mkdir |
xargs -t | Mostra o comando antes de rodar | xargs -t rm |
xargs -n 1 | Um item por execução | xargs -n 1 echo |
xargs -I {} | Escolhe onde o item entra | xargs -I {} cp {} {}.bak |
xargs -0 | Itens separados pelo caractere nulo | find -print0 | xargs -0 |
xargs -d '\n' | Itens separados por linha | xargs -d '\n' mkdir |
set -o pipefail | Pipe falha se qualquer etapa falhar | Use em scripts |
Exercícios
1. Contar arquivos
Complete para contar quantos itens há na pasta Imagens:
2. O molde da contagem
Complete o pipe que conta quantas vezes cada linha aparece:
3. Gravar como root
Complete para gravar a linha no arquivo do sistema:
4. Por que cat pastas.txt | mkdir não funciona?
5. Em sort frutas.txt | uniq -c, por que o sort vem antes?
Resumo
|liga a saída de um comando à entrada do próximo;>liga a um arquivo.- Monte pipes longos uma etapa por vez, olhando o resultado de cada uma.
teegrava e mostra ao mesmo tempo;| sudo teeescreve em arquivos do sistema.xargstransforma linhas em argumentos para comandos comomkdirerm.- O pipe só leva a saída (canal 1), e o código de saída é o do último comando.