O shebang determina o shell que executa o script?

77

Esta pode ser uma pergunta boba, mas eu ainda pergunto. Se eu declarar um shebang

#!/bin/bash 

no começo de my_shell_script.sh , então eu sempre tenho que invocar esse script usando o bash

[my@comp]$bash my_shell_script.sh

ou posso usar, por exemplo,

[my@comp]$sh my_shell_script.sh

e meu script determina o shell em execução usando o shebang? É o mesmo acontecendo com ksh shell? Estou usando o AIX.

    
por jrara 21.08.2013 / 06:08

5 respostas

111

O shebang #! é uma instância legível por humanos de um número mágico que consiste na cadeia de bytes 0x23 0x21 , que é usada pela família de funções exec() para determinar se o arquivo a ser executado é um script ou um binário. Quando o shebang estiver presente, exec() executará o executável especificado após o shebang.

Observe que isso significa que, se você invocar um script especificando o interpretador na linha de comando, como é feito em ambos casos apresentados na pergunta, exec() executará o interpretador especificado no linha de comando, nem sequer olhará para o script.

Assim, como outros notaram, se você quiser que exec() chame o interpretador especificado na linha shebang, o script deve ter o bit executável definido e chamado como ./my_shell_script.sh .

O comportamento é fácil de demonstrar com o seguinte script:

#!/bin/ksh
readlink /proc/$$/exe

Explicação:

  • #!/bin/ksh define ksh como o interpretador.

  • $$ contém o PID do processo atual.

  • /proc/pid/exe é um link simbólico para o executável do processo (pelo menos no Linux; no AIX, o /proc/$$/object/a.out é um link para o executável).

  • readlink emitirá o valor do link simbólico.

Exemplo:

Nota : Estou demonstrando isso no Ubuntu, onde o shell padrão /bin/sh é um link simbólico para traço , ou seja, /bin/dash e /bin/ksh é um link simbólico para /etc/alternatives/ksh , que por sua vez é um symlink para /bin/pdksh .

$ chmod +x getshell.sh
$ ./getshell.sh 
/bin/pdksh
$ bash getshell.sh 
/bin/bash
$ sh getshell.sh 
/bin/dash
    
por 21.08.2013 / 12:10
9

Sim, sim. Aliás, não é uma pergunta boba. Uma referência para minha resposta é aqui .  Começando um script com #!

  • É chamado de shebang ou linha "bang".

  • Não é nada além do caminho absoluto para o interpretador Bash.

  • Consiste em um sinal numérico e um caractere de ponto de exclamação (#!), seguido pelo caminho completo para o interpretador, como / bin / bash.

    Todos os scripts no Linux são executados usando o interpretador especificado em uma primeira linha Quase todos os scripts bash geralmente começam com #! / Bin / bash (supondo que o Bash tenha sido instalado em / bin) Isso garante que o Bash seja usado para interpretar o script, mesmo que seja executado em outro shell. O shebang foi introduzido por Dennis Ritchie entre a versão 7 do Unix e 8 no Bell Laboratories. Foi então também adicionado à linha BSD em Berkeley.

Ignorando uma linha de intérprete (shebang)

Se você não especificar uma linha de intérprete, o padrão será geralmente o / bin / sh. Mas, é recomendado que você defina a linha #! / Bin / bash.

    
por 21.08.2013 / 06:12
2

Na verdade, se você considerar isso, o executável anotado na linha shebang é apenas um executável. Faz sentido usar algum interpretador de texto como executável, mas não é necessário. Apenas para esclarecimento e demonstração, fiz um teste inútil:

#!/bin/cat
useless text
more useless text
still more useless text

Nomeou o arquivo test.txt e definiu o bit executável chmod u+x test.txt , depois "chamou": ./test.txt . Conforme esperado, o conteúdo do arquivo é gerado. Neste caso, o gato não ignora a linha shebang. Ele simplesmente exibe todas as linhas. Qualquer intérprete útil deve, portanto, ser capaz de ignorar essa linha de shebang. Para bash, perl e PHP, é simplesmente uma linha de comentário. Então sim, estes ignoram a linha shebang.

    
por 30.03.2017 / 08:28
2

A chamada do sistema exec do kernel Linux compreende shebangs ( #! ) nativamente

Quando você faz no bash:

./something

no Linux, isso chama a chamada de sistema exec com o caminho ./something .

Esta linha do kernel é chamada no arquivo passado para exec : link

if ((bprm->buf[0] != '#') || (bprm->buf[1] != '!'))

Isto lê os primeiros bytes do arquivo e compara-os com #! .

Se isso for verdade, então o resto da linha é analisada pelo kernel do Linux, o que faz outra chamada exec 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 um 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

#! simplesmente é legível por humanos, mas isso não é necessário.

Se o arquivo foi iniciado com bytes diferentes, a chamada do sistema exec usaria um manipulador diferente. O outro manipulador integrado mais importante é o dos arquivos executáveis do ELF: link que verifica os bytes 7f 45 4c 46 (que também podem ser lidos por .ELF ). Isso lê o arquivo ELF, coloca-o na memória corretamente e o inicia em execução. Veja também: link

Finalmente, você pode adicionar seus próprios manipuladores shebang com o mecanismo binfmt_misc . Por exemplo, você pode adicionar um manipulador personalizado para .jar files . Esse mecanismo ainda suporta manipuladores por extensão de arquivo. Outro aplicativo é executar executáveis de forma transparente uma arquitetura diferente com o QEMU .

Eu não acho que o POSIX especifique shebangs, no entanto: link , embora ele mencione isso em seções de lógica , e na forma "se scripts executáveis são suportados pelo sistema, algo pode acontecer".

    
por 28.03.2018 / 15:29
-1

Pelo que eu entendi, sempre que um arquivo tem um bit executável definido e é invocado, o kernel analisa o cabeçalho do arquivo para determinar como proceder (tanto quanto eu sei, você pode adicionar manipuladores personalizados para formatos de arquivo personalizados via LKMs). Se o arquivo parece ser um arquivo de texto com um #! combinação no início, sua execução é despachada para outro executável (geralmente uma espécie de shell), um caminho para o qual deve ser especificado diretamente após o referido shebang, na mesma linha. O kernel então executa o shell e passa o arquivo para ele manipular.

Em suma, não importa em qual shell você invocar o script - o kernel irá despachar a execução para o apropriado de qualquer forma.

    
por 21.08.2013 / 11:24