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'; $efunciona 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
dirno se exporta y$1escd "$foo"; ls, entonces:cd /starting/directory; foo=/somewhere/else; eval "$1"; pwdenumera el contenido/somewhere/elsey las impresiones/somewhere/else.cd /starting/directory; foo=/somewhere/else; (eval "$1"); pwdenumera el contenido/somewhere/elsey las impresiones/starting/directory.cd /starting/directory; foo=/somewhere/else; bash -c "$1"; pwdenumera 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 fooes más o menos equivalente aeval "$(cat foo)".evaly.dotes queevalfunciona con argumentos y.dotfunciona 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
bashde esa manera. Si debe invocarlo, utilice el POSIX garantizado incorporadosh. O(subshell eval)si desea proteger su medio ambiente.Personalmente, prefiero el caparazón
.dotsobre 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
echono le importa su conteo de argumentos.SALIDA:
¿Ver? Las comillas dobles aparecen porque
$varno se evalúa el resultado de la expansión de la shellquote-removal.SALIDA:
Pero con
evalosh:SALIDA:
Cuando usamos
evaloshel 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
evales más rápido. De la página del manual deeval:bash -cpor supuesto, ejecuta el comando en un shell bash. Una nota: utilicé/bin/echoporqueechoes un shell incorporadobash, lo que significa que no es necesario iniciar un nuevo proceso. Sustitución/bin/echodeecholabash -cprueba, se tomó1.28s. Eso es casi lo mismo. Hovever,evales más rápido para ejecutar ejecutables. La diferencia clave aquí es queevalno inicia un nuevo shell (ejecuta el comando en el actual) mientras quebash -cinicia un nuevo shell, luego ejecuta el comando en el nuevo shell. Iniciar un nuevo shell lleva tiempo, y es por eso quebash -ces más lento queeval.fuente
bash -cconevalnoexec.bash -cno es que mal ...