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

104

Quando é #!/bin/bashmais apropriado do que #!/bin/shem um script de shell?

Hendré
fonte
55
Quando você estiver usando bashfunções e sintaxe, em vez de shfunções e sintaxe.
Mokubai
3
Se isso ajuda alguém, notei que vimirá destacar bashisis se o seu script tiver o #!/bin/shshebang. Eu só mudo para bashse as coisas ficarem peludas o suficiente para começar a precisar dos recursos do bash.
SeldomNeedy
@SeldomNeedy Algumas das coisas destacadas por padrão funcionam bem em qualquer shell POSIX. $(...)é particularmente desagradável. Além disso, alguns deles são sutis [ <(...)e cmd >& filenão obter qualquer realce de erros, 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 recentemente houve alguma atividade sobre esse assunto no rastreador de problemas do vim .
SeldomNeedy 14/10

Respostas:

150

Em resumo:

  • Existem vários shells que implementam um superconjunto da especificação sh do POSIX . Em sistemas diferentes, /bin/shpode haver um link para ash, bash, dash, ksh, zsh, etc. (Porém, sempre será compatível com sh - nunca csh ou fish.)

  • Contanto que você atenha shapenas aos recursos, você pode (e provavelmente deve) usar #!/bin/she o script deve funcionar bem, independentemente do shell.

  • Se você começar a usar recursos específicos do bash (por exemplo, matrizes), solicite especificamente o bash - porque, mesmo que /bin/shjá chame o bash no seu sistema, talvez não no sistema de todos os outros , e seu script não será executado lá. (É claro que o mesmo se aplica a zsh e ksh.) Você pode usar a verificação de shell para identificar bashismos.

  • Mesmo que o script seja apenas para uso pessoal, você pode notar que alguns SOs mudam /bin/shdurante as atualizações - por exemplo, no Debian, costumava ser bash, mas depois foi substituído por um traço mínimo. Scripts que usavam basismos, mas que haviam #!/bin/shsubitamente quebrado.

Contudo:

  • Mesmo #!/bin/bashnão é muito correto. Em sistemas diferentes, o bash pode residir em /usr/binou /usr/pkg/binou /usr/local/bin.

  • Uma opção mais confiável é #!/usr/bin/env bash, que usa $ PATH. (Embora a envferramenta em si também não seja estritamente garantida, /usr/bin/envainda funciona em mais sistemas do que em outros /bin/bash).

grawity
fonte
10
Boa resposta. Você queria fazer CW?
Mokubai
3
Apenas uma observação se o bash for executado a partir de /bin/shentão ele tentará imitar os shrecursos (consulte a página de manual ), não tendo certeza de que os recursos específicos do bash estejam disponíveis neste modo. envtool é uma ferramenta posix que deve ser encontrada na maioria das distribuições, mas não tenho certeza, pois algumas podem não respeitar o posix.
Brice
8
Não, de fato, o POSIX afirma especificamente que não pode ser assumido /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 interrogando o PATH retornado pelo getconf PATH, garantindo que o nome do caminho retornado seja um nome de caminho absoluto e não um shell interno ". Veja também esta pergunta e, especificamente, esta resposta .
terdon 10/10
12
Hmm, bem, isso significa que o POSIX não define realmente uma maneira portátil de fazer os #!scripts funcionarem?
grawity
4
O POSIX sh não é Bourne: é mais um derivado do ksh inicial do que um descendente direto de Bourne. Distinguí-los é fácil: echo foo ^ catemite foo ^ catno POSIX sh e emite apenas fooem Bourne (como ^é um caractere de pipe).
Charles Duffy
18

Use o shebang correspondente ao shell que você realmente usou para desenvolver e depurar seu script. Ou seja, se o seu shell de login é bashe você executa seu script como executável no seu terminal, use #!/bin/bash. Não assuma apenas que, como você não usou matrizes (ou qualquer bashrecurso que você conheça), você pode escolher o shell que quiser. Existem muitas diferenças sutis entre shells ( echofunções, loops, etc.) que não podem ser descobertas sem testes adequados.

Considere o seguinte: se você sair #!/bin/bashe os usuários não o tiverem, eles verão uma mensagem de erro clara, algo como

Error: /bin/bash not found

A maioria dos usuários pode corrigir isso em um minuto instalando o pacote apropriado. Por outro lado, se você substituir o shebang #!/bin/she testá-lo em um sistema em que /bin/shexiste um link simbólico /bin/bash, seus usuários que não possuem bashterão problemas. 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 ser corrigido, e não haverá nenhuma pista sobre qual shell eles deveriam ter usado.

Não há muitas razões pelas quais você deseja usar um shell diferente no shebang. Uma razão é quando o shell que você usou não é generalizado. Outra é obter um desempenho shsignificativamente 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 altere o shebang.

Dmitry Grigoryev
fonte
@ Hastur Não entendi 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
1
Esqueça. Eu não entendi a parte "por que você gostaria de usar" ...
Hastur
6

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

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

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

Sério ?!

Sim seriamente.

Aqui está a coisa: Shell é uma linguagem de programação terrível . A única coisa que /bin/shvale a pena é o único e único interpretador de script que é garantido que toda instalação do Unix possui.

Aqui está outra coisa: /usr/bin/perlé mais provável que alguma iteração do interpretador principal do Perl 5 ( ) esteja 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 incluímos PHP e Tcl nessa categoria quando comparados ao shell) também estão disponíveis como o bash e outros shells estendidos.

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

