Como causar o erro “Argument list too long”? [duplicado]

12

Contexto da pergunta: De acordo com as especificações POSIX , ARG_MAX é o máximo length de argumentos de linha de comando para a família de funções exec() . O que me leva a acreditar que é um número real de argumentos, no entanto, isso claramente não funcionou:

$ ulimit -s
8192
$ touch {1..18000}.jpg
$ rm *.jpg
$ 

Obviamente, isso funciona bem, apesar de ter mais de 8192 itens. De acordo com a resposta de D.W. , o 8192 é supostamente o tamanho em kB. Então, claramente, a suposição anterior estava errada.

É aqui que entra a questão: Como descobrir qual a quantidade de itens que realmente serão acima do limite de 8192 kB? Em outras palavras, que tipo de computação tenho que executar para garantir que *.jpg type de glob resulte em Argument list too long error?

Por favor, note que esta não é uma cópia de O que define o tamanho máximo do argumento de comando único . Eu sei sobre os valores de getconf ARG_MAX e ulimit -s , essa não é a minha pergunta. Eu preciso saber como gerar argumentos suficientes em tamanho que estarão acima do limite . Em outras palavras, preciso encontrar uma maneira de obter o erro e não evitá-lo.

    
por Sergiy Kolodyazhnyy 23.06.2018 / 19:43

4 respostas

8

Usar getconf ARG_MAX para gerar uma lista longa de x e chamar um utilitário externo com isso como seu argumento geraria um erro "Argument list too long":

$ /bin/echo $( perl -e 'print "x" x $ARGV[0]' "$(getconf ARG_MAX)" )
/bin/sh: /bin/echo: Argument list too long

O ambiente e o comprimento da string /bin/echo serão incluídos no que faz o erro ocorrer, portanto, podemos tentar encontrar o maior número possível subtraindo-os:

$ env
PATH=/usr/bin:/bin:/usr/sbin:/sbin:/usr/X11R6/bin:/usr/local/bin

(Eu iniciei este shell com env -i sh , portanto, há apenas a variável PATH no ambiente)

$ /bin/echo $( perl -e 'print "x" x ($ARGV[0] - length($ENV{"PATH"}) - length("/bin/echo"))' "$(getconf ARG_MAX)" )
sh: /bin/echo: Argument list too long

Ainda é muito longo. Por quanto?

i=0
while ! /bin/echo $( perl -e 'print "x" x ($ARGV[0] - length($ENV{"PATH"}) - length("/bin/echo") - $ARGV[1])' "$(getconf ARG_MAX)" "$i" )
do
    i=$(( i + 1 ))
done

Esse loop sai por i=8 .

Portanto, há quatro bytes que não posso explicar de imediato (quatro dos oito devem ser para o nome da variável de ambiente PATH ). Estes são os terminadores nulos para as quatro cadeias PATH , o valor de PATH , /bin/echo e a longa cadeia de caracteres x .

Note que o argumento each é terminado em null, então quanto mais argumentos você tiver para o comando, mais curto o comprimento combinado deles pode ser.

Além disso, apenas para mostrar o efeito de um ambiente grande:

$ export BIG=$( perl -e 'print "x" x $ARGV[0]' "$( getconf ARG_MAX )" )

$ /bin/echo hello
sh: /bin/echo: Argument list too long

$ /bin/echo
sh: /bin/echo: Argument list too long
    
por 24.06.2018 / 09:33
9

Em muitas distribuições do Linux, você pode descobrir qual é o valor atual de ARG_MAX executando

getconf ARG_MAX

Uma maneira simples de gerar a mensagem "Argument list too long" é realmente fornecer uma longa lista de argumentos; por exemplo, no meu sistema

/bin/echo "$(find / -xdev 2> /dev/null)"

funciona, mas

/bin/echo "$(find / -xdev 2> /dev/null)" "$(find / -xdev 2> /dev/null)"

produz

bash: /bin/echo: Argument list too long

Para uma discussão aprofundada, consulte " Argumento lista erro muito longo para comandos rm, cp, mv "no estouro de pilha.

P.S. O comprimento em questão é a quantidade real de memória necessária para armazenar os argumentos e o ambiente. Não está relacionado ao número de argumentos.

    
por 23.06.2018 / 20:03
6

Para facilitar o início de um novo shell ( exit quando concluído) e defina o limite para um valor mais baixo (100kbytes):

$ bash
$ ulimit -s 100

Com o exemplo usado, o erro pode ser acionado:

$ touch {1..100000}.jpg
bash: /usr/bin/touch: Argument list too long

Mas é melhor usar algo como echo . Entenda que um builtin pode não acionar um erro, este comando deve funcionar corretamente:

$ echo {000001..100000}6789

Observe também que a quantidade de bytes está bem acima do limite definido acima (1.1Mbyte):

$ echo {000001..100000}6789 | wc -c
1100000

Mas este comando não funciona:

$ /bin/echo {000001..100000}6789
bash: /bin/echo: Argument list too long

O limite é definido pelo tamanho da lista de argumentos em bytes adicionados ao tamanho do ambiente do shell.

    
por 24.06.2018 / 06:39
6

Em vez de listar todos os arquivos no sistema, o que leva uma eternidade e não funciona em sistemas esparsos, o comando

/bin/echo {1..200000}

é uma maneira muito mais rápida (163ms) de gerar o erro. Para mim, ARG_MAX é 2097152 (2,097,152 da ordem de 2 milhões), mas o comando ainda comete erros.

Se o seu shell não tiver {start..end} , você poderá usar o shell um pouco mais lento (mas ainda mais rápido que os arquivos de listagem)

/bin/echo $(seq 1 200000)

Se um dos comandos não funcionar, apenas aumente o valor final até que ocorra, até que bash fique sem memória ou até que seq não conte mais.

    
por 24.06.2018 / 02:23