La exec
llamada al sistema del kernel de Linux comprende shebangs ( #!
) de forma nativa
Cuando lo haces en bash:
./something
en Linux, esto llama a la exec
llamada del sistema con la ruta ./something
.
Esta línea del núcleo se llama en el archivo pasado a exec
: https://github.com/torvalds/linux/blob/v4.8/fs/binfmt_script.c#L25
if ((bprm->buf[0] != '#') || (bprm->buf[1] != '!'))
Lee los primeros bytes del archivo y los compara con #!
.
Si la comparación es verdadera, el núcleo de Linux analiza el resto de la línea, que realiza otra exec
llamada con la ruta /usr/bin/env python
y el archivo actual como primer argumento:
/usr/bin/env python /path/to/script.py
y esto funciona para cualquier lenguaje de secuencias de comandos que se use #
como carácter de comentario.
Y sí, puedes hacer un ciclo infinito con:
printf '#!/a\n' | sudo tee /a
sudo chmod +x /a
/a
Bash reconoce el error:
-bash: /a: /a: bad interpreter: Too many levels of symbolic links
#!
Simplemente resulta ser legible para los humanos, pero eso no es obligatorio.
Si el archivo comenzó con diferentes bytes, entonces la exec
llamada al sistema usaría un controlador diferente. El otro controlador incorporado más importante es para archivos ejecutables ELF: https://github.com/torvalds/linux/blob/v4.8/fs/binfmt_elf.c#L1305 que comprueba los bytes 7f 45 4c 46
(que también son humanos legible para .ELF
). Confirmemos eso leyendo los 4 primeros bytes de /bin/ls
, que es un ejecutable ELF:
head -c 4 "$(which ls)" | hd
salida:
00000000 7f 45 4c 46 |.ELF|
00000004
Entonces, cuando el núcleo ve esos bytes, toma el archivo ELF, lo guarda en la memoria correctamente y comienza un nuevo proceso con él. Ver también: https://stackoverflow.com/questions/8352535/how-does-kernel-get-an-executable-binary-file-running-under-linux/31394861#31394861
Finalmente, puede agregar sus propios manejadores de shebang con el binfmt_misc
mecanismo. Por ejemplo, puede agregar un controlador personalizado para .jar
archivos . Este mecanismo incluso admite controladores por extensión de archivo. Otra aplicación es ejecutar de forma transparente ejecutables de una arquitectura diferente con QEMU .
Sin embargo, no creo que POSIX especifique shebangs: https://unix.stackexchange.com/a/346214/32558 , aunque sí lo menciona en las secciones de justificación y en la forma "si el sistema admite scripts ejecutables Puede pasar".
chmod +x my_shell_script.sh ; /path/to/my_shell_script.sh # or ./my_shell_script.sh if you happen to be in its directory