Agora, scripts shell simples , do tipo que apenas executam alguns programas em uma sequência de um trabalho cron ou algo assim, não há nada de errado em deixá-los como scripts shell. Mas scripts shell simples não precisam de matrizes, funções ou [[até mesmo. E você só deve escrever scripts de shell complicados quando não tiver outra opção. Os scripts do Autoconf, por exemplo, ainda são apropriadamente scripts shell. Mas esses scripts precisam ser executados em todas as encarnações /bin/shrelevantes para o programa que está sendo configurado. e isso significa que eles não podem usar nenhuma extensão. Você provavelmente não precisa se preocupar com Unixes proprietários antigos atualmente, mas provavelmente deve se preocupar com os BSDs de código aberto atuais, alguns dos quais não são instaladosbashpor padrão, e ambientes incorporados que fornecem apenas um mínimo de shell e busybox.

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

zwol
fonte
4
Desculpe, mas isso é um pouco bobo. Sim, se você estiver escrevendo algo que será i) distribuído e ii) para ambientes diferentes, você deve seguir o básico sh. Isso, no entanto, está muito longe de afirmar que você nunca deve usar outras conchas. Existem milhares (provavelmente muito mais) de 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 "sysdaminy" para os quais a maioria dos scripts é escrita. Se eu souber que meu script só será usado por mim e em uma máquina Linux, o bash está bom.
terdon 15/10/16
1
@terdon O ponto é que, se você tem a opção de escrever um script bash, também tem a opção de escrever um script perl (ou o que seja), e essa é sempre a melhor escolha.
Zwol 15/10/16
@terdon A resposta certamente não é boba, seu comentário é simplesmente ingênuo. Os scripts de shell são terríveis para depuração em comparação com o Perl e outros, para os quais é possível usar facilmente 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 colegas ou para a rede etc. É muito provável que não haja razão para correr esse risco.
Thorsten Schöning
@ ThorstenSchöning eu disse um pouco bobo. Se fosse Unix e Linux ou mesmo Stack Overflow, eu poderia até concordar. Se estivermos falando sobre as melhores práticas gerais, ou programadores profissionais, é claro que é melhor seguir o POSIX básico sh. No entanto, este é o Superusuário , um site destinado a usuários finais e que diz às pessoas para nunca usarem o bash ou o zsh ao escrever scripts de shell é, na minha opinião, extremo.
terdon 16/10
@terdon É realmente mais importante, na minha opinião, desencorajar os usuários finais a escrever scripts shell complexos. Os profissionais têm um nível de habilidade mais alto em média (portanto, são mais propensos a lidar com as armadilhas dos scripts de shell complexos), devem saber com alguma precisão em quais ambientes eles precisam ser portáteis e estão sendo pagos para não desistir em frustração.
Zwol 16/10/16
4

Geralmente, se o tempo for mais importante que a funcionalidade, você usará o shell mais rápido. O sh é frequentemente aliasado ao dash e tende a ser usado para tarefas cron do root ou operações em lote, onde cada (nano) segundo conta.

mckenzm
fonte
2
Carregar um interpretador de shell extra a partir do sistema de arquivos pode negar essa vantagem, e qualquer coisa em que os nanossegundos (que estão na mesma ordem de magnitude que um ciclo real da máquina) contam é o domínio dos 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 poderá lidar com tantos assim mesmo.
Dmitry Grigoryev 11/10
1
Mesmo que o mckenzm tenha exagerado um pouco, não há como negar que ter mais desempenho é melhor! Não se desligue da parte "nano". (Nanosegundos nem sequer contar em C a menos que seja um loop interno em um sistema em tempo real ou como!)
jpaugh
1
@jpaugh A menos que você esteja trabalhando com um sistema (legado) que suponha que certas operações levem pelo menos um período específico. Acontece!
JAB
3

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

Spencer Williams
fonte
1
  • sh (na maioria dos casos), bash, se necessário (ou ksh, ou o que for)

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

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

Obviamente, quando você tem uma razão para um script NUNCA estar automaticamente pegando um novo PATH, continue a codificá-lo - e / usr / bin / algo deve ser o caminho mais provável a ser usado.

Michael Felt
fonte