É 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?
Caso contrário, existe uma razão para isso?
É 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?
Caso contrário, existe uma razão para isso?
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, como execvp
executar a pesquisa PATH) ou em um shebang (que mais ou menos redireciona a execve
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.
execve
nem no shebang, embora faça pouco sentido ter um caminho relativo em um shebang.
/lib64/ld-linux-x86-64.so.2
(consulte a ldd
saída). O Linux o torna totalmente genérico: o binfmt
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 s wine
quando você executá-los, arquivos de classe e jar Java invocar java
, 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 que PATH
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 uma PATH
variável de ambiente. env
achados (neste exemplo) perl
em PATH
e usa a execve(2)
chamada de sistema para obter o kernel para executar o perl
executá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.
strace
(convertido /usr/bin/strace
em algum momento) com 2 argumentos.