Essa pode ser uma pergunta boba, mas eu ainda pergunto. Se eu declarei um shebang
#!/bin/bash
no começo de my_shell_script.sh
, então eu sempre tenho que invocar esse script usando 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 com ksh
shell? Estou usando o AIX.
scripting
executable
shebang
jrara
fonte
fonte
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
Respostas:
O shebang
#!
é uma instância legível por humanos de um número mágico que consiste na sequência de bytes0x23 0x21
, usada pelaexec()
família de funções para determinar se o arquivo a ser executado é um script ou um binário. Quando o shebang estiver presente,exec()
será executado o executável especificado após o shebang.Observe que isso significa que, se você chamar um script especificando o intérprete na linha de comando, como é feito nos dois casos apresentados na pergunta,
exec()
executará o intérprete especificado na linha de comando, ele nem olhará para o script.Portanto, como outros observaram, se você deseja
exec()
chamar o intérprete especificado na linha shebang, o script deve ter o bit executável definido e invocado como./my_shell_script.sh
.O comportamento é fácil de demonstrar com o seguinte script:
Explicação:
#!/bin/ksh
defineksh
para ser o intérprete.$$
manté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, /proc/$$/object/a.out é um link para o executável).readlink
produzirá 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çar, ou seja,/bin/dash
e/bin/ksh
é um link simbólico para o/etc/alternatives/ksh
qual, por sua vez, é um link simbólico para/bin/pdksh
.fonte
exec()
referida nesta resposta é uma chamada do sistema, o comandoexec
é um shell embutido, e é por isso que você não pode invocar umexec
programa do Node.js. ou Java. No entanto, qualquer comando de shell invocado por, por exemplo,Runtime.exec()
em Java é eventualmente processado pelaexec()
chamada do sistema.child_process.{exec(),execFile(),spawn()
} tudo seria implementado usando o Cexec()
(atravésprocess
).Sim. A propósito, não é uma pergunta boba. Uma referência para minha resposta está aqui . Iniciando um script com #!
É chamado de shebang ou linha "bang".
Não é nada além do caminho absoluto para o intérprete do Bash.
Consiste em um sinal numérico e um caractere de ponto de exclamação (#!), Seguido pelo caminho completo para o intérprete, 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 (assumindo que o Bash tenha sido instalado no / bin) Isso garante que o Bash seja usado para interpretar o script, mesmo se for executado sob outro shell. O shebang foi introduzido por Dennis Ritchie entre a Versão 7 Unix e a 8 no Bell Laboratories. Também foi 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 geralmente é o / bin / sh. Mas, é recomendável que você defina #! / Bin / bash line.
fonte
#!/usr/bin/perl
#!/usr/local/bin/python
#!/usr/local/bin/ruby
Outra entrada shebang comum usado para suportar múltiplos sistemas é usar env para localizar o intérprete que deseja utilizar, como#!/usr/bin/env perl
#!/usr/bin/env python
env
, qual deve ser realmente preferido? Python e Perl costumam usarenv
, enquanto em scripts de shell, isso geralmente é omitido e shebang aponta para o shell em questão.env
encontrar um programa em $ PATH é um pouco complicado. Ele não define variáveis de ambiente como o nome indica. $ PATH pode ser um resultado diferente para diferentes usuários. Mas ajuda os scripts a serem executados sem modificação em sistemas que colocam um interpretador perl razoável em algum lugar estranho.A
exec
chamada do sistema do kernel Linux entende shebangs (#!
) nativamenteQuando você faz no bash:
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#L25Ele 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:e isso funciona para qualquer linguagem de script que use
#
como caractere de comentário.E sim, você pode fazer um loop infinito com:
O Bash reconhece o erro:
#!
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á bytes7f 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:resultado:
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".
fonte
./something
de um shell não passará o caminho completo paraexec
, mas exatamente o caminho digitado. Você pode corrigir isso na sua resposta? Façaecho "$0"
no seu script e você verá que é esse o caso.De fato, se você considerar isso consequentemente, o executável observado 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 bastante inútil:
Nomeado o test.txt arquivo e definir o bit exectuable
chmod u+x test.txt
, em seguida, "chamado" que:./test.txt
. Como esperado, o conteúdo do arquivo é produzido. Nesse caso, o gato não ignora a linha shebang. Simplesmente gera todas as linhas. Qualquer intérprete útil deve, portanto, ser capaz de ignorar esta linha de conversa. Para bash, perl e PHP, é simplesmente uma linha de comentário. Então, sim, eles ignoram a linha shebang.fonte
Pelo que pude reunir, sempre que um arquivo tem um conjunto de bits executável e é chamado, 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 parecer ser um arquivo de texto com um #! combinação no início, sua execução é despachada para outro executável (geralmente um tipo de shell), um caminho para o qual deve ser especificado diretamente após o referido shebang, na mesma linha. O kernel prossegue para executar o shell e passar o arquivo para ele manipular.
Resumindo, não importa com qual shell você invoca o script - o kernel enviará a execução para a apropriada de qualquer maneira.
fonte
bash ./myscript.sh
e./myscript.sh
.