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

19

Eu comecei a me aprofundar mais no shell script, e eu sempre coloquei meu script em um arquivo, marquei chmod +x e então fiz /path/to/script.sh e deixei o interpretador usar como padrão. , que eu assumi que era zsh porque é isso que eu usei para o meu shell. Aparentemente parece que é apenas /bin/sh por padrão, mesmo se eu executar o script a partir de um prompt zsh, porque eu comecei colocando coisas específicas do zsh em meus scripts e ele 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á uma linha shebang ( #!/path/to/shell ) no começo? Eu assumo /bin/sh mas não posso confirmar.
  2. O que é considerado "melhores práticas" em termos de escrever 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 voltar ao bash se o zsh não estiver disponível? Eu tentei colocar duas linhas shebang, como abaixo, mas apenas erros com bad interpreter: /bin/zsh: no such file or directory se eu tentar em uma máquina sem zsh.

    #!/bin/zsh

    #!/bin/bash

por swrobel 08.11.2012 / 18:54

2 respostas

25

Which shell executes scripts when there's no shebang line (#!/path/to/shell) at the beginning? I assume /bin/sh but I can't confirm.

O kernel se recusa a executar tais scripts e retorna ENOEXEC, então o comportamento exato depende do programa em que você executa tal script de .

  • bash 4.2.39 - usa a si próprio
  • busybox-ash 1.20.2 - usa a si próprio
  • traço 0.5.7 - executa / bin / sh
  • fish 1.23.1 - reclama de ENOEXEC, então culpa o arquivo errado
  • AT & T ksh 93u + 2012.08.01 - usa a si próprio
  • mksh R40f - executa / bin / sh
  • pdksh 5.2.14 - executa / bin / sh
  • sh-heirloom 050706 - usa a si mesmo
  • tcsh 6.18.01 - executa / bin / sh
  • zsh 5.0.0 - executa / bin / sh
  • cmd.exe 5.1.2600 - parece engraçado para você.

Em glibc , as funções execv() ou execve() apenas retornam ENOEXEC. Mas execvp() oculta esse código de erro e invoca automaticamente / bin / sh. (Isso está documentado em exec (3p) .)

What is considered "best practices" in terms of writing shell scripts that will run on any platform? (ok, this is sort of open-ended)

Cole em sh e apenas os recursos definidos por POSIX, ou simplesmente use o bash (que é amplamente disponível) e mencione-o em 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 bash ou zsh, use #!/usr/bin/env bash em vez de codificar o caminho do shell. (No entanto, o shell POSIX tem garantia de estar em /bin/sh , então pule env nesse caso.)

(Infelizmente, mesmo /bin/sh não é sempre o mesmo. O programa GNU autoconf tem que lidar com muitas peculiaridades .

Is it possible to write a script that tries to use zsh and falls back to bash if zsh is not available? I've tried putting two shebang lines, like below, but it just errors with bad interpreter: /bin/zsh: no such file or directory out if I try it on a machine without zsh.

Só pode haver uma linha de shebang; tudo depois que o caractere de nova linha não é lido pelo kernel, e tratado como um comentário por shells.

É possível escrever um script que seja executado 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 por bash e zsh é tão diferente em vários lugares que eu não recomendo fazer isso para sua própria sanidade.

    
por 08.11.2012 / 19:37
2

1) O shell atual em que você está executando. (qualquer shell que possa ser)

2) Continue com o mesmo tipo de shell (bash / dash / ash / csh / qualquer que seja o seu sabor) e certifique-se de que suas "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 "if-then-else" para o interpreter directive . Você deve especificar um shell que deve existir em todos os sistemas aos quais você deseja dar suporte ... por exemplo, #!/bin/bash ou especifique um #!/bin/sh genérico, desde que seu script seja bastante genérico em todos os shells.

    
por 08.11.2012 / 19:37