Questão Quando devo usar #! / Bin / bash e quando #! / Bin / sh?


Quando é #!/bin/bash mais apropriado do que #!/bin/sh em um script de shell?


97


origem


Quando você está usando bash funções e sintaxe em vez de sh funções e sintaxe. - Mokubai♦
Vejo stackoverflow.com/questions/5725296/… - SPRBRN
Se isso ajuda alguém, eu notei que vim vai destacar bash-ismos se o seu script tem o #!/bin/sh shebang. Eu só mudo para bash se as coisas ficarem peludas o suficiente para começar a precisar de recursos bash. - SeldomNeedy
@SeldomNeedy Algumas das coisas que ele destaca por padrão funcionam bem em qualquer shell POSIX. $(...) é particularmente desagradável. Além disso, alguns deles são sutis [<(...) e cmd >& file não receba nenhum destaque de erro, por exemplo, eles simplesmente não têm destaque especial para o que eles significam, com ou sem g:is_bash] - Random832
@ Random832 Parece que houve alguma atividade sobre este tópico recentemente em rastreador de problemas do vim. - SeldomNeedy


Respostas:


Em resumo:

  • Existem várias conchas que implementam um superconjunto de a especificação sh POSIX. Em diferentes sistemas, /bin/sh pode ser um link para ash, bash, dash, ksh, zsh, & c. (Ele sempre será compatível com sh - nunca csh ou peixe).

  • Contanto que você fique com sh somente recursos, você pode (e provavelmente deve) usar #!/bin/sh e o script deve funcionar bem, não importa qual shell seja.

  • Se você começar a usar recursos específicos do bash (por exemplo, arrays), você deve solicitar especificamente o bash - porque, mesmo se /bin/sh já invoca bash on seu sistema, pode não estar todos os outros sistema, e seu script não será executado lá. (O mesmo se aplica a zsh e ksh.) Você pode usar concha para identificar os bashisms.

  • Mesmo que o script seja apenas para uso pessoal, você poderá notar que alguns sistemas operacionais mudam /bin/sh durante os upgrades - por ex. no Debian costumava ser bash, mas depois foi substituído por um mínimo de traço. Scripts que usavam bashisms mas tinham #!/bin/sh de repente quebrou.

Contudo:

  • Até #!/bin/bash não está muito correto. Em sistemas diferentes, o bash pode viver em /usr/bin ou /usr/pkg/bin ou /usr/local/bin.

  • Uma opção mais confiável é #!/usr/bin/env bash, que usa $ PATH. (Apesar de env ferramenta em si não é estritamente garantida, /usr/bin/env ainda funciona em mais sistemas do que /bin/bash faz.)


142



Boa resposta. Você quis fazer CW? - Mokubai♦
Apenas um comentário se o bash for executado /bin/sh então ele tentará imitar sh recursos (consulte página man), não há certeza de que recursos específicos do bash estão disponíveis neste modo. env ferramenta é uma ferramenta posix ele deve ser encontrado na maioria das distribuições, mas eu não tenho certeza, pois alguns podem não respeitar o posix. - Brice
Não, na verdade POSIX especificamente afirma não se pode presumir que esteja em /bin: "Os aplicativos devem observar que o PATH padrão para o shell não pode ser assumido como / bin / sh ou / usr / bin / sh, e deve ser determinado pela interrogação do PATH retornado pelo getconf PATH, assegurando que o caminho retornado seja um absoluto nome do caminho e não um shell embutido". Veja também essa questão e, especificamente esta resposta. - terdon
Hmm, bem, então isso significa que o POSIX na verdade não define uma maneira portátil de ter #! scripts funcionam? - grawity
POSIX sh é não Bourne: é mais um derivado do ksh do que um descendente direto de Bourne. Distinguê-los é fácil: echo foo ^ cat emite foo ^ cat no POSIX sh e emite apenas foo em Bourne (as ^ é um caractere de pipe lá). - Charles Duffy


