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:
-
ls 1.jpg 2.jpg 3.jpg
-
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 paraecho
em vez dels
, em shells ondeecho
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 paraxargs
com a opção-0
.echo
é um shell integrado e não sofre da limitação de linha de comando deexec
(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 queromv
muitos arquivos em um único diretório, por exemplomv * destdir
? Se*
der o erro ” muitos argumentos “, posso ‘ t makexargs
para passar os caminhos como os primeiros emmv
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 paraxargs
:.... | 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.