eval
y exec
ambos están integrados en comandos de bash (1) que ejecutan comandos.
También veo que exec
tiene algunas opciones, pero ¿es esa la única diferencia? ¿Qué pasa con su contexto?
bash
shell
shell-builtin
Willian Paixao
fuente
fuente
Respuestas:
eval
yexec
son bestias completamente diferentes. (Aparte del hecho de que ambos ejecutarán comandos, pero también todo lo que haces en un shell).Lo que
exec cmd
hace es exactamente lo mismo que solo ejecutarcmd
, excepto que el shell actual se reemplaza con el comando, en lugar de que se ejecute un proceso separado. Internamente, ejecutar say/bin/ls
llamaráfork()
para crear un proceso secundario y luegoexec()
en el secundario para ejecutar/bin/ls
.exec /bin/ls
por otro lado no se bifurcará, sino que simplemente reemplazará la carcasa.Comparar:
con
echo $$
imprime el PID del shell que comencé, y el listado/proc/self
nos da el PID dells
que se ejecutó desde el shell. Por lo general, las ID de proceso son diferentes, pero conexec
el shell yls
tienen la misma ID de proceso. Además, el siguiente comandoexec
no se ejecutó, ya que se reemplazó el shell.Por otra parte:
eval
ejecutará los argumentos como un comando en el shell actual. En otras palabras,eval foo bar
es lo mismo que justofoo bar
. Pero las variables se expandirán antes de la ejecución, por lo que podemos ejecutar comandos guardados en variables de shell:Será no crear un proceso hijo, por lo que la variable se establece en el shell actual. (Por supuesto
eval /bin/ls
, creará un proceso hijo, de la misma manera que lo/bin/ls
haría un viejo ).O podríamos tener un comando que genere comandos de shell. La ejecución
ssh-agent
inicia el agente en segundo plano y genera un montón de asignaciones variables, que podrían establecerse en el shell actual y ser utilizadas por los procesos secundarios (losssh
comandos que ejecutaría). Porssh-agent
lo tanto, se puede comenzar con:Y el shell actual obtendrá las variables para que otros comandos hereden.
Por supuesto, si la variable
cmd
contiene algo asírm -rf $HOME
, entonces ejecutareval "$cmd"
no sería algo que querría hacer. Incluso cosas como sustituciones de mando dentro de la cadena serían procesados, por lo que uno debe realmente estar seguro de que la entradaeval
es seguro antes de usarla.A menudo, es posible evitar
eval
y evitar incluso mezclar accidentalmente código y datos de manera incorrecta.fuente
eval
en primer lugar a esta respuesta también. Cosas como modificar variables indirectamente se pueden hacer en muchos shells a través dedeclare
/typeset
/nameref
y expansiones como${!var}
, por lo que usaría esas en lugar de aeval
menos que realmente tuviera que evitarlo.exec
No crea un nuevo proceso. Se reemplaza el proceso actual con el nuevo comando. Si hizo esto en la línea de comando, finalizará efectivamente su sesión de shell (¡y tal vez cierre la sesión o cierre la ventana de terminal!)p.ej
Aquí estoy
ksh
(mi caparazón normal). Comienzobash
y luego dentro de fiesta Iexec /bin/echo
. Podemos ver que luego volví a entrarksh
porque elbash
proceso fue reemplazado por/bin/echo
.fuente
TL; DR
exec
se usa para reemplazar el proceso actual del shell con nuevo y manejar la redirección de flujo / descriptores de archivo si no se ha especificado ningún comando.eval
se usa para evaluar cadenas como comandos. Ambos pueden usarse para construir y ejecutar un comando con argumentos conocidos en tiempo de ejecución, peroexec
reemplaza el proceso del shell actual además de ejecutar comandos.ejecutivo incorporado
Sintaxis:
Según el manual, si hay un comando especificado, este incorporado
En otras palabras, si estaba ejecutando
bash
con PID 1234 y si tuviera que ejecutarexec top -u root
dentro de ese shell, eltop
comando tendrá PID 1234 y reemplazará su proceso de shell.¿Dónde es esto útil? En algo conocido como scripts de envoltura. Tales scripts crean conjuntos de argumentos o toman ciertas decisiones sobre qué variables pasar al entorno, y luego se usan
exec
para reemplazarse con cualquier comando que se especifique, y, por supuesto, proporcionan esos mismos argumentos que el script de envoltura ha desarrollado a lo largo del camino.Lo que también dice el manual es que:
Esto nos permite redirigir cualquier cosa desde las secuencias de salida de shells actuales a un archivo. Esto puede ser útil para fines de registro o filtrado, donde no desea ver los
stdout
comandos, sino solostderr
. Por ejemplo, así:Este comportamiento lo hace útil para iniciar sesión en scripts de shell , redirigir secuencias a archivos o procesos separados y otras cosas divertidas con descriptores de archivo.
En el nivel del código fuente, al menos para la
bash
versión 4.3, elexec
incorporado está definido enbuiltins/exec.def
. Analiza los comandos recibidos, y si hay alguno, pasa cosas a lashell_execve()
función definida en elexecute_cmd.c
archivo.Para resumir, existe una familia de
exec
comandos en lenguaje de programación C, yshell_execve()
es básicamente una función de envoltura deexecve
:eval incorporado
Los estados del manual bash 4.3 (énfasis agregado por mí):
Tenga en cuenta que no se produce un reemplazo del proceso. A diferencia de
exec
donde el objetivo es simular laexecve()
funcionalidad, la funcióneval
incorporada solo sirve para "evaluar" argumentos, como si el usuario los hubiera escrito en la línea de comandos. Como tal, se crean nuevos procesos.¿Dónde podría ser útil? Como Gilles señaló en esta respuesta , "... 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". Personalmente, lo he usado en un par de secuencias de comandos en Ubuntu donde era necesario ejecutar / evaluar un comando basado en el espacio de trabajo específico que el usuario estaba usando actualmente.
En el nivel del código fuente, se define
builtins/eval.def
y pasa la cadena de entrada analizada aevalstring()
funcionar.Entre otras cosas,
eval
puede asignar variables que permanecen en el entorno actual de ejecución de shell, mientrasexec
que no puede:fuente
¿Cómo? El punto
eval
es que de ninguna manera crea un proceso hijo. Si lo hagoen un shell, luego el shell actual habrá cambiado de directorio. Tampoco
exec
crea un nuevo proceso hijo, sino que cambia el ejecutable actual (es decir, el shell) para el dado; la identificación del proceso (y los archivos abiertos y otras cosas) permanecen igual. A diferencia deeval
, unexec
no volverá al shell de llamada a menos que elexec
mismo falle debido a que no puede encontrar o cargar el ejecutable o morir por problemas de expansión de argumentos.eval
básicamente interpreta sus argumentos como una cadena después de la concatenación, es decir, hará una capa adicional de expansión de comodines y división de argumentos.exec
no hace nada de esofuente
Evaluación
Estos trabajan:
Sin embargo, estos no:
Procesar reemplazo de imagen
Este ejemplo demuestra cómo
exec
reemplaza la imagen de su proceso de llamada:¡Observe que se
exec echo $$
ejecutó con el PID de la subshell! Además, después de que se completó, volvimos a nuestrosh$
shell original .Por otro lado,
eval
no no sustituir la imagen del proceso. Más bien, ejecuta el comando dado como lo haría normalmente dentro del shell. (Por supuesto, si ejecuta un comando que requiere que se genere un proceso ... ¡lo hace!)fuente
exec
)