Límite de entrada y línea de comando Bash

90

¿Existe algún tipo de límite de caracteres impuesto en bash (u otros shells) por cuánto tiempo puede durar una entrada? Si es así, ¿cuál es ese límite de caracteres?

Es decir, ¿es posible escribir un comando en bash que sea demasiado largo para que se ejecute la línea de comandos? Si no hay un límite obligatorio, ¿hay un límite sugerido?

Derek Halden
fuente
2
El límite de entrada es muy diferente del límite de argumentos a nivel del sistema operativo (tenga en cuenta que algunas cosas distintas de los argumentos, como las variables de entorno, también se aplican a ese). El comando generado que se pasa al sistema operativo puede tener más o menos caracteres que el comando de shell que lo generó.
Charles Duffy

Respuestas:

126

El límite de la longitud de una línea de comando no lo impone el shell, sino el sistema operativo. Este límite suele estar en el rango de cien kilobytes. POSIX denota este límite ARG_MAXy en sistemas compatibles con POSIX puede consultarlo con

$ getconf ARG_MAX    # Get argument limit in bytes

Por ejemplo, en Cygwin es 32000, y en los diferentes BSD y sistemas Linux que utilizo es entre 131072 y 2621440.

Si necesita procesar una lista de archivos que exceden este límite, es posible que desee ver la xargsutilidad, que llama a un programa repetidamente con un subconjunto de argumentos que no excede ARG_MAX.

Para responder a su pregunta específica, sí, es posible intentar ejecutar un comando con una lista de argumentos demasiado larga. El shell producirá un error con un mensaje junto con "lista de argumentos demasiado larga".

Tenga en cuenta que la entrada a un programa (como se lee en stdin o cualquier otro descriptor de archivo) no está limitada (solo por los recursos del programa disponibles). Entonces, si su script de shell lee una cadena en una variable, no está restringido por ARG_MAX. La restricción tampoco se aplica a los shell-builtins.

Jens
fuente
Buena respuesta, pero me gustaría una aclaración. Si obtuve una construcción cmd <<< "$LONG_VAR"y el valor LONG_VAR excedió el límite, ¿fallaría mi comando?
Krzysztof Jabłoński
1
@ KrzysztofJabłoński Es poco probable, porque el contenido de LONG_VARse pasa en stdin, y eso se hace completamente en el shell; no se expande como un argumento para cmd, por lo que el límite ARG_MAX para fork () / exec () no entra en juego. Es fácil probarlo usted mismo: cree una variable con contenido superior a ARG_MAX y ejecute su comando.
Jens
2
Aquí está la aclaración, a título de indicación: para un archivo m4a 8 megabytes, lo hice: blah="$(cat /home/schwager/Music/Recordings/20090420\ 131623.m4a)"; cat <<< $blah >/dev/null. No tenga en cuenta ningún error.
Mike S
3
Pequeña advertencia. Las variables de entorno también cuentan. página de manual de sysconf > Es difícil usar ARG_MAX porque no se especifica cuánto> espacio de argumento para exec (3) es consumido por las variables de entorno del usuario.
Gerrit
3
@ user188737 Siento que es una advertencia bastante grande en BUGS . Por ejemplo xargsen MacOS 10.12.6 límites de lo mucho que trata de poner en una exec()a ARG_MAX - 4096. Así que el uso de scripts xargspodría funcionar, hasta que un día alguien ponga demasiadas cosas en el entorno. Corriendo con esto ahora (solucionarlo con :) xargs -s ???.
Neuralmer
44

Ok, habitantes. Así que he aceptado los límites de longitud de la línea de comando como evangelio durante bastante tiempo. Entonces, ¿qué hacer con las suposiciones de uno? Naturalmente, compruébalos.

Tengo una máquina Fedora 22 a mi disposición (es decir, Linux con bash4). He creado un directorio con 500.000 inodos (archivos) cada uno de 18 caracteres de largo. La longitud de la línea de comando es de 9.500.000 caracteres. Creado así:

seq 1 500000 | while read digit; do
    touch $(printf "abigfilename%06d\n" $digit);
done

Y notamos:

$ getconf ARG_MAX
2097152

Sin embargo, tenga en cuenta que puedo hacer esto:

$ echo * > /dev/null

Pero esto falla:

