Corrigindo "Argument list too long" -- Quando rm * e comandos similares falham
O que este artigo aborda
- Por que
rm *ecp * dest/falham com "Argument list too long" - Como processar grandes quantidades de arquivos com seguranca usando
find + xargsefind -delete - Como lidar com nomes de arquivo com espacos ou caracteres especiais
Correcao rapida
# Substituto para rm * -- abordagem mais segura find . -maxdepth 1 -name "*.log" -type f -delete # Ou via xargs find . -maxdepth 1 -name "*.log" -print0 | xargs -0 rm
Por que "Argument list too long" acontece?
Quando voce executa rm *, o shell (nao o rm) expande o wildcard primeiro. Com dezenas de milhares de arquivos, a lista de argumentos resultante excede o limite do kernel ARG_MAX, e o kernel retorna um erro E2BIG.
$ rm *.log -bash: /bin/rm: Argument list too long
Verifique o ARG_MAX do seu sistema:
$ getconf ARG_MAX 2097152
2097152
O valor tipico no Linux e 2 MB (2.097.152 bytes). Quando o comprimento total de todos os argumentos expandidos excede esse valor, o comando falha.
Este erro afeta qualquer comando que use wildcards: ls *.log, cp *.log dest/, cat *.txt, chmod 644 *.php, e assim por diante.
find processa arquivos um de cada vez e nunca constroi uma lista completa de argumentos para exec(), por isso contorna esse limite completamente.
Correcao com find -delete
Para exclusao, find -delete e a opcao mais simples e segura -- nao precisa de xargs.
find . -maxdepth 1 -name "*.log" -type f -delete
-maxdepth 1: apenas o diretorio atual (escopo equivalente arm *)-type f: apenas arquivos (evita exclusao acidental de diretorios)-delete: exclui cada correspondencia
Para incluir subdiretorios, remova -maxdepth:
find /path/to/dir -name "*.log" -type f -delete
Antes de excluir, verifique o que sera removido:
# Visualizar correspondencias e contar find . -maxdepth 1 -name "*.log" -type f find . -maxdepth 1 -name "*.log" -type f | wc -l
Correcao com find + xargs
Um padrao de uso geral que funciona com qualquer comando, nao apenas rm.
Padrao basico
find . -maxdepth 1 -name "*.log" | xargs rm
xargs divide automaticamente os argumentos em lotes para ficar dentro do ARG_MAX.
Nomes de arquivo com espacos ou caracteres especiais
O xargs padrao divide por espacos em branco, o que quebra nomes de arquivo contendo espacos. Use -print0 com xargs -0 (delimitado por NUL) para seguranca total:
find . -maxdepth 1 -name "*.log" -print0 | xargs -0 rm
Usar -print0 | xargs -0 como padrao e o habito mais seguro.
Execucao paralela para velocidade
find . -name "*.log" -print0 | xargs -0 -P4 rm
-P4 executa 4 processos em paralelo. Util ao excluir um numero muito grande de arquivos.
Correcao para cp / mv
O mesmo erro E2BIG aparece com cp * dest/ e mv * dest/.
# cp
find . -maxdepth 1 -name "*.log" -print0 | xargs -0 -I{} cp {} /dest/
# mv
find . -maxdepth 1 -name "*.log" -print0 | xargs -0 -I{} mv {} /dest/-I{} substitui cada caminho em {}.
Voce tambem pode usar -exec:
find . -maxdepth 1 -name "*.log" -exec cp {} /dest/ \;-exec inicia um processo por arquivo, entao xargs e mais rapido para grandes quantidades.
Correcao com loop de shell
Uma alternativa simples quando find nao esta disponivel, ou quando voce precisa revisar cada arquivo antes de agir.
for f in *.log; do
rm "$f"
doneO shell invoca rm uma vez por arquivo, entao ARG_MAX nunca e atingido.
Sempre coloque "$f" entre aspas. Sem as aspas, nomes de arquivo com espacos farao o loop quebrar.
Resumo
| Abordagem | Exemplo | Melhor para |
|---|---|---|
find -delete |
find . -name "*.log" -type f -delete |
Apenas exclusao (mais simples) |
find | xargs rm |
find . -name "*.log" | xargs rm |
Exclusao padrao |
-print0 | xargs -0 |
find . -name "*.log" -print0 | xargs -0 rm |
Nomes com caracteres especiais |
| Loop de shell | for f in *.log; do rm "$f"; done |
Revisao passo a passo |
-exec |
find . -name "*.log" -exec cp {} /dest/ \; |
Operacoes alem de exclusao |
Fluxo de decisao
- Excluindo arquivos ->
find -delete - Copiando ou movendo ->
find ... -print0 | xargs -0 comando - Revisar cada arquivo -> loop de shell