Escrevendo scripts de shell que serão executados em qualquer shell (usando várias linhas shebang?)

19

Eu comecei a me aprofundar no script de shell e sempre jogava meu script em um arquivo, marcava-o chmod +xe fazia-o /path/to/script.she deixava que qualquer intérprete padrão fosse o seu caminho, o que eu assumi ser zsh porque é isso que Eu usei para a minha concha. Aparentemente, parece que é apenas /bin/shpor padrão, mesmo se eu executar o script a partir de um prompt do zsh, porque comecei a colocar coisas específicas do zsh nos meus scripts e está falhando a menos que eu execute zsh /path/to/script.sh.

Para chegar ao ponto, aqui estão minhas perguntas:

  1. Qual shell executa scripts quando não há nenhuma linha shebang ( #!/path/to/shell) no início? Presumo, /bin/shmas não posso confirmar.
  2. O que é considerado "práticas recomendadas" em termos de escrita de scripts de shell que serão executados em qualquer plataforma? (ok, isso é meio que aberto)
  3. É possível escrever um script que tente usar o zsh e volte ao bash se o zsh não estiver disponível? Eu tentei colocar duas linhas shebang, como abaixo, mas apenas erros bad interpreter: /bin/zsh: no such file or directoryse eu tentar em uma máquina sem zsh.

    #!/bin/zsh

    #!/bin/bash

swrobel
fonte

Respostas:

26

Qual shell executa scripts quando não há uma linha shebang (#! / Path / to / shell) no início? Presumo / bin / sh, mas não posso confirmar.

O kernel se recusa a executar tais scripts e retornos ENOEXEC, de modo que o comportamento exato depende do programa que você executar um script como a partir .

  • bash 4.2.39 - usa-se
  • busybox-ash 1.20.2 - usa-se
  • traço 0.5.7 - execuções / bin / sh
  • fish 1.23.1 - reclama do ENOEXEC e culpa o arquivo errado
  • AT&T ksh 93u + 2012.08.01 - usa-se
  • mksh R40f - execuções / bin / sh
  • pdksh 5.2.14 - execuções / bin / sh
  • sh-heirloom 050706 - usa-se
  • tcsh 6.18.01 - execuções / bin / sh
  • zsh 5.0.0 - execuções / bin / sh
  • cmd.exe 5.1.2600 - parece engraçado.

Na glibc , funciona execv()ou execve()simplesmente retorna ENOEXEC. Mas execvp()oculta esse código de erro e chama automaticamente / bin / sh. (Isso está documentado em exec (3p) .)

O que é considerado "práticas recomendadas" em termos de escrita de scripts de shell que serão executados em qualquer plataforma? (ok, isso é meio que aberto)

Atenha-se a she somente aos recursos definidos pelo POSIX ou apenas faça o bash completo (que está amplamente disponível) e mencione-o nos seus requisitos se for distribuí-lo.

(Agora que penso nisso, o Perl - ou talvez o Python - seria ainda mais portátil, sem mencionar uma sintaxe melhor.)

Sempre adicione a linha shebang. Se estiver usando o bash ou o zsh, use em #!/usr/bin/env bashvez de codificar o caminho do shell. (No entanto, é garantido que o shell POSIX esteja em /bin/sh, portanto, pule envnesse caso.)

(Infelizmente, nem /bin/shsempre é o mesmo. O programa GNU autoconf precisa lidar com muitas peculiaridades .)

É possível escrever um script que tente usar o zsh e volte ao bash se o zsh não estiver disponível? Eu tentei colocar duas linhas shebang, como abaixo, mas apenas erros com intérprete incorreto: / bin / zsh: não existe esse arquivo ou diretório se eu tentar em uma máquina sem zsh.

Só pode haver uma linha shebang; tudo depois do caractere de nova linha nem é lido pelo kernel e tratado como um comentário pelos shells.

É possível escrever um script que execute como #!/bin/sh, verifique qual shell está disponível e execute exec zsh "$0" "$@"ou exec bash "$0" "$@"dependendo do resultado. No entanto, a sintaxe usada pelo bash e pelo zsh é tão diferente em vários lugares que eu não recomendaria fazer isso por sua própria sanidade.

gravidade
fonte
1
como você rastreou o que cada shell estava realmente chamando quando recebeu o ENOEXEC?
swrobel
2
@Srobrobel: Usando strace -f -e fork,clone,execve. Algumas conchas foram executadas /bin/shapós falha; outros interpretaram eles mesmos o roteiro.
grawity
1
@Srobrobel: Outro método é executar um script que consiste em readlink /proc/$$/exe.
grawity
2
Veja também a resposta de Stéphane Chazelas para Qual interpretador de shell executa um script sem shebang? (duplicada entre sites da sub-pergunta # 1)
G-Man diz 'Reinstate Monica'
1
Para cshe tcsh, o comportamento depende se o script começa com #(nesse caso, eles se invocam em vez de sh para interpretar o script). Isso remonta ao tempo em que o csh suportou comentários, mas não o shell Bourne, então a #foi uma dica de que era um script csh.
SCH
2

1) O shell atual em que você está executando. (Qualquer que seja o shell)

2) Adira ao mesmo tipo de shell (bash / dash / ash / csh / qualquer que seja o seu sabor) e verifique se as "plataformas suportadas" instalam o shell que você deseja usar por padrão. Além disso, tente usar comandos comumente disponíveis nos sistemas. Evite opções específicas da máquina.

3) Não existe realmente uma lógica "se-então-outro" no interpreter directive. Você deve especificar um shell que deve existir em todos os sistemas que você deseja oferecer suporte ... #!/bin/bashou seja, especificar um genérico #!/bin/sh, desde que seu script seja bastante genérico em todos os shells.

TheCompWiz
fonte