Por que não usar shebangs sem caminho?

19

É possível ter um shebang que, em vez de especificar um caminho para um interpretador, tenha o nome do interpretador e deixe o shell encontrá-lo através de $ PATH?

Se não, há algum motivo para isso?

    
por Amelio Vazquez-Reina 29.05.2013 / 16:36

3 respostas

17

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 responsável pela chamada de execve para o novo processo.

O kernel não executa nenhuma interpretação no caminho em execve (cabe às funções do invólucro como execvp executar a pesquisa PATH) ou em um shebang (que mais ou menos redireciona a chamada execve internamente). Então você precisa colocar o caminho absoluto no shebang¹. A implementação original do shebang foi apenas algumas linhas de código, e não foi significativamente expandido desde.

Nas primeiras versões do Unix, o shell fez o trabalho de invocar-se quando percebeu que você estava invocando um script. Shebang foi adicionado ao kernel por várias razões (resumindo a justificativa de Dennis Ritchie :

  • O chamador não precisa se preocupar se um programa para executar é um script de shell ou um binário nativo.
  • O próprio script especifica qual interpretador usar, em vez do chamador.
  • O kernel usa o nome do script nos logs.

Os shebangs sem caminhos requerem o aumento do kernel para acessar variáveis de ambiente e processar PATH , ou fazer com que o kernel execute um programa de 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 é interpretado relativamente ao diretório atual do processo (não ao diretório que contém o script), o que dificilmente é útil em um shebang.

    
por 30.05.2013 / 01:24
18

Há mais coisas acontecendo do que aparenta. #! linhas são interpretadas pelo kernel Unix ou Linux, #! não é um aspecto de 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 não saber qual executável executar, ou chamar perl de uma forma portátil ou similar, é usar #!/usr/bin/env perl . O kernel executa /usr/bin/env , que herda uma variável de ambiente PATH . env encontra (neste exemplo) perl in PATH e usa a chamada do sistema execve(2) para fazer com que o kernel execute o executável perl .

    
por 29.05.2013 / 17:48
4
$ 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 userspace). O kernel espera um nome de arquivo / caminho que possa acessar diretamente.

Se você quiser que o sistema encontre o seu executável observando a 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.

    
por 29.05.2013 / 16:42

Tags