Eu tenho um projeto composto por cerca de 20 .sh
arquivos pequenos. Eu os chamo de "pequenos" porque geralmente nenhum arquivo tem mais de 20 linhas de código. Adotei uma abordagem modular porque assim sou fiel à filosofia Unix e é mais fácil para mim manter o projeto.
No início de cada .sh
arquivo, coloco #!/bin/bash
.
Simplificando, entendo que as declarações de script têm dois propósitos:
- Eles ajudam o usuário a lembrar qual shell é necessário para executar o arquivo (digamos, depois de alguns anos sem usar o arquivo).
- Eles garantem que o script seja executado apenas com um determinado shell (Bash nesse caso) para evitar comportamento inesperado caso outro shell seja usado.
Quando um projeto começa a crescer de, digamos, 5 arquivos para 20 arquivos ou de 20 para 50 arquivos (não neste caso, mas apenas para demonstrar), temos 20 ou 50 linhas de declarações de script. Eu admito, embora possa ser engraçado para alguns, parece um pouco redundante para mim usar 20 ou 50 em vez de dizer apenas 1 por projeto (talvez no arquivo principal do projeto).
Existe uma maneira de evitar essa suposta redundância de 20 ou 50 ou um número muito maior de linhas de declarações de script usando alguma declaração de script "global", em algum arquivo principal?
Mesmo que seu projeto agora consista apenas em 50 scripts Bash, mais cedo ou mais tarde ele começará a acumular scripts escritos em outras linguagens, como Perl ou Python (pelos benefícios que essas linguagens de script têm que o Bash não tem).
Sem uma linha adequada
#!
em cada script, seria extremamente difícil usar os vários scripts sem também saber qual interpretador usar. Não importa se cada script é executado a partir de outros scripts , isso apenas transfere a dificuldade dos usuários finais para os desenvolvedores. Nenhum desses dois grupos de pessoas precisa saber em qual idioma um script foi escrito para poder usá-lo.Shell scripts executados sem uma
#!
linha e sem um interpretador explícito são executados de maneiras diferentes, dependendo de qual shell os invoca (consulte, por exemplo, a pergunta Qual interpretador de shell executa um script sem shebang? e especialmente a resposta de Stéphane ), que não é o que você deseja em um ambiente de produção (você deseja um comportamento consistente e possivelmente até portabilidade).Os scripts executados com um interpretador explícito serão executados por esse interpretador, independentemente do que a
#!
linha diz. Isso causará problemas mais adiante se você decidir reimplementar, digamos, um script Bash em Python ou qualquer outra linguagem.Você deve gastar essas teclas extras e sempre adicionar uma
#!
linha a cada script.Em alguns ambientes, existem textos jurídicos padronizados de vários parágrafos em cada script de cada projeto. Fique muito feliz por ser apenas uma
#!
linha que parece "redundante" em seu projeto.Você não entendeu o ponto de
#!
. Na verdade, é uma diretiva para o sistema operacional executar este programa no interpretador definido.Portanto, um script pode ser executado e
#!/usr/bin/perl
o programa resultante pode ser executado./myprogram
e o interpretador perl pode ser usado. Semelhante#!/usr/bin/python
faria com que um programa fosse executado em python.Portanto, a linha
#!/bin/bash
diz ao sistema operacional para executar este programa no bash.Aqui está um exemplo:
Portanto, apesar de meu shell ser ksh, o programa "x" é executado no bash por causa da
#!
linha, e podemos ver isso explicitamente na listagem do processo.Sobre
.sh
O que é ruim é
.sh
no final do nome do arquivo.Imagine que você reescreve um dos scripts em python.
Bem, agora você tem que mudar a primeira linha para
#!/usr/bin/python3
isso não é tão ruim, já que você teve que mudar todas as outras linhas de código no arquivo também. No entanto, você também precisa alterar o nome do arquivo deprog.sh
paraprog.py
. E então você tem que encontrar em todos os outros scripts e todos os seus scripts de usuário (aqueles que você nem sabia que existiam) e alterá-los para usar o novo script.sed -e 's/.sh/.py/g'
pode ajudar para aqueles que você conhece. Mas agora sua ferramenta de controle de revisão está mostrando uma alteração em muitos arquivos não relacionados.Como alternativa, faça da maneira Unix e nomeie o programa como
prog
nãoprog.sh
.Sobre
#!
Se você tiver o
#!
, e definir a permissão/modo para incluir execute. Então você não precisa conhecer o intérprete. O computador fará isso por você.Para sistemas não gnu, leia o manual para
chmod
(e aprenda octal), talvez leia mesmo assim.Provavelmente vale a pena apontar que isso está completamente errado. A linha hashbang de forma alguma impede que você tente alimentar o arquivo para um shell/intérprete incorreto:
(ou similarmente com
awk -f array.sh
etc.)Mas, em qualquer caso, outra abordagem para a modularidade seria definir funções de shell nos arquivos, uma função por arquivo, se preferir, e depois
source
os arquivos do programa principal. Dessa forma, você não precisaria de hashbangs: eles seriam tratados como quaisquer outros comentários e tudo seria executado usando o mesmo shell. A desvantagem seria que você precisariasource
dos arquivos com as funções (por exemplofor x in functions/*.src ; do source "$x" ; done
), e todos eles seriam executados usando o mesmo shell, portanto, você não poderia substituir diretamente um deles por uma implementação Perl.Existe - é chamado de portabilidade ou conformidade POSIX. Esforce-se para sempre escrever scripts de maneira portátil e neutra em shell, obtenha-os apenas de um script que use
#!/bin/sh
ou quando você usar/bin/sh
interativamente (ou pelo menos um shell compatível com POSIX, comoksh
).No entanto, os scripts portáteis não o salvam de:
/bin/sh
script comcsh
.Se posso expressar minha opinião, "evitar redundância" eliminando
#!
é um objetivo errado. O objetivo deve ser um desempenho consistente e, na verdade, um script de trabalho que funcione e considere casos extremos, siga certas regras gerais como não-parsing-ls ou sempre-cotando-variáveis-a menos que precise de divisão de palavras .Eles realmente não são para o usuário - eles são para o sistema operacional executar o intérprete adequado. "Proper" neste caso, significa que o sistema operacional encontra o que está em shebang; se o código abaixo dele for um shell errado - a culpa é do autor. Quanto à memória do usuário, não acho que o "usuário" de programas como o Microsoft Word ou o Google Chrome precise saber em que idioma os programas estão escritos; os autores podem precisar.
Então, novamente, os scripts escritos de forma portátil podem eliminar a necessidade de lembrar qual shell você usou originalmente, porque os scripts portáteis devem funcionar em qualquer shell compatível com POSIX.
Eles não. O que realmente impede o comportamento inesperado é escrever scripts portáteis.
A razão pela qual você precisa colocar
#!/bin/bash
no início de cada script é que você o está executando como um processo separado.Quando você executa um script como um novo processo, o sistema operacional vê que é um arquivo de texto (em oposição a um executável binário) e precisa saber qual interpretador executar. Se você não disser, o SO pode apenas adivinhar, usando sua configuração padrão (que um administrador pode alterar). Portanto, a
#!
linha (além de adicionar permissões executáveis, é claro) transforma um arquivo de texto simples em um executável que pode ser executado diretamente, com a confiança de que o sistema operacional sabe o que fazer com ele.Se você deseja remover a
#!
linha, suas opções são:Execute o script diretamente (como você está fazendo agora) e espere que o interpretador padrão corresponda ao script - você provavelmente está seguro na maioria dos sistemas Linux, mas não é portátil para outros sistemas (por exemplo, Solaris), e pode ser alterado para qualquer coisa (eu poderia até configurá-lo para rodar
vim
no arquivo!).Execute o script usando
bash myscript.sh
. Isso funciona bem, mas você precisa especificar o caminho para o script e é confuso.Crie o script usando
. myscript.sh
, que executa o script no processo do interpretador atual (ou seja, não como um subprocesso). Mas isso quase certamente exigirá modificações em seus scripts e os tornará menos modulares/reutilizáveis.Nos casos 2 e 3, o arquivo não precisa (e não deveria ter) permissões de execução, e dar a ele um sufixo
.sh
(ou ) é uma boa ideia..bash
Mas nenhuma dessas opções parece boa para o seu projeto, pois você disse que deseja manter seus scripts modulares (=> independentes e autocontidos), então você deve manter sua
#!/bin/bash
linha no topo dos scripts.Em sua pergunta, você também disse que está seguindo a filosofia do Unix. Se isso for verdade, você deve aprender para que
#!
serve realmente a linha e continuar usando-a em todos os scripts executáveis!