AskOverflow.Dev

AskOverflow.Dev Logo AskOverflow.Dev Logo

AskOverflow.Dev Navigation

  • Início
  • system&network
  • Ubuntu
  • Unix
  • DBA
  • Computer
  • Coding
  • LangChain

Mobile menu

Close
  • Início
  • system&network
    • Recentes
    • Highest score
    • tags
  • Ubuntu
    • Recentes
    • Highest score
    • tags
  • Unix
    • Recentes
    • tags
  • DBA
    • Recentes
    • tags
  • Computer
    • Recentes
    • tags
  • Coding
    • Recentes
    • tags
Início / unix / Perguntas / 421633
Accepted
user9303970
user9303970
Asked: 2018-02-04 04:49:33 +0800 CST2018-02-04 04:49:33 +0800 CST 2018-02-04 04:49:33 +0800 CST

Muitas linhas shebang (declaração de script) --- alguma maneira de reduzir sua quantidade?

  • 772

Eu tenho um projeto composto por cerca de 20 .sharquivos 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 .sharquivo, coloco #!/bin/bash.

Simplificando, entendo que as declarações de script têm dois propósitos:

  1. Eles ajudam o usuário a lembrar qual shell é necessário para executar o arquivo (digamos, depois de alguns anos sem usar o arquivo).
  2. 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?

shell-script shebang
  • 6 6 respostas
  • 2037 Views

6 respostas

  • Voted
  1. Best Answer
    Kusalananda
    2018-02-04T05:26:38+08:002018-02-04T05:26:38+08:00

    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.

    • 19
  2. Stephen Harris
    2018-02-04T04:59:15+08:002018-02-04T04:59:15+08:00

    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/perlo programa resultante pode ser executado ./myprograme o interpretador perl pode ser usado. Semelhante #!/usr/bin/pythonfaria com que um programa fosse executado em python.

    Portanto, a linha #!/bin/bashdiz ao sistema operacional para executar este programa no bash.

    Aqui está um exemplo:

    $ echo $0
    /bin/ksh
    
    $ cat x
    #!/bin/bash
    
    ps -aux | grep $$
    
    $ ./x
    sweh      2148  0.0  0.0   9516  1112 pts/5    S+   07:58   0:00 /bin/bash ./x
    sweh      2150  0.0  0.0   9048   668 pts/5    S+   07:58   0:00 grep 2148
    

    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.

    • 11
  3. ctrl-alt-delor
    2018-02-04T08:41:49+08:002018-02-04T08:41:49+08:00

    Sobre.sh

    O que é ruim é .shno 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/python3isso 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 de prog.shpara prog.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 prognão prog.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ê.

    chmod +x prog #on gnu adds execute permission to prog.
    ./prog #runs the program.
    

    Para sistemas não gnu, leia o manual para chmod(e aprenda octal), talvez leia mesmo assim.

    • 9
  4. ilkkachu
    2018-02-04T07:33:53+08:002018-02-04T07:33:53+08:00

    [As linhas hashbang] garantem que o script seja executado apenas com um determinado shell (Bash nesse caso) para evitar comportamento inesperado caso outro shell seja usado.

    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:

    $ cat array.sh
    #!/bin/bash
    a=(a b c)
    echo ${a[1]} $BASH_VERSION
    $ dash array.sh
    array.sh: 2: array.sh: Syntax error: "(" unexpected
    

    (ou similarmente com awk -f array.shetc.)


    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 sourceos 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ê precisaria sourcedos arquivos com as funções (por exemplo for 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.

    • 8
  5. Sergiy Kolodyazhnyy
    2018-02-04T09:48:09+08:002018-02-04T09:48:09+08:00

    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?

    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/shou quando você usar /bin/shinterativamente (ou pelo menos um shell compatível com POSIX, como ksh).

    No entanto, os scripts portáteis não o salvam de:

    • necessidade de usar recursos de um dos shells ( a resposta de ilkkachu é um exemplo)
    • necessidade de usar linguagens de script mais avançadas que shells (Python e Perl)
    • Erro PEBKAC: seu script cai nas mãos do usuário J.Doe, que executa seu script não como você pretendia, por exemplo, eles executam o /bin/shscript com csh.

    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 ajudam o usuário a lembrar qual shell é necessário para executar o arquivo (digamos, depois de alguns anos sem usar o arquivo).

    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 garantem que o script seja executado apenas com um determinado shell (Bash nesse caso) para evitar comportamento inesperado caso outro shell seja usado.

    Eles não. O que realmente impede o comportamento inesperado é escrever scripts portáteis.

    • 4
  6. Laurence Renshaw
    2018-02-09T17:48:58+08:002018-02-09T17:48:58+08:00

    A razão pela qual você precisa colocar #!/bin/bashno 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:

    1. 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 vimno arquivo!).

    2. Execute o script usando bash myscript.sh. Isso funciona bem, mas você precisa especificar o caminho para o script e é confuso.

    3. 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/bashlinha 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!

    • 1

