Estaba leyendo un script bash alguien hizo y me di cuenta de que el autor no utiliza eval para evaluar una variable como un comando
, el autor usa
bash -c "$1"
en lugar de
eval "$1"
Supongo que usar eval es el método preferido y probablemente sea más rápido de todos modos. ¿Es eso cierto?
¿Hay alguna diferencia práctica entre los dos? ¿Cuáles son las diferencias notables entre los dos?
bash
shell-script
bash-script
quién soy
fuente
fuente
e='echo foo'; $e
funciona bienRespuestas:
eval "$1"
ejecuta el comando en el script actual. Puede establecer y usar variables de shell del script actual, establecer variables de entorno para el script actual, establecer y usar funciones del script actual, establecer el directorio actual, umask, límites y otros atributos para el script actual, y así sucesivamente.bash -c "$1"
ejecuta el comando en un script completamente separado, que hereda las variables de entorno, los descriptores de archivo y otro entorno de proceso (pero no transmite ningún cambio) pero no hereda la configuración interna del shell (variables del shell, funciones, opciones, trampas, etc.).Hay otra forma,
(eval "$1")
que ejecuta el comando en una subshell: hereda todo del script de llamada pero no transmite ningún cambio.Por ejemplo, suponiendo que la variable
dir
no se exporta y$1
escd "$foo"; ls
, entonces:cd /starting/directory; foo=/somewhere/else; eval "$1"; pwd
enumera el contenido/somewhere/else
y las impresiones/somewhere/else
.cd /starting/directory; foo=/somewhere/else; (eval "$1"); pwd
enumera el contenido/somewhere/else
y las impresiones/starting/directory
.cd /starting/directory; foo=/somewhere/else; bash -c "$1"; pwd
enumera el contenido de/starting/directory
(porquecd ""
no cambia el directorio actual) e imprime/starting/directory
.fuente
(eval "$1")
no tiene nada que ver con esosource
. Es solo una combinación de(…)
yeval
.source foo
es más o menos equivalente aeval "$(cat foo)"
.eval
y.dot
es queeval
funciona con argumentos y.dot
funciona con archivos.La diferencia más importante entre
Y
Es que el primero se ejecuta en una subshell y el segundo no. Asi que:
SALIDA:
SALIDA:
Sin embargo, no tengo idea de por qué alguien usaría el ejecutable
bash
de esa manera. Si debe invocarlo, utilice el POSIX garantizado incorporadosh
. O(subshell eval)
si desea proteger su medio ambiente.Personalmente, prefiero el caparazón
.dot
sobre todo.SALIDA
¿PERO LO NECESITA?
La única causa para usar, en realidad, es en el caso de que su variable realmente asigne o evalúe a otra, o la división de palabras sea importante para la salida.
Por ejemplo:
SALIDA:
Eso funciona, pero solo porque
echo
no le importa su conteo de argumentos.SALIDA:
¿Ver? Las comillas dobles aparecen porque
$var
no se evalúa el resultado de la expansión de la shellquote-removal
.SALIDA:
Pero con
eval
osh
:SALIDA:
Cuando usamos
eval
osh
el shell da un segundo paso a los resultados de las expansiones y también los evalúa como un comando potencial, por lo que las citas marcan la diferencia. También puedes hacer:SALIDA
fuente
Hice una prueba rápida:
(Sí, lo sé, usé bash -c para ejecutar el bucle, pero eso no debería hacer la diferencia).
Los resultados:
Entonces
eval
es más rápido. De la página del manual deeval
:bash -c
por supuesto, ejecuta el comando en un shell bash. Una nota: utilicé/bin/echo
porqueecho
es un shell incorporadobash
, lo que significa que no es necesario iniciar un nuevo proceso. Sustitución/bin/echo
deecho
labash -c
prueba, se tomó1.28s
. Eso es casi lo mismo. Hovever,eval
es más rápido para ejecutar ejecutables. La diferencia clave aquí es queeval
no inicia un nuevo shell (ejecuta el comando en el actual) mientras quebash -c
inicia un nuevo shell, luego ejecuta el comando en el nuevo shell. Iniciar un nuevo shell lleva tiempo, y es por eso quebash -c
es más lento queeval
.fuente
bash -c
coneval
noexec
.bash -c
no es que mal ...