Investigación

Investigación

Este:

#!/bin/bash

# Run command ~100Kbytes long
/bin/echo $(perl -e 'print "x"x100000') | wc
# Run command ~54Kbytes long
# This line fails: line 7: /bin/echo: Argument list too long
/bin/echo $(perl -e 'print "x "x27000') | wc

# Same command, but run using xargs
# Run command ~100Kbytes long
perl -e 'print "x"x100000' | xargs -n 100000 /bin/echo | wc
# Run command ~54Kbytes long
# This line fails: xargs: /bin/echo: Argument list too long
perl -e 'print "x "x27000' | xargs -n 100000 /bin/echo | wc

funciona bien en GNU/Linux, pero las 2 líneas de 54 Kbytes fallan en MacOS X.

ARG_MAXes mucho más alto que 100 KBytes, y tenga en cuenta que las líneas de 100 Kbytes nonofalla: es la línea de 54 KBytes la que falla.

mac$ getconf ARG_MAX
262144
mac$ uname -a
Darwin macosx 11.4.2 Darwin Kernel Version 11.4.2: Thu Aug 23 16:26:45 PDT 2012; root:xnu-1699.32.7~1/RELEASE_I386 i386
# Kusalananda suggests it may be due to the size of the environment
mac$ env | wc
      27      32     956

¿Por qué falla el comando de 54 Kbytes?

¿Hay alguna manera de predecir si la lista de argumentos es demasiado larga para MacOS X sin ejecutarla?

Investigación

Este:

#!/bin/bash

runtest() {
    echo environment size:
    env | wc
    echo Run command ~100Kbytes long
    /bin/echo $(perl -e 'print "x"x100000') | wc
    echo Run command ~54Kbytes long
    # This line fails: line 7: /bin/echo: Argument list too long
    /bin/echo $(perl -e 'print "x "x27000') | wc
    
    # Same command, but run using xargs
    echo Run command ~100Kbytes long
    perl -e 'print "x"x100000' | xargs -n 100000 /bin/echo | wc
    echo Run command ~54Kbytes long
    # This line fails: xargs: /bin/echo: Argument list too long
    perl -e 'print "x "x27000' | xargs -n 100000 /bin/echo | wc
    echo
}

# Clean environment
runtest

# Make a huge environment
for a in `seq 5000`; do eval "a$a=1" ; done
for a in `seq 5000`; do eval "a$a() { 1; }" ; done
# This works as before
runtest

# Export environment
for a in `seq 5000`; do eval export a$a ; done
for a in `seq 5000`; do eval export -f a$a ; done
# Now the 100Kbytes commands fail, too
runtest

da esta salida:

environment size:
    6027    6032   47849
Run command ~100Kbytes long
       1       1  100001
Run command ~54Kbytes long
test: line 10: /bin/echo: Argument list too long
       0       0       0
Run command ~100Kbytes long
       1       1  100001
Run command ~54Kbytes long
xargs: /bin/echo: Argument list too long
       0       0       0

environment size:
    6027    6032   47849
Run command ~100Kbytes long
       1       1  100001
Run command ~54Kbytes long
test: line 10: /bin/echo: Argument list too long
       0       0       0
Run command ~100Kbytes long
       1       1  100001
Run command ~54Kbytes long
xargs: /bin/echo: Argument list too long
       0       0       0

environment size:
   16027   26032  126742
Run command ~100Kbytes long
test: line 7: /bin/echo: Argument list too long
       0       0       0
Run command ~54Kbytes long
test: line 10: /bin/echo: Argument list too long
       0       0       0
Run command ~100Kbytes long
xargs: insufficient space for argument
       0       0       0
Run command ~54Kbytes long
xargs: /bin/echo: Argument list too long
       0       0       0

Entonces Kusalananda tiene razón en queexportadoEl entorno puede tener un efecto. No está claro cuál es la fórmula para calcular esto: ¿Quizás sea simplemente el tamaño? ¿Quizás la cantidad de variables también sea importante? ¿Quizás sean sólo las longitudes de los nombres? ¿Quizás una combinación lineal de esas?

Élaúnno explica que en un entorno determinado un comando de 100 Kbytes funciona bien, pero un comando de 54 Kbytes no.

Es como si MacOS no sólo tuviera un límite en el tamaño total sino que también tuviera un límite en el número de argumentos.

Los números también tendrían sentido si MacOS usa 8 bytes adicionales por argumento:

# One big argument
100K * "x" = 100000+2 < 262144 # Works
# 27K small arguments
27K * "x " = 27K*(8+2) > 262144 # Fails
# 26K small arguments
26K * "x " = 26K*(8+2) < 262144 # Works

¿Pero MacOS hace eso?

Respuesta1

Investigaciones adicionales indican (versión de MacOS desconocida):

Effective length = 
  length of arguments +
  5 * number of arguments +
  length of body/value of exported functions/variables +
  length of names of exported functions/variables +
  4 * number of exported functions/variables

Si la longitud efectiva es < 256 Kbytes, se ejecutará el comando. No está claro si esto es cierto para todas las versiones de MacOS.

Para MacOS El Capitan 10.11.4, esto proporciona la longitud de la línea de comando pesimista (suponiendo que el comando que desea ejecutar sea /bin/echo x x x x ...):

perl -e '                                                                             
  $envc=(keys %ENV);                                                                    
  $envn=length join"",(keys %ENV);                                                      
  $envv=length join"",(values %ENV);                                                    
  $maxlen=3+(262144 - $envn - $envv) / 5 - $envc*2;                                     
  print("Max len = $maxlen\n");
'                                                        

No está claro si esto es cierto para todas las versiones de MacOS.

información relacionada