É possível ter um shebang que, em vez de especificar um caminho para um intérprete, tenha o nome do intérprete e permita que o shell o encontre através de $ PATH?
A pesquisa PATH é um recurso da biblioteca C padrão no espaço do usuário, assim como as variáveis de ambiente em geral. O kernel não vê variáveis de ambiente, exceto quando passa por um ambiente do chamador execvepara o novo processo.
O kernel não executa nenhuma interpretação no caminho execve(depende das funções do wrapper, como execvpexecutar a pesquisa PATH) ou em um shebang (que mais ou menos redireciona a execvechamada internamente). Então você precisa colocar o caminho absoluto no shebang¹. A implementação original do shebang era apenas algumas linhas de código e não foi significativamente expandida desde então.
Nas primeiras versões do Unix, o shell fez o trabalho de se chamar quando percebeu que você estava chamando um script. Shebang foi adicionado ao kernel por várias razões (resumindo a lógica de Dennis Ritchie :
O chamador não precisa se preocupar se um programa para executar é um shell script ou um binário nativo.
O próprio script especifica qual intérprete usar, em vez do chamador.
O kernel usa o nome do script nos logs.
Shebangs sem caminho exigiriam aumentar o kernel para acessar variáveis e processos do ambiente PATH, ou fazer com que o kernel execute um programa no espaço do usuário que execute a pesquisa PATH. O primeiro método requer a adição de uma quantidade desproporcional de complexidade ao kernel. O segundo método já é possível com um #!/usr/bin/envshebang .
¹ Se você colocar um caminho relativo, ele será interpretado em relação ao diretório atual do processo (não ao diretório que contém o script), o que dificilmente é útil em um shebang.
Não, o kernel não requer um caminho absoluto execvenem no shebang, embora faça pouco sentido ter um caminho relativo em um shebang.
Stéphane Chazelas
3
Para quem está curioso sobre como "o shebang redireciona a chamada executve internamente": na verdade, faz parte de um mecanismo genérico para executar intérpretes em executáveis que precisam deles. Os executáveis ELF vinculados dinamicamente são "interpretados" por /lib64/ld-linux-x86-64.so.2(consulte a lddsaída). O Linux o torna totalmente genérico: o binfmtsuporte (desde 2.1.43) permite registrar pares de intérprete / caminho / número mágico ou extensão de arquivo. Você pode ter PE32 .exeinvoke s winequando você executá-los, arquivos de classe e jar Java invocar java, etc. etc.
Peter Cordes
#! / usr / bin / env -S [shebang] foi necessário para executar o nó sem conhecer seu caminho (usando o nvm - que o coloca em um local diferente do que eu esperava inicialmente).
Há mais coisas acontecendo do que aparenta. #!As linhas são interpretadas pelo kernel Unix ou Linux, #!não é um aspecto dos shells. Isso significa que PATHrealmente não existe no momento em que o kernel decide o que executar.
A maneira mais comum de lidar com o desconhecimento de qual executável executar, ou chamar de perlmaneira portátil ou similar, é usar #!/usr/bin/env perl. O kernel é executado /usr/bin/env, que herda uma PATHvariável de ambiente. envachados (neste exemplo) perlem PATHe usa a execve(2)chamada de sistema para obter o kernel para executar o perlexecutável.
$ strace sleep 1
execve("/usr/bin/sleep",["sleep","1"],[/*99 vars */])=0
A conversão para o caminho completo é feita pelo shell (mais geral: no espaço do usuário). O kernel espera um nome / caminho de arquivo que possa acessar diretamente.
Se você deseja que o sistema encontre seu executável olhando através da variável PATH, você pode reescrever seu shebang como #!/usr/bin/env EXEC.
Mas também neste caso, não é o kernel que faz a pesquisa.
A conversão para o caminho completo é feita pelo shell Obrigado, embora ... o exemplo deva ilustrar isso? A meu ver, o shell está apenas em execução strace(convertido /usr/bin/straceem algum momento) com 2 argumentos.
Respostas:
A pesquisa PATH é um recurso da biblioteca C padrão no espaço do usuário, assim como as variáveis de ambiente em geral. O kernel não vê variáveis de ambiente, exceto quando passa por um ambiente do chamador
execve
para o novo processo.O kernel não executa nenhuma interpretação no caminho
execve
(depende das funções do wrapper, comoexecvp
executar a pesquisa PATH) ou em um shebang (que mais ou menos redireciona aexecve
chamada internamente). Então você precisa colocar o caminho absoluto no shebang¹. A implementação original do shebang era apenas algumas linhas de código e não foi significativamente expandida desde então.Nas primeiras versões do Unix, o shell fez o trabalho de se chamar quando percebeu que você estava chamando um script. Shebang foi adicionado ao kernel por várias razões (resumindo a lógica de Dennis Ritchie :
Shebangs sem caminho exigiriam aumentar o kernel para acessar variáveis e processos do ambiente
PATH
, ou fazer com que o kernel execute um programa no espaço do usuário que execute a pesquisa PATH. O primeiro método requer a adição de uma quantidade desproporcional de complexidade ao kernel. O segundo método já é possível com um#!/usr/bin/env
shebang .¹ Se você colocar um caminho relativo, ele será interpretado em relação ao diretório atual do processo (não ao diretório que contém o script), o que dificilmente é útil em um shebang.
fonte
execve
nem no shebang, embora faça pouco sentido ter um caminho relativo em um shebang./lib64/ld-linux-x86-64.so.2
(consulte aldd
saída). O Linux o torna totalmente genérico: obinfmt
suporte (desde 2.1.43) permite registrar pares de intérprete / caminho / número mágico ou extensão de arquivo. Você pode ter PE32.exe
invoke swine
quando você executá-los, arquivos de classe e jar Java invocarjava
, etc. etc.Há mais coisas acontecendo do que aparenta.
#!
As linhas são interpretadas pelo kernel Unix ou Linux,#!
não é um aspecto dos shells. Isso significa quePATH
realmente não existe no momento em que o kernel decide o que executar.A maneira mais comum de lidar com o desconhecimento de qual executável executar, ou chamar de
perl
maneira portátil ou similar, é usar#!/usr/bin/env perl
. O kernel é executado/usr/bin/env
, que herda umaPATH
variável de ambiente.env
achados (neste exemplo)perl
emPATH
e usa aexecve(2)
chamada de sistema para obter o kernel para executar operl
executável.fonte
A conversão para o caminho completo é feita pelo shell (mais geral: no espaço do usuário). O kernel espera um nome / caminho de arquivo que possa acessar diretamente.
Se você deseja que o sistema encontre seu executável olhando através da variável PATH, você pode reescrever seu shebang como
#!/usr/bin/env EXEC
.Mas também neste caso, não é o kernel que faz a pesquisa.
fonte
strace
(convertido/usr/bin/strace
em algum momento) com 2 argumentos.