Entonces, pensé que tenía una buena comprensión de esto, pero solo realicé una prueba (en respuesta a una conversación en la que no estaba de acuerdo con alguien) y descubrí que mi comprensión es defectuosa ...
Con el mayor detalle posible, ¿qué sucede exactamente cuando ejecuto un archivo en mi shell? Lo que quiero decir es que si escribo: ./somefile some arguments
en mi shell y somefile
presiono Intro (y existe en el cwd, y tengo permisos de lectura + ejecución somefile
), ¿qué sucede debajo del capó?
Yo pensaba que la respuesta fue:
- El shell hace una llamada al sistema
exec
, pasando el camino asomefile
- El kernel examina
somefile
y mira el número mágico del archivo para determinar si es un formato que el procesador puede manejar - Si el número mágico indica que el archivo está en un formato que el procesador puede ejecutar, entonces
- se crea un nuevo proceso (con una entrada en la tabla de procesos)
somefile
se lee / se asigna a la memoria. Se crea una pila y la ejecución salta al punto de entrada del código desomefile
, conARGV
inicializado a una matriz de los parámetros (achar**
,["some","arguments"]
)
- Si el número mágico es un shebang, se
exec()
genera un nuevo proceso como el anterior, pero el ejecutable utilizado es el intérprete al que hace referencia el shebang (por ejemplo,/bin/bash
or/bin/perl
) ysomefile
se pasa aSTDIN
- Si el archivo no tiene un número mágico válido, se produce un error como "archivo no válido (número mágico incorrecto): error de formato de ejecución"
Sin embargo, alguien me dijo que si el archivo es texto sin formato, el shell intenta ejecutar los comandos (como si hubiera escrito bash somefile
). No lo creía, pero lo intenté y fue correcto. Así que claramente tengo algunas ideas erróneas sobre lo que realmente sucede aquí, y me gustaría entender la mecánica.
¿Qué sucede exactamente cuando ejecuto un archivo en mi shell? (con tanto detalle es razonable ...)
source somefile
Sin./somefile
embargo, es muy diferente de un nuevo proceso que se bifurca ../somefile
haría que bash ejecutara los comandossomefile
si el archivo no tuviera un número mágico. Pensé que solo mostraría un error, y en su lugar parece que efectivamentesource somefile
somefile
trata de un archivo de texto, se genera un nuevo shell si intento ejecutarlo. Un archivo seecho $$
comporta de manera diferente si lo ejecuto vs fuente.Respuestas:
La respuesta definitiva a "cómo se ejecutan los programas" en Linux es el par de artículos en LWN.net titulados, sorprendentemente, Cómo se ejecutan los programas y Cómo se ejecutan los programas: binarios ELF . El primer artículo aborda los guiones brevemente. (Estrictamente hablando, la respuesta definitiva está en el código fuente, pero estos artículos son más fáciles de leer y proporcionan enlaces al código fuente).
Un poco de experimentación muestra que lo entendiste bien y que la ejecución de un archivo que contiene una lista simple de comandos, sin un shebang, debe ser manejada por el shell. La página de manual de execve (2) contiene el código fuente de un programa de prueba, execve; usaremos eso para ver qué sucede sin un shell. Primero, escriba un script de prueba que
testscr1
contengay otro
testscr2
, que contiene soloHaga que ambos sean ejecutables y verifique que ambos se ejecuten desde un shell:
Ahora intente nuevamente, usando
execve
(suponiendo que lo haya construido en el directorio actual):testscr1
todavía funciona, perotestscr2
produceEsto muestra que el shell se maneja de manera
testscr2
diferente. Sin embargo, no procesa el script en sí, todavía lo/bin/sh
hace; esto se puede verificar canalizandotestscr2
aless
:En mi sistema, obtengo
Como puede ver, está el shell que estaba usando,
zsh
que comenzóless
, y un segundo shell, simplesh
(dash
en mi sistema), para ejecutar el script, que se ejecutópstree
. Enzsh
esto se maneja enzexecve
inSrc/exec.c
: el shell usaexecve(2)
para intentar ejecutar el comando, y si eso falla, lee el archivo para ver si tiene un shebang, procesándolo en consecuencia (lo que el núcleo también habrá hecho), y si eso falla, intenta ejecutar el archivo consh
tal de que no haya leído ningún byte cero del archivo:bash
tiene el mismo comportamiento, implementadoexecute_cmd.c
con un comentario útil (como lo señala taliezin ):POSIX define un conjunto de funciones, conocido como las
exec(3)
funciones , que se envuelvenexecve(2)
y proporcionar esta funcionalidad también; vea la respuesta de muru para más detalles. En Linux, al menos, estas funciones son implementadas por la biblioteca C, no por el núcleo.fuente
En parte, esto depende de la
exec
función familiar particular que se use.execve
, como Stephen Kitt ha demostrado en detalle, solo ejecuta archivos en el formato binario correcto o scripts que comienzan con un shebang adecuado.Sin embargo ,
execlp
yexecvp
vaya un paso más allá: si el shebang no era correcto, el archivo se ejecuta con/bin/sh
Linux. Deman 3 exec
:POSIX ( esto es algo mío) es compatible con esto :
Esto no especifica cómo se obtiene el intérprete de comandos, por lo tanto, pero no especifica que se deba dar un error. Supongo, por lo tanto, que los desarrolladores de Linux permitieron ejecutar dichos archivos
/bin/sh
(o esto ya era una práctica común y simplemente siguieron su ejemplo).FWIW, la página de manual de FreeBSD
exec(3)
también menciona comportamientos similares:AFAICT, sin embargo, no hay usos comunes de shell
execlp
oexecvp
directamente, presumiblemente para un control más fino sobre el medio ambiente. Todos implementan la misma lógica usandoexecve
.fuente
execl
,execlp
,execle
,execv
,execvp
yexecvpe
son todas frontales a laexecve
llamada al sistema; los primeros son proporcionados por la biblioteca C, el núcleo solo conoceexecve
(yexecveat
hoy en día).Esto podría ser una adición a la respuesta de Stephen Kitt, como un comentario de la
bash
fuente en el archivoexecute_cmd.c
:fuente
El fichero es ejecutado como un script de shell, se no de origen (por ejemplo, las variables establecidas en el archivo ejecutado no afectan exterior). Probablemente vestigial del pasado brumoso, cuando había un shell y un formato ejecutable. No es un ejecutable, debe ser un script de shell.
fuente
exec()
o el caparazón? Quiero significativamente más internos