Quase todos os pipelines acabam por esbarrar na mesma parede: o comando de que precisamos não lê da entrada padrão. O find encontrou os ficheiros, o grep filtrou a lista — e agora o rm, o cp ou o ssh só aceitam nomes escritos na linha de comando. É aqui que entra o xargs, a cola invisível que transforma uma lista em argumentos.
Neste artigo vemos as opções que contam no dia a dia — agrupar, posicionar com um marcador, separar com segurança, correr em paralelo e controlar o que corre — e, como sempre no blog HJFR, o ângulo de segurança: nomes de ficheiros maliciosos que transformam uma limpeza inocente num incidente.
Veja o guia em vídeo
Prefere ver antes de experimentar? No canal HJFR-IT no YouTube mostramos o xargs opção a opção, com o resultado de cada comando no ecrã — narrado em português e com legendas.
O que faz o xargs
O xargs lê itens da entrada padrão (ou de um ficheiro), separa-os e constrói com eles linhas de comando, que executa — com o echo, se não indicarmos comando. Por omissão, separa por espaços e quebras de linha, trata aspas e barra invertida como especiais e junta tantos argumentos quantos couberem numa só invocação.
xargs [OPÇÕES] [COMANDO [ARGUMENTOS-INICIAIS]]
produtor | xargs comando # a lista vem do stdin
xargs -a lista.txt comando # a lista vem de um ficheiro
O problema que o xargs resolve
Muitos comandos — rm, cp, mkdir — não leem da entrada padrão: esperam os nomes como argumentos. Mandar-lhes uma lista por um cano não faz nada. O xargs põe-se no meio: recebe a lista pela entrada e escreve-a como argumentos do comando.
$ echo 'nota1.txt nota2.txt' | rm
rm: missing operand
Try 'rm --help' for more information.
$ echo 'nota1.txt nota2.txt' | xargs rm # corre: rm nota1.txt nota2.txt
Agrupar argumentos: -n e -L
Sem opções, o xargs junta tudo numa só linha de comando. A opção -n controla quantos argumentos entram em cada invocação: com -n 2, o comando corre várias vezes, dois argumentos de cada vez — útil quando há limite de argumentos ou queremos processar aos pares.
$ seq 6 | xargs
1 2 3 4 5 6
$ seq 6 | xargs -n 2
1 2
3 4
5 6
$ printf '1 2\n3\n4 5 6\n' | xargs -L 1
1 2
3
4 5 6
Com -n 2 a saída ficou em três linhas: foram três execuções do echo. Já a -L conta linhas em vez de argumentos: cada linha da entrada dá uma invocação, com as palavras que tiver.
O marcador -I (e -a para ler de um ficheiro)
Por omissão, o xargs põe os argumentos no fim do comando, mas muitas vezes precisamos deles no meio. O -I define um marcador — tradicionalmente as chavetas — que representa cada item e pode aparecer onde e quantas vezes quisermos.
# o nome aparece na origem e no destino da cópia
ls *.pdf | xargs -I {} cp {} backup/{}
# qualquer texto serve de marcador; aqui, H de host
xargs -a servidores.txt -I H ssh H uptime
-Iimplica uma invocação por item, e cada linha é um item: um nome comoplano 2027.pdfchega inteiro (uma quebra de linha no nome continua a parti-lo).-a FICHEIROlê os itens de um ficheiro em vez do stdin, dispensa ocate deixa a entrada padrão livre para o comando.
Segurança com nulo: -0, find -print0 e -d
A armadilha dos espaços
Aqui está a armadilha mais importante do xargs. Ele separa os itens por espaços e quebras de linha — mas os nomes de ficheiros podem conter ambos. Um ficheiro chamado o meu ficheiro.tmp é lido como três nomes, e o comando falha ou, pior, apaga o que não devia.
$ find cache -name '*.tmp' | xargs rm
rm: cannot remove 'cache/o': No such file or directory
rm: cannot remove 'meu': No such file or directory
rm: cannot remove 'ficheiro.tmp': No such file or directory
A correção: -print0 e -0
A solução é o par mágico: o find com -print0 termina cada nome com o caráter nulo — invisível e impossível num nome de ficheiro — e o xargs com -0 lê da mesma forma (e deixa de tratar aspas como especiais). Use sempre este par ao combinar find e xargs.
find cache -name '*.tmp' -print0 | xargs -0 rm
Separador à medida: -d
Quando a lista vem de um ls ou de um ficheiro de texto, a opção -d define o separador. Com -d '\n', cada linha é um item, espaços incluídos, e um apóstrofo como em caixa d'água.jpg deixa de dar unmatched single quote. Contra quebras de linha no nome, porém, só o -0.
ls fotos/*.jpg | xargs -d '\n' du -h
Correr em paralelo: -P
Uma capacidade que poucos conhecem e que vale ouro: com -P 4, o xargs mantém quatro cópias do comando a correr ao mesmo tempo e lança a seguinte assim que uma termina. Numa lista de mil imagens ou de dezenas de servidores, isto transforma minutos em segundos, aproveitando todos os núcleos do processador.
# descarregar quatro endereços em simultâneo
cat urls.txt | xargs -P 4 -n 1 curl -sO
# consultar quatro servidores ao mesmo tempo
xargs -a servidores.txt -P 4 -I H ssh H uptime
Combine -P com -n ou -I (sem eles, tudo cabe numa só invocação) e conte com a saída pela ordem de conclusão, não pela ordem da lista.
Controlo e segurança: -t, -p e -r
-t(de trace) imprime cada comando no stderr antes de o executar — essencial antes de uma operação destrutiva. No GNU xargs atual, os argumentos com espaços aparecem entre aspas.-pvai mais longe: mostra cada comando e só o executa se respondermosy.-r(--no-run-if-empty) evita um problema clássico: sem ele, se a lista chegar vazia, o xargs do GNU corre o comando à mesma, sem argumentos. Com-r, uma lista vazia não faz nada.
$ ls *.bak | xargs -t rm
rm db.conf.bak site.conf.bak
$ (cd uploads && ls | xargs -p rm)
rm fatura.pdf logo.png -rf thumbs?...n
$ find cache -name '*.swp' -print0 | xargs -0 -r rm # lista vazia: nada corre
Exemplo real: redimensionar imagens em paralelo
Juntemos tudo para reduzir a metade todas as imagens de uma árvore de pastas. O find emite os .jpg separados por nulo; o xargs lê-os em segurança com -0, corre quatro conversões em simultâneo com -P 4 e usa o marcador para pôr o nome na origem e no destino do convert, do ImageMagick.
find fotos -name '*.jpg' -print0 | xargs -0 -P 4 -I {} convert {} -resize 50% {}
Uma linha substitui um ciclo inteiro num script. Atenção: com a mesma origem e destino, o original é substituído — experimente primeiro numa cópia.
xargs em cibersegurança
Os nomes de ficheiros são dados não confiáveis. Num diretório onde outros escrevem — uploads de um site, /tmp, partilhas — quem escolhe os nomes pode ser um atacante. Um ficheiro chamado $'x\nrelatorio.pdf\nx.tmp' é apanhado por find uploads -name '*.tmp'; sem -print0, o xargs parte-o nas quebras de linha e entrega relatorio.pdf ao rm, que apaga um ficheiro alheio à limpeza. Num script a correr como root, o alvo pode ser bem pior. Com -print0 | xargs -0, o nome é um único argumento.
Nomes que se fazem passar por opções. Se a lista vier do ls, um ficheiro chamado -rf chega ao rm como opção: rm fatura.pdf logo.png -rf thumbs apaga thumbs/ inteiro, em silêncio. A defesa é dupla: -- antes dos nomes (xargs rm --) marca o fim das opções, e caminhos com prefixo, como os que o find produz, nunca começam por traço.
Resposta a incidentes em escala. Do lado de quem defende, o xargs acelera a triagem: calcular hashes de uma árvore inteira (find /var/www -type f -print0 | xargs -0 sha256sum > hashes.txt), recolher o mesmo indicador de dezenas de servidores com -P, ou isolar suspeitos com xargs -0 -I {} mv -- {} /root/quarentena/. O -t deixa rasto do que correu — também é evidência.
Experimente no simulador interativo
O simulador recria um diretório com armadilhas: um nome com espaços em cache/ e, em uploads/, os nomes maliciosos -rf e um com quebras de linha. À esquerda vê os itens que o xargs leu (os perigosos a laranja), as invocações que construiu — no -P, uma pista por via — e o efeito no diretório; à direita, o terminal. Use Demonstrar tudo para a sequência guiada, Anterior e Seguinte para navegar, ou Repor estado para recomeçar.
Erros comuns e boas práticas
- Usar
find | xargssem-print0e-0: funciona nos testes e falha no primeiro nome com espaços. Use o par — oufind -exec … {} +. - Passar listas do
lsa comandos destrutivos: nomes sem caminho podem começar por-. Prefira ofinde ponha--antes dos nomes. - Esquecer o
-rem scripts: com lista vazia, umxargs du -shmede o diretório atual em vez de nada. - Confundir
-ncom-L:-nconta argumentos,-Lconta linhas — e nenhum protege contra espaços. - Paralelizar sem pensar na saída: com
-P, as linhas chegam pela ordem de conclusão; inclua o nome do item em cada linha. - Executar à primeira: antes de um
rmem massa, corra a mesma linha comxargs -t echo rmou com-p.
Conclusão
O xargs transforma listas em argumentos: -n e -L para agrupar, -I para o marcador, -a e -d para a origem e o separador, -0 para nomes difíceis, -P para o paralelismo e -t, -p e -r para o controlo. É a cola por trás de metade dos pipelines poderosos em Linux — e, mal usado, uma das formas mais rápidas de apagar o que não devia. Combine-o com o comando find, que produz as listas, e com os pipelines de texto com cut, sort, uniq e wc, que as filtram.
Workshop — Linha de Comandos Linux
Quer passar da leitura à prática, com exercícios reais e acompanhamento? No workshop Linha de Comandos Linux da HJFR trabalha estes e outros comandos da série — da administração do dia a dia à resposta a incidentes.
Este artigo faz parte da série «Comandos Linux, um a um» do blog HJFR — fique atento aos próximos comandos.