Use o shebang correspondente ao shell que você realmente usou para desenvolver e depurar seu script. Ou seja se o seu login shell é bash, e você executa seu script como executável em seu terminal, use #!/bin/bash. Não apenas assuma que desde que você não usou matrizes (ou qualquer outra coisa bash característica de que você está ciente), você está seguro para escolher qualquer shell que você gosta. Existem muitas diferenças sutis entre as conchas (echo, funções, loops, you name it) que não podem ser descobertos sem testes apropriados.

Considere isto: se você sair #!/bin/bash e seus usuários não têm, eles verão uma mensagem de erro clara, algo como

Error: /bin/bash not found

A maioria dos usuários pode consertar isso em menos de um minuto instalando o pacote apropriado. Por outro lado, se você substituir o shebang por #!/bin/sh e testá-lo em um sistema onde /bin/sh é um link simbólico para /bin/bash, seus usuários que não têm bash estará em apuros. Eles provavelmente verão uma mensagem de erro enigmática como:

Error in script.sh line 123: error parsing token xyz

Isso pode levar horas para consertar, e não haverá nenhuma pista sobre qual shell eles deveriam ter usado.

Não há muitas razões pelas quais você gostaria de usar um shell diferente no shebang. Uma razão é quando o shell que você usou não é muito difundido. Outra é ganhar desempenho com sh que é significativamente mais rápido em alguns sistemas, E seu script será um gargalo de desempenho. Nesse caso, teste seu script completamente com o shell de destino e, em seguida, altere o shebang.


17



@Hastur Eu não entendo o seu comentário. O shebang certamente definirá qual shell será usado para executar o script, você acha que minha resposta implica o contrário? - Dmitry Grigoryev
Esqueça. Eu entendi mal a parte "por que você gostaria de usar"... - Hastur


Você só deve usar #! /bin/sh.

Você não deve usar extensões bash (ou zsh, ou fish, ou ...) em um shell script, nunca.

Você só deve escrever scripts de shell que funcionem com qualquer implementação da linguagem shell (incluindo todos os programas "utility" que acompanham o próprio shell). Nos dias de hoje você pode provavelmente levar POSIX.1-2001 (não -2008) como autoritativo para o que o shell e os utilitários são capazes, mas esteja ciente de que você pode um dia ser chamado para portar seu script para um sistema legado (por exemplo, Solaris ou AIX) cujo shell e utilitários foram congelados por volta de 1992.

O que, sério?

Sim seriamente.

Aqui está a coisa: Shell é um terrivel linguagem de programação. A única coisa que tem para isso é que /bin/sh é o único interpretador de scripts que cada A instalação do Unix é garantida.

