A exec
chamada do sistema do kernel Linux entende shebangs ( #!
) nativamente
Quando você faz no bash:
./something
no Linux, este chama a exec
chamada de sistema com o caminho ./something
.
Essa linha do kernel é chamada no arquivo passado para exec
: https://github.com/torvalds/linux/blob/v4.8/fs/binfmt_script.c#L25
if ((bprm->buf[0] != '#') || (bprm->buf[1] != '!'))
Ele lê os primeiros bytes do arquivo e os compara #!
.
Se a comparação for verdadeira, o restante da linha será analisado pelo kernel do Linux, que fará outra exec
chamada com o caminho /usr/bin/env python
e o arquivo atual como o primeiro argumento:
/usr/bin/env python /path/to/script.py
e isso funciona para qualquer linguagem de script que use #
como caractere de comentário.
E sim, você pode fazer um loop infinito com:
printf '#!/a\n' | sudo tee /a
sudo chmod +x /a
/a
O Bash reconhece o erro:
-bash: /a: /a: bad interpreter: Too many levels of symbolic links
#!
por acaso é legível por humanos, mas isso não é necessário.
Se o arquivo exec
fosse iniciado com bytes diferentes, a chamada do sistema usaria um manipulador diferente. O outro manipulador interno mais importante é para arquivos executáveis do ELF: https://github.com/torvalds/linux/blob/v4.8/fs/binfmt_elf.c#L1305, que verifica se há bytes 7f 45 4c 46
(que também são humanos legível para .ELF
). Vamos confirmar que, lendo os 4 primeiros bytes de /bin/ls
, que é um executável ELF:
head -c 4 "$(which ls)" | hd
resultado:
00000000 7f 45 4c 46 |.ELF|
00000004
Portanto, quando o kernel vê esses bytes, ele pega o arquivo ELF, coloca-o na memória corretamente e inicia um novo processo com ele. Consulte também: https://stackoverflow.com/questions/8352535/how-does-kernel-get-an-executable-binary-file-running-under-linux/31394861#31394861
Por fim, você pode adicionar seus próprios manipuladores shebang com o binfmt_misc
mecanismo Por exemplo, você pode adicionar um manipulador personalizado para .jar
arquivos . Esse mecanismo ainda suporta manipuladores por extensão de arquivo. Outro aplicativo é executar de forma transparente executáveis de uma arquitetura diferente com o QEMU .
Eu não acho que o POSIX especifique shebangs, no entanto: https://unix.stackexchange.com/a/346214/32558 , embora mencione isso nas seções de justificativa e na forma "se scripts executáveis são suportados pelo sistema, algo pode acontecer".
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