É correto usar / bin / sh no hashbang se o shell Bourne não estiver disponível em uma distribuição?

15

Geralmente, scripts shell conter o seguinte comentário na primeira linha do arquivo script: #!/bin/sh. De acordo com as pesquisas que fiz, isso é chamado de "hash bang" e é um comentário convencional. Este comentário informa Unix que este arquivo é executado pela Shell Bourne sob o diretório /bin.

Minha pergunta começa nesse ponto. Até agora eu não vi esse comentário como #!/bin/bash. É sempre #!/bin/sh. No entanto, as distribuições do Ubuntu não possuem o programa Bourne Shell. Eles têm o Bourne Again Shell (bash).

Nesse ponto, é correto colocar o comentário #!/bin/shem shell scripts escritos nas distribuições do Ubuntu?

Goktug
fonte
1
Veja minha resposta a esta pergunta com falha no servidor: #! / Bin / sh vs #! / Bin / bash para obter a portabilidade máxima .
Gordon Davisson
Mais comumente chamadoshebang
fpmurphy

Respostas:

16

#!/bin/shdeve funcionar em todas as distribuições do Unix e do tipo Unix. Geralmente, é considerado o hashbang mais portátil, desde que o script seja mantido em conformidade com o POSIX. O /bin/shshell deve ser um shell que implementa o padrão de shell POSIX, independentemente do shell atual que se disfarça de /bin/shshell.


#!/bin/shagora é normalmente apenas um link, já que o shell Bourne não é mais mantido. Em muitos sistemas Unix, /bin/shhaverá um link para , /bin/kshou /bin/ash, em muitos sistemas Linux baseados em RHEL, será um link /bin/bash, no entanto, no Ubuntu e em muitos sistemas baseados no Debian, será um link /bin/dash. Todos os shells, quando chamados como sh, entrarão no modo de compatibilidade POSIX.

O hashbang é um espaço reservado importante porque permite uma portabilidade muito maior do que outros métodos, desde que seu script seja estritamente compatível com POSIX (repetido para enfatizar a importância).