Aqui está a outra coisa: alguma iteração do intérprete central do Perl 5 (/usr/bin/perl) é Mais provavelmente estará disponível em uma instalação Unix selecionada aleatoriamente do que (/(usr|opt)(/(local|sfw|pkg)?)?/bin/bash é. Outras boas linguagens de script (Python, Ruby, node.js, etc. - inclusive incluirei o PHP e o Tcl nessa categoria ao comparar com o shell) também estão aproximadamente disponíveis como o bash e outros shells estendidos.

Portanto, se você tem a opção de escrever um script bash, você tem a opção de usar uma linguagem de programação que não é terrível.

Agora, simples scripts de shell, do tipo que apenas executam alguns programas em uma sequência a partir de uma tarefa cron ou algo assim, não há nada de errado em deixá-los como scripts de shell. Mas scripts de shell simples não precisam de arrays ou funções ou [[ até. E você só deve escrever complicado scripts de shell quando você não tem outra escolha. Scripts autoconf, por exemplo, são apropriadamente scripts de shell. Mas esses scripts precisam ser executados cada encarnação de /bin/sh isso é relevante para o programa que está sendo configurado. e isso significa que eles não podem usar extensões. Você provavelmente não precisa se preocupar com os antigos Unixes proprietários, mas provavelmente devemos se preocupam com os BSDs de código aberto atuais, alguns dos quais não instalam bash por padrão, e ambientes incorporados que lhe dão apenas um mínimo de shell e busybox.

Em conclusão, o momento em que você se encontra querendo um recurso que não está disponível na linguagem de shell portátil, isso é um sinal de que o script se tornou muito complicado para manter um script de shell. Reescreva-o em uma linguagem melhor.


5



Desculpe, mas isso é um pouco bobo. Sim, se você está escrevendo algo que será i) distribuído e ii) para ambientes diferentes, você deve se ater ao básico sh. Isso, no entanto, está muito longe de afirmar que você deveria Nunca use outras conchas. Existem milhares (provavelmente muitos mais) scripts escritos todos os dias e a grande maioria deles só será executada em uma única máquina. Seu conselho faz sentido no código de produção, mas não nos trabalhos diários de "sysdaminy" para os quais a maioria dos scripts é escrita. Se eu sei que o meu script só será usado por mim e em uma máquina Linux, bash está bem. - terdon
@terdon O ponto é que, se você tem a opção de escrever um script bash, então você também tem a opção de escrever um script perl (ou qualquer outro), e isso é sempre a melhor escolha. - zwol
@terdon A resposta certamente não é boba, seu comentário é simplesmente ingênuo. Scripts shell são terríveis para depurar em comparação com Perl e tal, para o qual se pode facilmente usar IDEs completos com depuração gráfica e tudo. Além disso, a maioria dos scripts escritos todos os dias para algo pequeno a fazer tendem a ser alterados e alterados novamente, crescer, são copiados como exemplos para os colegas ou para a rede etc. Não há razão para correr esse risco. - Thorsten Schöning
@ ThorstenSchöning eu disse um pouco boba. Se isso fosse Unix e Linux ou até mesmo Estouro de pilha Eu posso até concordar. Se estamos falando de boas práticas gerais ou programadores profissionais, é claro que é melhor ficar com o POSIX básico. No entanto, isso é Superusuário, um site destinado a usuários finais e dizendo às pessoas para nunca usar bash ou zsh ao escrever scripts shell é, na minha opinião, extremo. - terdon
@terdon Na verdade é Mais importante, na minha opinião, desencorajar os usuários finais de escrever scripts de shell complexos. Os profissionais têm, em média, um nível de habilidade mais alto (assim, são mais propensos a lidar com as armadilhas dos complexos scripts de shell), devem saber com precisão quais ambientes precisam ser portáteis, e estão sendo pagos para não desistirem. em frustração. - zwol


Geralmente, se o tempo for mais importante que a funcionalidade, você usará o shell mais rápido. sh é frequentemente usado para dash e tende a ser usado para tarefas cron ou tarefas em que cada (nano) segundo conta.


3



Carregar um interpretador de shell extra do sistema de arquivos pode negar tal vantagem, e qualquer coisa em que nanossegundos (que estão na mesma ordem de grandeza que um ciclo de máquina real) é o domínio de programadores de linguagem C e assembly. - rackandboneman
Nanossegundos só fazem diferença nos trabalhos do cron se você tiver bilhões deles, e o cron não será capaz de lidar com tantos de qualquer maneira. - Dmitry Grigoryev
Mesmo que o mckenzm exagere um pouco, não há como negar que ter mais performance é melhor! Não fique preso na parte "nano". (Nanossegundos nem contam em C, a menos que seja um laço interno em um sistema em tempo real ou algo assim!) - jpaugh
@ jpaugh A menos que você esteja trabalhando com um sistema (legado) que pressuponha que determinadas operações levem pelo menos um período específico de tempo. Acontece! - JAB


Para ser ainda mais breve, use sh se a portabilidade na maioria dos sistemas é mais importante e bash se você quiser usar alguns de seus recursos específicos, como matrizes, se a versão do bash o suportar.


2





  • sh (para a maioria dos casos), bash se especificamente necessário (ou ksh, ou qualquer outro)

O caminho mais seguro quando codificado, seria / usr / bin /shellOfChoice mas uma nova convenção que estou tentando usar sempre agora - como 'locais padrão' por meio de uma mudança que o PATH pode mudar é:

#! / usr / bin / env sh ou
 #! / usr / bin / env bash
ou por exemplo, scripts perl
 #! / usr / bin / env perl -w

É claro, quando você tem um motivo para um script NUNCA estar pegando automaticamente um novo PATH, continue codificando-o - e, em seguida, / usr / bin / alguma coisa deve ser o caminho mais provável a ser usado.


1