$ /bin/echo * > /dev/null
bash: /bin/echo: Argument list too long

Puedo ejecutar un bucle for:

$ for f in *; do :; done

que es otro shell incorporado.

Lectura cuidadosa de la documentación paraARG_MAX estados, longitud máxima de argumento para las funciones ejecutivas . Esto significa: sin llamar exec, no hay ARG_MAXlimitación. Por lo tanto, explicaría por qué los elementos integrados de shell no están restringidos por ARG_MAX.

Y, de hecho, puedo lsusar mi directorio si mi lista de argumentos tiene 109948 archivos, o aproximadamente 2,089,000 caracteres (más o menos). Sin embargo, una vez que agrego un archivo de nombre de archivo de 18 caracteres más, aparece un error de lista de argumentos demasiado larga . También ARG_MAXfunciona como se anuncia: el ejecutivo está fallando con más de ARG_MAXcaracteres en la lista de argumentos, incluidos, debe tenerse en cuenta, los datos del entorno.

Mike S
fuente
Hmm. No había leído la respuesta existente para dar a entender que las incorporaciones estaban sujetas a la restricción en cuestión, pero ciertamente puedo ver cómo alguien podría hacerlo.
Charles Duffy
6
Sí, creo que es difícil recordar, especialmente para los afficianados de línea de comandos más nuevos, que la situación de llamar a un bash integrado frente a fork / ejecutar un comando es diferente en formas no obvias. Quería dejar eso en claro. Una pregunta que me hacen invariablemente en una entrevista de trabajo (como administrador de sistemas de Linux) es: "Tengo un montón de archivos en un directorio. ¿Cómo puedo recorrerlos todos ...?" El interrogador siempre se dirige hacia la límite de longitud y quiere una solución de buscar / mientras o xargs. En el futuro voy a decir, "ah, diablos, solo usa un bucle for. ¡Puede manejarlo!" :-)
Mike S
@MikeS, si bien podría hacer un bucle for, si puede usar un combo find-xargs, se bifurcará mucho menos y será más rápido. ;-)
Lester Cheung
4
@LesterCheung for f in *; do echo $f; doneno se bifurca en absoluto (todas las funciones internas). Así que no sé si un combo find-xargs será más rápido; no ha sido probado. De hecho, no sé cuál es el conjunto de problemas del OP. Quizás find /path/to/directoryno le sea útil porque devolverá el nombre de la ruta del archivo. Quizás le guste la simplicidad de un for f in *bucle. Independientemente, la conversación es sobre el límite de entrada de línea, no sobre la eficiencia. Así que sigamos en el tema, que se refiere a la longitud de la línea de comandos.
Mike S
FWIW, el problema, según recuerdo, era simplemente intentar escribir un shell en C y determinar cuánto tiempo debería permitir que las entradas fueran.
Derek Halden
-3

Hay un límite de búfer de algo así como 1024. La lectura simplemente se colgará a mitad de pegado o entrada. Para resolver esto, use la opción -e.

http://linuxcommand.org/lc3_man_pages/readh.html

-usamos Readline para obtener la línea en un shell interactivo

Cambie su lectura a read -e y el molesto bloqueo de entrada de línea desaparecerá.

Paul Kenjora
fuente
1
No se trata de read: "Es decir, ¿es posible escribir un comando en bash que sea demasiado largo para que se ejecute la línea de comandos?"
Chai T. Rex
@ ChaiT.Rex tiene razón, pero aquí está la cuestión: intente ejecutar Bash de forma interactiva sin Readline, es decir bash --noediting, y en el nuevo indicador intente ejecutar el comando echo somereallylongword, donde una palabra realmente larga tiene más de 4090 caracteres. Probado en Ubuntu 18.04, la palabra se truncó, por lo que obviamente tiene algo que ver con que Readline no esté habilitado.
Amir
@Amir ¡Interesante! ¡Estás en lo correcto! Intenté editar la respuesta, pero luego me di cuenta de que la opción -e no se aplica a bash en este contexto (en bash, sale del shell inmediatamente en caso de error). Y no estoy seguro de por qué Paul giró para leer. De todos modos, hay un límite de búfer de entre 4 y 5000 caracteres cuando bash se inicia con --noreadline. Ese es un efecto secundario que no conocía ni esperaba.
Mike S