cabeçalhos de script de shell (#! / bin / sh vs #! / bin / csh)


93

Por que todos os arquivos de script começam com

#!/bin/sh

ou com

#!/bin/csh

Isso é necessário? Qual é o propósito disso? E qual é a diferença entre os dois?


1
Para um script csh, você deve usar #!/bin/csh -f; o -fdiz ao shell para não fornecer o .logine .cshrc, o que torna o script executado mais rápido e evita dependências na configuração do usuário. (Ou melhor ainda, não escreva scripts csh.) Não use -fpara scripts sh ou bash; não tem o mesmo significado.
Keith Thompson

Respostas:


100

Isso é conhecido como Shebang:

http://en.wikipedia.org/wiki/Shebang_(Unix)

#! intérprete [opcional-arg]

Um shebang só é relevante quando um script tem permissão de execução (por exemplo, chmod u + x script.sh).

Quando um shell executa o script, ele usa o interpretador especificado.

Exemplo:

#!/bin/bash
# file: foo.sh
echo 1

$ chmod u+x foo.sh
$ ./foo.sh
  1

@Kolob Canyon você não precisa, mas pode ajudar alguns editores com realce de sintaxe (embora geralmente haja outras maneiras de conseguir a mesma coisa): unix.stackexchange.com/a/88730/193985
Braham Snyder

42

A #!linha informa ao kernel (especificamente, a implementação da execvechamada do sistema) que este programa foi escrito em uma linguagem interpretada; o caminho absoluto que segue identifica o intérprete. Os programas compilados em código de máquina começam com uma sequência de bytes diferente - na maioria dos Unixes modernos, 7f 45 4c 46( ^?ELF) que os identifica como tal.

Você pode colocar um caminho absoluto para qualquer programa que desejar após o #!, desde que esse programa não seja um #!script. O kernel reescreve uma invocação de

./script arg1 arg2 arg3 ...

onde ./scriptcomeça com, digamos, #! /usr/bin/perlcomo se a linha de comando tivesse realmente sido

/usr/bin/perl ./script arg1 arg2 arg3

Ou, como você viu, você pode usar #! /bin/shpara escrever um script para ser interpretado por sh.

A #!linha só é processada se você invocar diretamente o script ( ./scriptna linha de comando); o arquivo também deve ser executável ( chmod +x script). Se você fizer isso, sh ./scripta #!linha não será necessária (e será ignorada se estiver presente), e o arquivo não precisa ser executável. O objetivo do recurso é permitir que você invoque diretamente programas em linguagem interpretada sem precisar saber em que idioma eles estão escritos. (Faça grep '^#!' /usr/bin/*- você descobrirá que muitos programas de estoque estão de fato usando esse recurso.)

Aqui estão algumas regras para usar este recurso:

  • A #!devem ser os dois primeiros bytes do arquivo. Em particular, o arquivo deve estar em uma codificação compatível com ASCII (por exemplo, UTF-8 funcionará, mas UTF-16 não) e não deve começar com uma "marca de ordem de byte", ou o kernel não o reconhecerá como um #!roteiro.
  • O caminho após #!deve ser um caminho absoluto (começa com /). Não pode conter espaço, tabulação ou caracteres de nova linha.
  • É um bom estilo, mas não obrigatório, colocar um espaço entre o #!e o /. Não coloque mais de um espaço lá.
  • Você não pode colocar variáveis ​​de shell na #!linha, elas não serão expandidas.
  • Você pode colocar um argumento de linha de comando após o caminho absoluto, separado dele por um único espaço. Como o caminho absoluto, este argumento não pode conter espaço, tabulação ou caracteres de nova linha. Às vezes, isso é necessário para fazer as coisas funcionarem ( #! /usr/bin/awk -f), às vezes é apenas útil ( #! /usr/bin/perl -Tw). Infelizmente, você não pode colocar dois ou mais argumentos após o caminho absoluto.
  • Algumas pessoas dirão para você usar em #! /usr/bin/env interpretervez de #! /absolute/path/to/interpreter. Isso quase sempre é um erro. Isso faz com que o comportamento do seu programa dependa da $PATHvariável do usuário que invoca o script. E nem todos os sistemas têm, envem primeiro lugar.
  • Programas que precisam setuidou setgidnão podem ser usados ​​com privilégios #!; eles devem ser compilados em código de máquina. (Se você não sabe o que setuidé, não se preocupe com isso.)

No cshque diz respeito , refere-se shaproximadamente a como o Substituto Avançado de Chá Nutrimat se refere ao chá. Ele tem (ou melhor, teve; as implementações modernas do shalcançaram) várias vantagens em relação shao uso interativo, mas usá-lo (ou seu descendente tcsh) para scripts é quase sempre um erro . Se você é novo no shell scripting em geral, recomendo fortemente que você ignore e se concentre em sh. Se você estiver usando um cshparente como shell de login, mude para bashou zsh, para que a linguagem de comando interativa seja a mesma que a linguagem de script que você está aprendendo.


Versões recentes do Linux permitem que o interpretador especificado seja um script. É prática comum omitir o espaço após o #!; nenhum comentário sobre se é um bom estilo. Veja esta pergunta e minha resposta para uma discussão sobre os prós e contras do #!/usr/bin/envhack.
Keith Thompson

@KeithThompson Tenho a impressão de que o Linux é a única variante comum do Unix que permite que o interpretador seja um script, então ainda não é algo em que se possa confiar. Desde que escrevi isso, eu mesmo encontrei uma situação em que #!/usr/bin/envera a coisa certa, mas continua sendo minha opinião que quase sempre é uma má ideia.
zwol

4

Isso define qual shell (interpretador de comando) você está usando para interpretar / executar seu script. Cada shell é ligeiramente diferente na maneira como interage com o usuário e executa scripts (programas).

Quando você digita um comando no prompt do Unix, está interagindo com o shell.

Por exemplo, #!/bin/cshrefere-se ao C-shell, /bin/tcsho t-shell, /bin/basho bash shell, etc.

Você pode dizer qual shell interativo está usando o

 echo $SHELL

comando, ou alternativamente

 env | grep -i shell

Você pode alterar seu shell de comando com o chshcomando.

Cada um tem um conjunto de comandos ligeiramente diferente e uma maneira de atribuir variáveis ​​e seu próprio conjunto de construções de programação. Por exemplo, a instrução if-else com bash parece diferente daquela no C-shell.

Esta página pode ser de interesse, pois "traduz" entre os comandos / sintaxe bash e tcsh.

Usar a diretiva no script de shell permite executar programas usando um shell diferente. Por exemplo, eu uso o tcshshell interativamente, mas geralmente executo scripts bash usando / bin / bash no arquivo de script.

A parte, de lado:

Este conceito se estende a outros scripts também. Por exemplo, se você programa em Python, você colocaria

 #!/usr/bin/python

no topo do seu programa Python


Então, é necessário? Como posso saber qual shell estou realmente usando?
One Two Three

Portanto, se estou escrevendo os scripts para alguém usar em sua máquina e não sei qual shell eles estão usando. (Essa pessoa, infelizmente, não tem ideia sobre essas coisas, portanto, tudo o que ela pode fazer é executar o script sem alterar nada). Posso fazer algo assim #! $SHELL? Isso colocaria a concha correta no Shebang?
One Two Three

1
@OneTwoThree A maioria dos sistemas possui shells padrão, se você escrever um script bash ou csh, não terá problemas. O shell que eles estão usando interativamente não importa, essa é a beleza da !#/bin/bashdiretiva , por exemplo . Diz ao sistema qual shell usar para executar seu script de shell.
Levon

O valor de $SHELLnão indica necessariamente qual shell você está executando no momento; normalmente mostra seu shell padrão . conjuntos tcsh $versione $tcsh; conjuntos bash $BASH_VERSION. Nem todas as conchas têm necessariamente mecanismos semelhantes.
Keith Thompson

1
@OneTwoThree: A #!linha deve corresponder à sintaxe do script, não ao shell interativo usado por quem está executando o script.
Keith Thompson
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.