“ Lista de argumentos muito longa ”: Como faço para lidar com isso, sem alterar meu comando?

Quando executo um comando como ls */*/*/*/*.jpg, recebo o erro

-bash: /bin/ls: Argument list too long 

Eu sei por que isso acontece: é porque há um limite de kernel na quantidade de espaço para argumentos para um comando. O conselho padrão é mudar o comando que eu uso, para evitar exigir muito espaço para argumentos (por exemplo, use find e xargs).

E se eu não quiser alterar o comando? E se eu quiser continuar usando o mesmo comando? Como posso fazer as coisas “simplesmente funcionarem”, sem receber esse erro? Quais soluções estão disponíveis?

Comentários

  • Leitura útil: Bash FAQ 95 . Sem alterar seu comando não há ‘ s não há muito que você possa fazer além de recompilar para aumentar o tamanho máximo de sua lista de argumentos ou alterar sua estrutura de diretório para que haja menos arquivos.
  • @ jw013 com base na versão do kernel do Linux, pode ser possível aumentar a lista de argumentos – consulte unix.stackexchange.com/a/45161/8979 para obter detalhes sobre a mudança em sistemas recentes.
  • @UlrichDangel, Sim, é possível! Veja minha resposta; minha resposta mostra como fazer (em L inux, com um kernel recente o suficiente).

Resposta

No Linux, a quantidade máxima de espaço para o comando argumentos é 1/4 da quantidade de espaço de pilha disponível. Portanto, uma solução é aumentar a quantidade de espaço disponível para a pilha.

Versão curta: execute algo como

ulimit -s 65536 

Versão mais longa : A quantidade padrão de espaço disponível para a pilha é algo como 8.192 KB. Você pode ver a quantidade de espaço disponível, da seguinte forma:

$ ulimit -s 8192 

Escolha um número maior e defina a quantidade de espaço disponível para a pilha. Por exemplo, se você quiser tentar permitir até 65536 KB para a pilha, execute isto:

$ ulimit -s 65536 

Você pode precisar brincar com o quão grande isso precisa ser, usando tentativa e erro. Em muitos casos, esta é uma solução rápida e suja que eliminará a necessidade de modificar o comando e trabalhar a sintaxe de find, xargs, etc. (embora eu saiba que há outros benefícios em fazer isso).

Acredito que isso seja específico do Linux. Suspeito que provavelmente não ajudará em nenhum outro sistema operacional Unix (não testado).

Comentários

  • Você pode verificar assim se funcionou : $ getconf ARG_MAX 2097152 $ ulimit -s 65535 $ getconf ARG_MAX 16776960
  • Isso significa que se eu tornar o tamanho da pilha ilimitado com ulimit -s unlimited, o tamanho da linha de comando será ilimitado também?

Resposta

Em vez de ls */*/*/*/*.jpg, tente:

echo */*/*/*/*.jpg | xargs ls 

xargs (1) sabe qual é o número máximo de argumentos no sistema e quebrará sua entrada padrão para chamar a linha de comando especificada várias vezes sem mais argumentos do que esse limite, seja ele qual for (você também pode defini-lo abaixo do máximo do sistema operacional “usando o -n opção).

Por exemplo, suponha que o limite seja de 3 argumentos e você tenha cinco arquivos. Nesse caso, xargs executará ls duas vezes:

  1. ls 1.jpg 2.jpg 3.jpg
  2. ls 4.jpg 5.jpg

Freqüentemente, isso é perfeitamente adequado, mas nem sempre – por exemplo, você não pode confie em ls (1) classificar todas as entradas para você de maneira adequada, porque cada ls -invocação separada classificará apenas o subconjunto de entradas fornecidas por xargs.

Embora você possa ultrapassar o limite sugerido por outros, ainda haverá um limite – e algum dia sua coleção JPG irá crescer novamente. Você deve preparar seu (s) script (s) para lidar com um número infinito …

Comentários

  • Obrigado pela ideia! Esta não é uma solução alternativa ruim. Duas advertências: 1. Isso quebra em diretórios e nomes de arquivos que possuem espaços em seus nomes, portanto ‘ não é um substituto perfeito. 2. Isso vai ter o mesmo problema com Argument list too long, mas para echo em vez de ls, em shells onde echo não é um comando interno de shell? (Talvez ‘ não seja um problema na maioria dos shells, então talvez ‘ seja irrelevante.)
  • Sim , os caracteres especiais nos nomes dos arquivos são um problema. Sua melhor aposta é usar find com o predicado -print0 – e canalizar sua saída para xargs com a opção -0.echo é um shell integrado e não sofre da limitação de linha de comando de exec (3).
  • Isso funciona com comandos que esperam o argumento variável como o último parâmetro, como para ls, mas o que eu faço quando quero mv muitos arquivos em um único diretório, por exemplo mv * destdir? Se * der o erro ” muitos argumentos “, posso ‘ t make xargs para passar os caminhos como os primeiros em mv de alguma forma, ou posso?
  • Verifique a página do manual para xargs em seu sistema – no FreeBSD, por exemplo, o -J ajudará você com esta tarefa. Se no seu sistema operacional não houver maneira de fazer isso, você ‘ precisará escrever um script personalizado para reordenar os argumentos. Algo como: destdir=$1; shift; mv "$@" "$destdir". Em seguida, forneça esse novo script para xargs: .... | xargs newscript $destdir

Resposta

Este artigo do Linux Journal fornece 4 soluções. Apenas a quarta solução não envolve alterar o comando:

O método 4 envolve aumentar manualmente o número de páginas que são alocadas no kernel para linha de comando argumentos. Se você olhar o arquivo include / linux / binfmts.h, encontrará o seguinte próximo ao topo:

/* * MAX_ARG_PAGES defines the number of pages allocated for arguments * and envelope for the new program. 32 should suffice, this gives * a maximum env+arg of 128kB w/4KB pages! */ #define MAX_ARG_PAGES 32 

Para aumentar a quantidade de memória dedicado aos argumentos da linha de comando, você simplesmente precisa fornecer o valor MAX_ARG_PAGES com um número maior. Assim que esta edição for salva, simplesmente recompile, instale e reinicie no novo kernel como faria normalmente.

Em meu próprio sistema de teste, consegui resolver todos os meus problemas aumentando esse valor para 64. Depois de muito tempo teste, não tive nenhum problema desde a troca. Isso é totalmente esperado, pois mesmo com MAX_ARG_PAGES definido como 64, a linha de comando mais longa possível que eu poderia produzir ocuparia apenas 256 KB da memória do sistema – não muito para os padrões de hardware de sistema de hoje .

As vantagens do Método 4 são claras. Agora você pode simplesmente executar o comando como faria normalmente, e ele será concluído com êxito. As desvantagens são igualmente claras. Se você aumentar a quantidade de memória disponível para a linha de comando além da quantidade de memória de sistema disponível, você pode criar um ataque DOS em seu próprio sistema e fazer com que ele trave. Em sistemas multiusuário em particular, mesmo um pequeno aumento pode ter um impacto significativo porque cada usuário é então alocado memória adicional. Portanto, sempre teste extensivamente em seu próprio ambiente, pois esta é a maneira mais segura de determinar se o Método # 4 é uma opção viável para você.

Eu concordo que a limitação é seriamente irritante.

Deixe uma resposta

O seu endereço de email não será publicado. Campos obrigatórios marcados com *