relate perguntas

  • Subtraindo a mesma coluna entre duas linhas no awk

  • Um script que imprime as linhas de um arquivo com seu comprimento [fechado]

  • exportar variáveis ​​​​env programaticamente, via stdout do comando [duplicado]

  • Dividir por delimitador e concatenar problema de string

  • MySQL Select com função IN () com array bash

Sidebar

Stats

  • Perguntas 205573
  • respostas 270741
  • best respostas 135370
  • utilizador 68524
  • Highest score
  • respostas
  • Marko Smith

    Como exportar uma chave privada GPG e uma chave pública para um arquivo

    • 4 respostas
  • Marko Smith

    ssh Não é possível negociar: "nenhuma cifra correspondente encontrada", está rejeitando o cbc

    • 4 respostas
  • Marko Smith

    Como podemos executar um comando armazenado em uma variável?

    • 5 respostas
  • Marko Smith

    Como configurar o systemd-resolved e o systemd-networkd para usar o servidor DNS local para resolver domínios locais e o servidor DNS remoto para domínios remotos?

    • 3 respostas
  • Marko Smith

    Como descarregar o módulo do kernel 'nvidia-drm'?

    • 13 respostas
  • Marko Smith

    apt-get update error no Kali Linux após a atualização do dist [duplicado]

    • 2 respostas
  • Marko Smith

    Como ver as últimas linhas x do log de serviço systemctl

    • 5 respostas
  • Marko Smith

    Nano - pule para o final do arquivo

    • 8 respostas
  • Marko Smith

    erro grub: você precisa carregar o kernel primeiro

    • 4 respostas
  • Marko Smith

    Como baixar o pacote não instalá-lo com o comando apt-get?

    • 7 respostas
  • Martin Hope
    rocky Como exportar uma chave privada GPG e uma chave pública para um arquivo 2018-11-16 05:36:15 +0800 CST
  • Martin Hope
    Wong Jia Hau ssh-add retorna com: "Erro ao conectar ao agente: nenhum arquivo ou diretório" 2018-08-24 23:28:13 +0800 CST
  • Martin Hope
    Evan Carroll status systemctl mostra: "Estado: degradado" 2018-06-03 18:48:17 +0800 CST
  • Martin Hope
    Tim Como podemos executar um comando armazenado em uma variável? 2018-05-21 04:46:29 +0800 CST
  • Martin Hope
    Ankur S Por que /dev/null é um arquivo? Por que sua função não é implementada como um programa simples? 2018-04-17 07:28:04 +0800 CST
  • Martin Hope
    user3191334 Como ver as últimas linhas x do log de serviço systemctl 2018-02-07 00:14:16 +0800 CST
  • Martin Hope
    Marko Pacak Nano - pule para o final do arquivo 2018-02-01 01:53:03 +0800 CST
  • Martin Hope
    Kidburla Por que verdadeiro e falso são tão grandes? 2018-01-26 12:14:47 +0800 CST
  • Martin Hope
    Christos Baziotis Substitua a string em um arquivo de texto enorme (70 GB), uma linha 2017-12-30 06:58:33 +0800 CST
  • Martin Hope
    Bagas Sanjaya Por que o Linux usa LF como caractere de nova linha? 2017-12-20 05:48:21 +0800 CST

Hot tag

linux bash debian shell-script text-processing ubuntu centos shell awk ssh

Explore

  • Início
  • Perguntas
    • Recentes
    • Highest score
  • tag
  • help

Footer

AskOverflow.Dev

About Us

  • About Us
  • Contact Us

Legal Stuff

  • Privacy Policy

Language

  • Pt
  • Server
  • Unix

© 2023 AskOverflow.DEV All Rights Reserve