shebangs com caminhos absolutos são padrão (POSIX)?

6

EDIT: A pergunta e as respostas estão corretas, mas o problema que eu disse aqui não é. O mantenedor realmente RECUSOU para usar /usr/bin/env como uma solução e, em vez disso, recriou o script como sh , e isso quebrou outras instalações de usuários. Portanto, usar env para localizar bash não é POSIX, mas é o padrão "suficiente" para ser considerado um padrão.

Estou tendo alguns erros na instalação de software no nixos (especificamente na haskell stack ) e depois de algumas pesquisas na internet, encontrei alguns exemplos de pessoas com problemas com o caminho específico do software instalado. Aqui um exemplo em que um mantenedor reverteu uma modificação em uma solução /usr/bin/env ao encontrar o bash porque ele quebrou outras instalações de usuários .

Então, referindo-se a env em um shebang sem informar o caminho absoluto da instalação (confiando no caminho de busca do sistema) é algo que poderia ser considerado errado?

Quero dizer, ok usando

#!env bash

em vez de

#!/usr/bin/env bash

se o caminho absoluto de instalação para env em si não é padrão em todos os sistemas?

    
por flavio 20.02.2017 / 03:23

2 respostas

3

env está presente em /usr/bin em praticamente todos os sistemas semelhantes ao Unix que ainda existem no século XXI. As duas exceções que conheço são o SCO OpenServer (que ainda alimenta alguns servidores muito antigos) e o NextSTEP (não pode haver muito hardware suportado que não tenha desaparecido). Para portabilidade, use #!/usr/bin/env . Qualquer outra coisa é menos portável (exceto #!/bin/sh , que carrega seus próprios problemas e só é útil se você planeja executar seu script no SCO).

POSIX e Single Unix não definem /usr/bin/env , ou /bin/sh , ou qualquer caminho absoluto diferente de / , /tmp e algumas entradas em /dev . /usr/bin/env não é um padrão Unix formal, mas é um padrão de fato.

#!env é completamente inútil. A pesquisa do Shebang não usa a variável PATH , é feita pelo kernel. (E, se fizesse a pesquisa PATH, você também pode escrever #!bash diretamente)

#!/usr/bin/env bash está perfeitamente bem para um script bash e eu questiono a sabedoria do mantenedor que rejeitou uma mudança de #!/bin/bash . Parece que o mantenedor ficou irritado com a solicitação e não levou muito a sério. Mudar para usar sh padrão em vez de bash é ainda melhor para portabilidade, mas aparentemente isso não funcionou (o script provavelmente tinha uma construção não padronizada). Se a conversão do script para funcionar em outros shells não for possível, o script ainda deve ter sido alterado para usar #!/usr/bin/env bash em vez de #!/bin/bash .

    
por 21.02.2017 / 02:24
4

POSIX não especifica exatamente como o shebang deve ser interpretado. Citando a exec família de funções RACIONAL :

One common historical implementation is that the execl(), execv(), execle(), and execve() functions return an [ENOEXEC] error for any file not recognizable as executable, including a shell script. When the execlp() and execvp() functions encounter such a file, they assume the file to be a shell script and invoke a known command interpreter to interpret such files. This is now required by POSIX.1-2008. These implementations of execvp() and execlp() only give the [ENOEXEC] error in the rare case of a problem with the command interpreter's executable file. Because of these implementations, the [ENOEXEC] error is not mentioned for execlp() or execvp(), although implementations can still give it.

Another way that some historical implementations handle shell scripts is by recognizing the first two bytes of the file as the character string "#!" and using the remainder of the first line of the file as the name of the command interpreter to execute.

One potential source of confusion noted by the standard developers is over how the contents of a process image file affect the behavior of the exec family of functions. The following is a description of the actions taken:

  1. If the process image file is a valid executable (in a format that is executable and valid and having appropriate privileges) for this system, then the system executes the file.

  2. If the process image file has appropriate privileges and is in a format that is executable but not valid for this system (such as a recognized binary for another architecture), then this is an error and errno is set to [EINVAL] (see later RATIONALE on [EINVAL]).

  3. If the process image file has appropriate privileges but is not otherwise recognized:

    1. If this is a call to execlp() or execvp(), then they invoke a command interpreter assuming that the process image file is a shell script.

    2. If this is not a call to execlp() or execvp(), then an error occurs and errno is set to [ENOEXEC].

E, mais cedo, na DESCRIPTION , diz que execlp e execvp devem executar scripts com sh :

In the cases where the other members of the exec family of functions would fail and set errno to [ENOEXEC], the execlp() and execvp() functions shall execute a command interpreter and the environment of the executed command shall be as if the process invoked the sh utility using execl() as follows:

execl(<shell path>, arg0, file, arg1, ..., (char *)0);

where <shell path> is an unspecified pathname for the sh utility, file is the process image file, and for execvp(), where arg0, arg1, and so on correspond to the values passed to execvp() in argv[0], argv2, and so on.

Portanto, essas funções executam o equivalente a sh file ... . E quando o script é executado a partir de um shell POSIX, os efeitos do shebang não são especificados. Veja 2.1, Introdução à Shell :

  1. The shell reads its input from a file (see sh), from the -c option or from the system() and popen() functions defined in the System Interfaces volume of POSIX.1-2008. If the first line of a file of shell commands starts with the characters "#!", the results are unspecified.

Zsh não se importa, o bash faz:

$ cat foo.sh
#! env perl
echo $0
$ zsh -c ./foo.sh
Can't locate object method "echo" via package "./foo.sh" (perhaps you forgot to load "./foo.sh"?) at ./foo.sh line 2.
$ bash -c ./foo.sh
bash: ./foo.sh: env: bad interpreter: No such file or directory

Não confie em não especificar PATH lookups no shebang. (Eu sei que eu corri zsh -c ./foo.sh em vez de zsh foo.sh , no entanto, a intenção aqui era mostrar o que os shells fazem na execução de comandos podem diferir.)

    
por 20.02.2017 / 04:55

Tags