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 eval
sea 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
declare
se evaluará la parte del valor delkey=val
argumento. (Esto+a
provocará 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
eval
soluciones 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 restablecePS1
para 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.declare
es 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.+x
es "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+c
para deshabilitar variables compuestas o+F
deshabilitar las variables flotantes. Todavía usaríaeval
donde sabes dónde estás parado.Una POSIX (se establece en
$<prefix>var
lugar de$var
evitar 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): Pkey
yval
, 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 comoPATH
oPS1
.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
-k
opción. Cuando está en vigor, cualquierdd
opció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 | grep
no muestra variables de entorno con una sola letra minúscula. El primerobash
muestra que no se pasan argumentos al script ejecutado mediante-c
, y el entorno contiene las tres variables de una letra. Laset +k
cancela-k
y muestra que el mismo comando ahora tiene argumentos pasados. (Sea=1
trató como$0
para 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=2
deberí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 ambosbash
yksh
). Lo intenté:y solo la
already_invoked_with_minus_k
variable de entorno se establece en elexec
script 'd.fuente
Mi intento:
Funciona con basura (casi) arbitraria en el RHS:
fuente
shift
lugar deshift 1
). De lo contrario, gracias!Hace algún tiempo me decidí
alias
por 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,
alias
se 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$var
variable que está evaluando no contiene bytes que no coincidan con los caracteres alfanuméricos ASCII o _.eval
se usa aquí para manejar la invocación de lo nuevoalias
desde un contexto de nombre de variable entre comillas, no para la asignación exactamente. Yeval
solo se llama si laalias
definició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 ._$var
Sin 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
$var
valor. Yeval
solo llamará a esoalias
si tampoco comienza con un número; de lo contrario,eval
solo obtiene un argumento nulo. Entonces, si se cumplen ambas condiciones, seeval
llama a laalias
definició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
alias
en este contexto es que puede imprimir su trabajo.alias
imprimirá una declaración de ejecución segura de cotización doblemente citada cuando se le solicite .SALIDA
fuente