Me gustaría pasar los parámetros a un script bash, dd-style. Básicamente quiero
./script a=1 b=43
tener el mismo efecto que
a=1 b=43 ./script
Pensé que podría lograr esto con:
for arg in "$@"; do
eval "$arg";
done
¿Cuál es una buena manera de garantizar que evalsea seguro, es decir, que "$arg"coincida con una asignación de variables estática (sin ejecución de código)?
¿O hay una mejor manera de hacer esto? (Me gustaría mantener esto simple).

=separador y hacer la asignación con una evaluación más cuidadosamente construida. Solo por seguridad, para uso privado, lo haría como lo hiciste.Respuestas:
Puede hacer esto en bash sin eval (y sin escape artificial):
Editar: Basado en un comentario de Stéphane Chazelas, agregué banderas a la declaración para evitar que la variable asignada ya se declare como una matriz o variable entera, lo que evitará una serie de casos en los que
declarese evaluará la parte del valor delkey=valargumento. (Esto+aprovocará un error si la variable a establecer ya se declara como una variable de matriz, por ejemplo). Todas estas vulnerabilidades se relacionan con el uso de esta sintaxis para reasignar variables existentes (matriz o entero), que normalmente serían bien conocidas. variables de shellDe hecho, esta es solo una instancia de una clase de ataques de inyección que afectarán igualmente las
evalsoluciones basadas en: sería realmente mucho mejor permitir solo nombres de argumentos conocidos que establecer ciegamente cualquier variable que esté presente en la línea de comandos. (Considere lo que sucede si se establece la línea de comandoPATH, por ejemplo. O se restablecePS1para incluir alguna evaluación que ocurrirá en la siguiente pantalla de aviso).En lugar de usar variables bash, preferiría usar una matriz asociativa de argumentos con nombre, que es más fácil de configurar y mucho más seguro. Alternativamente, podría establecer variables bash reales, pero solo si sus nombres están en una matriz asociativa de argumentos legítimos.
Como ejemplo del último enfoque:
fuente
^[[:alpha:]_][[:alnum:]_]*=:?foo=es la única forma de establecer foo en la cadena vacía, por lo que debería permitirse (en mi humilde opinión). Arreglé los soportes, gracias.declarees casi tan peligroso comoeval(incluso se puede decir peor, ya que no es tan aparente que sea tan peligroso). Intenta, por ejemplo, llamar a eso'DIRSTACK=($(echo rm -rf ~))'como argumento.+xes "no-x".-a= matriz indexada,-A= matriz asociativa,-i= variable entera. Por lo tanto: matriz no indexada, no matriz asociativa, no entero.bash, es posible que deba agregar+cpara deshabilitar variables compuestas o+Fdeshabilitar las variables flotantes. Todavía usaríaevaldonde sabes dónde estás parado.Una POSIX (se establece en
$<prefix>varlugar de$varevitar problemas con variables especiales comoIFS/PATH...):Llamado como
myscript x=1 PATH=/tmp/evil %=3 blah '=foo' 1=2, asignaría:fuente
La solución de lcd047 se refactorizó con un
DD_OPT_prefijo codificado :Frostschutz merece el crédito por la mayor parte de la refactorización.
Puse esto en un archivo fuente con una variable global:
eval "$DD_OPTS_PARSE"hace toda la magiaUna versión para funciones sería:
DD_OPTS_PARSE_LOCAL="${PARSE_AND_REMOVE_DD_OPTS/DD_OPT_/local DD_OPT_}"En uso:
eval "$DD_OPTS_PARSE_LOCAL"Hice un repositorio de esto, completo con pruebas y un archivo README.md. Luego usé esto en un contenedor CLI de API de Github que estaba escribiendo, y utilicé el mismo contenedor para configurar un clon de github de dicho repositorio (el arranque es divertido).
Paso seguro de parámetros para scripts de bash en una sola línea. Disfrutar. :)
fuente
*=*y dejar de sustituir key / val donde no hay =. (desde que estabas refactorizando): Pkeyyval, y simplemente escribireval "${1%%=*}"=\${1#*=}. Pero eso es más o menos,eval "$1"ya que en @ rici'sdeclare "$arg"no funcionará, obviamente. También tenga cuidado de configurar cosas comoPATHoPS1.case. Probablemente no importa, pero por si no lo sabías ...El shell Bourne clásico es compatible, y los shell Bash y Korn siguen siendo compatibles, una
-kopción. Cuando está en vigor, cualquierddopción de comando ' similar' en cualquier lugar de la línea de comando se convierte automáticamente en variables de entorno que se pasan al comando:Es un poco más difícil convencer de que son variables de entorno; ejecutar esto funciona para mí:
El primero
env | grepno muestra variables de entorno con una sola letra minúscula. El primerobashmuestra que no se pasan argumentos al script ejecutado mediante-c, y el entorno contiene las tres variables de una letra. Laset +kcancela-ky muestra que el mismo comando ahora tiene argumentos pasados. (Sea=1trató como$0para el guión; también puede probarlo con el eco adecuado).Esto logra lo que la pregunta pregunta: que escribir
./script.sh a=1 b=2debería ser lo mismo que escribira=1 b=2 ./script.sh.Tenga en cuenta que tiene problemas si intenta trucos como este dentro de un script:
El
"$@"es tratado literalmente; no se vuelve a analizar para encontrar variables de estilo de asignación (en ambosbashyksh). Lo intenté:y solo la
already_invoked_with_minus_kvariable de entorno se establece en elexecscript 'd.fuente
Mi intento:
Funciona con basura (casi) arbitraria en el RHS:
fuente
shiftlugar deshift 1). De lo contrario, gracias!Hace algún tiempo me decidí
aliaspor este tipo de trabajo. Aquí hay alguna otra respuesta mía:Sin embargo, a veces puede ser posible separar la evaluación y la ejecución de tales declaraciones. Por ejemplo,
aliasse puede usar para evaluar previamente un comando. En el siguiente ejemplo, la definición de la variable se guarda en un alias que solo puede declararse con éxito si la$varvariable que está evaluando no contiene bytes que no coincidan con los caracteres alfanuméricos ASCII o _.evalse usa aquí para manejar la invocación de lo nuevoaliasdesde un contexto de nombre de variable entre comillas, no para la asignación exactamente. Yevalsolo se llama si laaliasdefinición anterior es exitosa, y aunque sé que muchas implementaciones diferentes aceptarán muchos tipos diferentes de valores para nombres de alias, aún no he encontrado un shell que acepte uno completamente vacío ._$varSin embargo, la definición dentro del alias es para , y esto es para garantizar que no se sobrescriban valores de entorno significativos. No conozco ningún valor de entorno notable que comience con un _ y, por lo general, es una apuesta segura para la declaración semiprivada.De todos modos, si la definición de alias es exitosa, declarará un alias con el nombre del
$varvalor. Yevalsolo llamará a esoaliassi tampoco comienza con un número; de lo contrario,evalsolo obtiene un argumento nulo. Entonces, si se cumplen ambas condiciones, seevalllama a laaliasdefinición de variable y se guarda en elalias, después de lo cual el nuevo alias se elimina rápidamente de la tabla hash.También útil
aliasen este contexto es que puede imprimir su trabajo.aliasimprimirá una declaración de ejecución segura de cotización doblemente citada cuando se le solicite .SALIDA
fuente