eval
toma una cadena como argumento y la evalúa como si hubiera escrito esa cadena en una línea de comando. (Si pasa varios argumentos, primero se unen con espacios entre ellos).
${$n}
es un error de sintaxis en bash. Dentro de las llaves, solo puede tener un nombre de variable, con algunos posibles prefijos y sufijos, pero no puede tener una sintaxis bash arbitraria y, en particular, no puede usar la expansión variable. Sin embargo, hay una manera de decir "el valor de la variable cuyo nombre está en esta variable":
echo ${!n}
one
$(…)
ejecuta el comando especificado dentro de los paréntesis en un subshell (es decir, en un proceso separado que hereda todas las configuraciones, como los valores de las variables del shell actual), y recopila su salida. Así que echo $($n)
ejecuta $n
como un comando de shell y muestra su salida. Desde $n
evalúa a 1
, $($n)
intenta ejecutar el comando 1
, que no existe.
eval echo \${$n}
ejecuta los parámetros pasados a eval
. Después de la expansión, los parámetros son echo
y ${1}
. Entonces eval echo \${$n}
ejecuta el comando echo ${1}
.
Tenga en cuenta que la mayoría de las veces, debe usar comillas dobles alrededor de las sustituciones de variables y sustituciones de comandos (es decir, siempre que haya un $
):"$foo", "$(foo)"
. Siempre ponga comillas dobles alrededor de las sustituciones de variables y comandos , a menos que sepa que necesita dejarlos fuera. Sin las comillas dobles, el shell realiza la división de campos (es decir, divide el valor de la variable o la salida del comando en palabras separadas) y luego trata cada palabra como un patrón comodín. Por ejemplo:
$ ls
file1 file2 otherfile
$ set -- 'f* *'
$ echo "$1"
f* *
$ echo $1
file1 file2 file1 file2 otherfile
$ n=1
$ eval echo \${$n}
file1 file2 file1 file2 otherfile
$eval echo \"\${$n}\"
f* *
$ echo "${!n}"
f* *
eval
no se usa muy a menudo. En algunos shells, el uso más común es obtener el valor de una variable cuyo nombre no se conoce hasta el tiempo de ejecución. En bash, esto no es necesario gracias al ${!VAR}
sintaxis. eval
sigue siendo útil cuando necesita construir un comando más largo que contenga operadores, palabras reservadas, etc.
Simplemente piense en eval como "evaluar su expresión una vez más antes de la ejecución"
eval echo \${$n}
se convierte en echo $1
después de la primera ronda de evaluación. Tres cambios para notar:
- El
\$
se convirtió en$
(Se necesita la barra invertida; de lo contrario, intenta evaluar${$n}
, lo que significa una variable llamada{$n}
, que no está permitido) $n
fue evaluado a1
- El
eval
desapareció
En la segunda ronda, es básicamente echo $1
que se puede ejecutar directamente.
Entonces eval <some command>
primero evaluará <some command>
(por evaluar aquí me refiero a sustituir variables, reemplazar caracteres escapados con los correctos, etc.), y luego ejecutar la expresión resultante una vez más.
eval
se utiliza cuando desea crear variables dinámicamente o leer resultados de programas diseñados específicamente para ser leídos de esta manera. Consulte http://mywiki.wooledge.org/BashFAQ/048 para ver ejemplos. El enlace también contiene algunas formas típicas en las que eval
se utiliza y los riesgos asociados con él.
En mi experiencia, un uso "típico" de eval es para ejecutar comandos que generan comandos de shell para establecer variables de entorno.
Tal vez tenga un sistema que use una colección de variables de entorno y tenga un script o programa que determine cuáles deben configurarse y sus valores. Cada vez que ejecuta un script o programa, se ejecuta en un proceso bifurcado, por lo que todo lo que hace directamente a las variables de entorno se pierde cuando sale. Pero ese script o programa puede enviar los comandos de exportación a stdout.
Sin eval, necesitaría redirigir stdout a un archivo temporal, generar el archivo temporal y luego eliminarlo. Con eval, solo puede:
eval "$(script-or-program)"
Tenga en cuenta que las citas son importantes. Tome este ejemplo (ideal):
# activate.sh
echo 'I got activated!'
# test.py
print("export foo=bar/baz/womp")
print(". activate.sh")
$ eval $(python test.py)
bash: export: `.': not a valid identifier
bash: export: `activate.sh': not a valid identifier
$ eval "$(python test.py)"
I got activated!