Nota: Quando bashé chamado no modo POSIX, ainda permite algumas coisas não POSIX [[, como matrizes e muito mais. Essas coisas podem falhar em um não- bashsistema.

Jesse_b
fonte
3
"no Ubuntu, é um link para / bin / dash" e, em geral, outros sistemas baseados no Debian. O IIRC no FreeBSD / GhostBSD também é um link simbólico /bin/ash.
Sergiy Kolodyazhnyy
Para ser totalmente portátil, coloque um espaço entre o shebang e o caminho (absoluto) do intérprete. Alguns sistemas procuram em #! /vez de apenas #!.
Simon Richter
5
@SimonRichter Uma referência a isso seria agradável de ver.
Kusalananda
@SergiyKolodyazhnyy A versão instalada do sh no FreeBSD é ash e não um link simbólico.
Rob
2
@ Kusalananda, hmm, esta página diz que isso é um mito, por isso provavelmente pode ser desconsiderado.
Simon Richter
12

Você entendeu ao contrário. /bin/shhoje em dia quase nunca é uma concha Bourne, e é quando é que você tem um problema ao usar um #! /bin/shestrondo.

O shell Bourne foi um shell escrito no final dos anos 70 e substituiu o shell Thompson anterior (também chamado sh). No início dos anos 80, David Korn escreveu algumas extensões para o shell Bourne, corrigiu alguns bugs e projetou constrangimentos (e introduziu alguns) e o chamou de shell Korn.

No início dos anos 90, o POSIX especificou o sh idioma com base em um subconjunto do shell Korn e a maioria dos sistemas agora mudou /bin/shpara o shell Korn ou um shell compatível com essa especificação. No caso dos BSDs, eles mudaram gradualmente o seu /bin/sh, inicialmente (depois que não podiam mais usar o shell Bourne por motivos de licença) o shell Almquist, um clone do shell Bourne com algumas extensões ksh para tornar-se compatível com POSIX.

Hoje, todos os sistemas POSIX têm um shell chamado sh(na maioria das vezes, mas não necessariamente /bin, o POSIX não especifica o caminho dos utilitários especificados) que é principalmente compatível com POSIX. Geralmente é baseado em ksh88, ksh93, pdksh, bash, ash ou zsh², mas não no shell Bourne, pois o shell Bourne nunca foi compatível com POSIX³. Algumas dessas conchas ( bash, zsh, yashe alguns pdkshderivados de permitir um modo compatível com POSIX quando invocada como she são menos compatíveis em contrário).

bash(a resposta da GNU para o shell Korn) é na verdade o único shell de código aberto (e pode-se dizer que atualmente é mantido, pois os outros geralmente são baseados no ksh88, que não recebeu nenhum novo recurso desde os anos 90) que foi certificado como sendo compatível com POSIX sh(como parte da certificação macOS).

Quando você escreve um script com um #! /bin/sh -she-bang, deve usar uma shsintaxe padrão (e também deve usar a sintaxe padrão para os utilitários usados ​​nesse script, se quiser ser portátil, não é apenas o shell que está envolvido na interpretação de um shell script), então não importa qual implementação desse shinterpretador de sintaxe padrão seja usada ( ksh, bash...).

Não importa que essas cascas tenham extensões acima do padrão, desde que você não as utilize. É como escrever código C, desde que você escreva código C padrão e não use extensões de um compilador (como gcc) ou outro, seu código deve compilar OK, independentemente da implementação do compilador, desde que o compilador seja compatível.

Aqui, com o seu #! /bin/shshe-bang, o seu principal problema seria os sistemas onde /bin/shé o shell Bourne que, por exemplo, não suporta características padrão, como $((1+1)), $(cmd), ${var#pattern}... Em que caso você pode precisar de soluções alternativas como:

#! /bin/sh -
if false ^ true; then
  # in the Bourne shell, ^ is an alias for |, so false ^ true returns
  # true in the Bourne shell and the Bourne shell only.
  # Assume the system is Solaris 10 (older versions are no longer maintained)
  # You would need to adapt if you need to support some other system
  # where /bin/sh is the Bourne shell.
  # We also need to fix $PATH as the other utilities in /bin are
  # also ancient and not POSIX compatible.
  PATH=`/usr/xpg6/bin/getconf PATH`${PATH:+:}$PATH || exit
  export PATH
  exec /usr/xpg4/bin/sh "$0" "$@"
  # that should give us an environment that is mostly  compliant
  # to the Single UNIX Specification version 3 (POSIX.2004), the
  # latest supported by Solaris 10.
fi
# rest of the script

A propósito, o Ubuntu /bin/shnão é bashpor padrão. Hoje em dashdia, um shell baseado no NetBSD sh, ele próprio baseado no shell Almquist, que é principalmente compatível com POSIX, exceto que ele não suporta caracteres de vários bytes. Em outros sistemas baseados em Debian Ubuntu e, você pode escolher entre bashe dashpara /bin/shcom dpkg-reconfigure dash) 4 . shOs scripts enviados com o Debian devem funcionar da mesma forma nos dois shells, à medida que são gravados no padrão de política Debian (um superconjunto do padrão POSIX). Você provavelmente vai descobrir que eles também trabalho OK em zsh's shemulação ou bosh(provavelmente não ksh93, nem yashque não tem um localbuiltin (exigido pela política Debian, mas não POSIX)).

Todos os sistemas no escopo em unix.stackexchange.com possuem um POSIX em sh algum lugar. A maioria deles possui um /bin/sh(você pode encontrar outros muito raros que não têm um /bindiretório, mas provavelmente não se importa com isso), e isso geralmente é um shinterpretador POSIX (e, em casos raros, um shell Bourne (não padrão) )

Mas shé o único executável de interpretador de shell que você pode encontrar em um sistema. Para os outros shells, você pode ter certeza de que o macOS, Cygwin e a maioria das distribuições GNU / Linux terão bash. Os sistemas operacionais derivados do SYSV (Solaris, AIX ...) geralmente terão o ksh88, possivelmente o ksh93. O OpenBSD, MirOS, terá um derivado pdksh. o macOS terá zsh. Mas fora disso, não haverá garantia. Não há garantia de que um bashou outro desses shells será instalado em /binou em outro local (geralmente é encontrado nos /usr/local/binBSDs quando instalados, por exemplo). E, claro, nenhuma garantia da versão do shell que será instalada.

Observe que o #! /path/to/executable não é uma convenção , é um recurso de todos os kernels do tipo Unix ( introduzidos no início dos anos 80 por Dennis Ritchie ) que permite executar arquivos arbitrários, especificando o caminho do intérprete na primeira linha, começando com #!. Pode ser qualquer executável.

Quando você executa um arquivo cuja primeira linha começa com #! /some/file some-optional-arg, o kernel acaba executando/some/file com some-optional-arg, o caminho do script e os argumentos originais como argumentos. Você pode fazer essa primeira linha #! /bin/echo testpara ver o que está acontecendo:

$ ./myscript foo
test ./myscript foo

Quando você usa em /bin/sh -vez de /bin/echo test, o kernel executa/bin/sh - ./myscript foo , shinterpreta o código de conteúdo armazenado myscripte ignora a primeira linha como um comentário (começa com #).


¹ Provavelmente, o único sistema hoje em que algum de nós se depara com um /bin/shbaseado no shell Bourne é o Solaris 10. O Solaris é um dos poucos Unices que decidiu manter um shell Bourne lá para compatibilidade com versões anteriores (o POSIXsh linguagem não é totalmente compatível com versões anteriores do shell Bourne) e (pelo menos para implantações de desktop e servidor completo) têm o POSIX em shoutro lugar (em /usr/xpg4/bin/sh, com base no ksh88), mas isso mudou no Solaris 11, onde /bin/shagora é o ksh93. Os outros são quase extintos.

² O /bin/shMacOS / X costumava serzsh , mas depois mudou para bash. Não é zsho foco principal a ser usado como uma shimplementação POSIX . Seu shmodo é principalmente poder incorporar ou chamar o código sourcePOSIX ( ) shnos zshscripts

³ Recentemente, a @schily estendeu o shell do OpenSolaris (base no shell do SVR4, baseado no shell Bourne) para se tornar compatível com POSIX, chamado, boshmas não sei que ele ainda é usado em qualquer sistema. Junto com ksh88isso, é um segundo shell compatível com POSIX, com base no código do shell Bourne

4 Nas versões mais antigas, você também pode usar mkshou sua lkshencarnação mais POSIX . Esse é o shell do MirOS (anteriormente MirBSD) baseado no pdksh, baseado no shell Forsyth (outra reimplementação do shell Bourne))

Stéphane Chazelas
fonte
Pequenas coisas (sobre o código do shell no meio da resposta): você não deve usar logo exec sh "$0" "$@"após definir o PATH? Isso deveria pegar shno lugar correto, eu teria pensado.
Kusalananda
1
@ Kusalananda, isso deve funcionar, mas é mais arriscado, pois poderíamos terminar em um loop infinito se algo estiver errado (como sh com permissões erradas, getconf modificado ...). De qualquer forma, o resto é específico do Solaris 10, para que também possamos codificar tudo, incluindo o conteúdo de $PATH.
Stéphane Chazelas
Qualquer citação para o OSX usando o ksh como seu shell POSIX. Seu shell padrão costumava ser o tcsh, mas eu não me lembro de o bash não estar sendo usado, especialmente porque o Korn Shell não era de código aberto até o OSX ser lançado
#
1
@ Mark, eu não disse que o OSX já usou o ksh. Eu disse que costumava ser o zsh e eles mudaram para o bash (uma compilação especial do bash).
Stéphane Chazelas
1
@fpmurphy, se você olhar para as versões anteriores, o bash já estava do lado do ksh onde quer que o ksh não fosse compatível com o shell Bourne. Enquanto você tinha que esperar até o bash2 para obter o mesmo nível de recurso que o ksh88, o bash já tinha várias extensões do ksh, como $(...)modos emacs / vi, expansões til / brace (aquelas inicialmente do csh), fc, typeset, alias , sintaxe da função estilo ksh ...
Stéphane Chazelas
8

Sim, você pode usar #!/bin/shem um script porque /bin/sh(espero) é fornecido em tais sistemas, geralmente através de um link de algum tipo que faz com que se bashcomporte (mais ou menos) como shfaria. Aqui está um sistema Centos7, por exemplo, vinculado sha bash:

-bash-4.2$ ls -l /bin/sh
lrwxrwxrwx 1 root root 4 Dec  4 16:48 /bin/sh -> bash
-bash-4.2$ 

Você também pode usar #!/bin/bashse estiver escrevendo um bashscript apenas para esse sistema e quiser usar os bashrecursos. No entanto, esses scripts sofrerão problemas de portabilidade, por exemplo, no OpenBSD, onde bashé instalado apenas se o administrador tiver o problema de instalá-lo (eu não) e, em seguida, ele estiver instalado /usr/local/bin/bash, não /bin/bash. Um #!/bin/shscript estritamente POSIX deve ser mais portátil.

agitar
fonte
Observe o seguinte: "Quando chamado como sh, o Bash entra no modo POSIX depois de ler os arquivos de inicialização". - gnu.org/software/bash/manual/bashref.html#Bash-POSIX-Mode
glenn jackman
2
Quando escrevo scripts para servidores RHEL no meu trabalho, uso com #!/bin/bashprecisão para tirar proveito dos recursos que não são do POSIX.
precisa saber é o seguinte
@MontyHarder IIRC no RHEL /bin/shé um link simbólico bash, está correto? Eu sei com certeza no CentOS que é.
Sergiy Kolodyazhnyy
1
@SergiyKolodyazhnyy Sim, no servidor RHEL que acabei de verificar, é um link simbólico para bash. O binário sabe qual nome foi usado para invocá-lo e, quando é chamado sh, age como o velho Bourne sh.
Monty Harder
6

Você perguntou

é correto colocar o comentário #! / bin / sh em scripts de shell escritos em distribuições do ubuntu?

A resposta depende do que você escreve no script de shell.

  • Se você usar estritamente scripts portáteis compatíveis com POSIX e não usar nenhum comando específico do bash, poderá usá-lo /bin/sh.

  • Se você sabe que você está sempre apenas usando o script em uma máquina com bash, e você quiser usar sintaxe específica do bash, então você deve usar/bin/bash

  • Se você está quer ter certeza de que o script irá funcionar em uma variedade de máquinas Unix, então você deve usar somente a sintaxe compatível com POSIX, e/bin/sh

  • Se você usa regularmente outro shell (por exemplo ksh , zsh ou tcsh ), e quer usar essa sintaxe em seu script, então você deve usar o interpretador apropriado (como /bin/ksh93, /bin/zshou /bin/tcsh)

Stobor
fonte
3

O "#!" O comentário nem sempre usa /bin/bashou /bin/sh. Ele apenas lista o que o intérprete deve ser, não apenas para scripts de shell. Por exemplo, meus scripts python geralmente começam com#!/usr/bin/env python .

Agora, a diferença entre #!/bin/she #!/bin/bashé que isso /bin/shnem sempre é um link simbólico para /bin/bash. Frequentemente, mas nem sempre. O Ubuntu é uma exceção notável aqui. Eu vi scripts funcionando bem no CentOS, mas falhando no Ubuntu porque o autor usou a sintaxe específica do bash #!/bin/sh.

aragaer
fonte
1

Desculpe por derramar água fria em todas as ótimas respostas que dizem que /bin/shestá presente em todos os sistemas Unix - está presente, exceto no sistema Unix mais usado de todos os tempos: Android.

O Android tem seu shell /system/bin/sh, e geralmente não há como fazer um /bin/shlink, mesmo em um sistema enraizado (devido à maneira como o sistema é bloqueado pelo uso de selinux e de recursos (7) conjuntos delimitadores).

Para aqueles que dirão que o Android não é compatível com POSIX: nem a maioria das distribuições Linux e BSD. E a existência de /bin/shcom esse caminho não é obrigatória pelo padrão :

Os aplicativos devem observar que o padrão PATHpara o shell não pode ser assumido como um /bin/shou /usr/bin/sh, e deve ser determinado pelo interrogatório do PATHretornado getconf PATH, garantindo que o nome do caminho retornado seja um nome de caminho absoluto e não um shell interno.

mosvy
fonte
Embora todos os sistemas que tentam ser compatíveis com POSIX possuam vários erros de conformidade (incluindo os certificados), o Android (e a maioria dos outros sistemas incorporados, como o roteador ou o SO da lâmpada), não pretende ser compatível com POSIX. O Android está fora de tópico aqui, exceto quando se trata de sua interface POSIX.
Stéphane Chazelas
@ Christopher, qual getconf? Por exemplo, no Solaris 11.4, seria esse /usr/bin? Aquele em /usr/xpg4/bin(para conformidade com o SUSv2), aquele em /usr/xpg6/bin(para conformidade com o SUSv3)? /usr/xpg7/bin(para SUSv4)?
Stéphane Chazelas
@ StéphaneChazelas Se quisermos julgar as intenções, acho que posso descobrir facilmente algumas citações de Linus Torvalds ou Theo de Raadt, no sentido de que eles não se importam muito com o POSIX ;-) E a maioria dos sistemas embarcados é baseada no linux + busybox, que dificilmente é menos compatível com POSIX do que o sistema típico de Unix. E a) o Android não é realmente um sistema "incorporado" eb) um sistema do Android pode ser compatível com POSIX sem ter um shell dentro /bin/sh
mosvy
1
@mosvy, o que você diz é principalmente verdade. Mas Torvalds só pode falar pelo kernel do Linux. Chet Ramey se preocupa com a conformidade do POSIX para o bash, o RedHat se preocupa com a conformidade do POSIX (eles patrocinam o grupo Austin e participam de suas reuniões de grupo, eles mantêm muito do software GNU). A idéia é que o POSIX seja o único padrão que a maioria dos sistemas semelhantes ao Unix observa. Os usuários se preocupam com a compatibilidade com POSIX, pois facilita o software portátil para diferentes sistemas. Não é o ideal, mas é melhor que nada. O Android tem sua própria API de programação, o POSIX não é realmente uma preocupação por lá.
Stéphane Chazelas