Corrigindo "Argument list too long" -- Quando rm * e comandos similares falham

Corrigindo "Argument list too long" -- Quando rm * e comandos similares falham

O que este artigo aborda

  • Por que rm * e cp * dest/ falham com "Argument list too long"
  • Como processar grandes quantidades de arquivos com seguranca usando find + xargs e find -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 a rm *)
  • -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"
done

O 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

  1. Excluindo arquivos -> find -delete
  2. Copiando ou movendo -> find ... -print0 | xargs -0 comando
  3. Revisar cada arquivo -> loop de shell

Proximas leituras