È #! / bin / sh letto dall'interprete?

61

In bash o sh , suppongo che tutto ciò che inizia con # sia un commento .

Ma in bash script scriviamo:

#!/bin/bash

E negli script Python c'è:

#!/bin/python

Significa che # di per sé è un commento mentre #! non lo è?

    
posta Gaurav Sharma 09.01.2013 - 07:04

4 risposte

93

La riga #! viene utilizzata prima lo script viene eseguito, quindi ignorato quando viene eseguito lo script.

Stai chiedendo quale sia la differenza tra una linea di shebang e un commento ordinario.

Una riga che inizia con #! è tanto un commento quanto qualsiasi altra riga che inizia con # . Questo è vero se #! è la prima riga del file o da qualsiasi altra parte. #!/bin/sh ha un effetto , ma non viene letto dallo stesso interprete .

# non è un commento in tutti i linguaggi di programmazione ma, come sai, è un commento in shell di tipo Bourne che includono sh e bash (così come la maggior parte delle shell non-Bourne-style, come% codice%). È anche un commento in Python . Ed è un commento in una varietà di file di configurazione che non sono affatto degli script (come csh ).

Supponiamo che uno script di shell inizi con /etc/fstab . Questo è un commento e l'interprete (la shell) ignora tutto sulla riga dopo il carattere #!/bin/sh .

Lo scopo di una riga # non è quello di fornire informazioni all'interprete. Lo scopo della riga #! è di dire al sistema operativo (o qualunque processo avvia l'interprete) cosa usare come interprete .

  • Se invochi lo script come un file eseguibile, ad esempio, eseguendo #! , il sistema consulta la prima riga per vedere se inizia con ./script.sh , seguito da zero o più spazi, seguito da un comando. Se lo fa, esegue quel comando con il nome dello script come argomento. In questo esempio, esegue #! (o, tecnicamente, /bin/sh script.sh ).

  • Se invochi lo script chiamando esplicitamente l'interprete, la riga /bin/sh ./script.sh non viene mai consultata. Pertanto, se esegui #! , la prima riga non ha alcun effetto. Se la prima riga di sh script.sh è script2.sh , l'esecuzione di #!/usr/games/nibbles non tenterà di aprire lo script in sh script2.sh (ma nibbles sarà).

Noterai che in nessuno dei due casi l'estensione dello script ( ./script2.sh ), se ne ha una, influisce sul modo in cui viene eseguita. In un sistema simile a Unix, questo non influisce normalmente su come viene eseguito lo script. In alcuni altri sistemi, come Windows, la riga .sh shebang potrebbe essere ignorata interamente dal sistema e l'estensione potrebbe determinare che cosa esegue gli script. (Questo non significa che devi dare le estensioni degli script, ma è una delle ragioni per cui, se lo fai, dovrebbero essere corrette.)

#! è stato scelto per servire esattamente questo scopo perché #! inizia un commento. La riga # è per il sistema, non per l'interprete e deve essere ignorata dall'interprete.

Linea Shebang per script Bash

Tu (in origine) hai detto che usi #! per #!/bin/sh script. Lo devi fare solo se lo script non richiede alcuna delle estensioni di bash - bash deve essere in grado di eseguire lo script. sh non è sempre un collegamento simbolico a sh . Spesso, incluso su tutti i recenti sistemi Debian e Ubuntu, bash è un link simbolico a sh .

Shebang Line per script Python

Hai anche detto (nella prima versione della tua domanda, prima della modifica) che avvii i tuoi script Python con dash . Se intendi questo letteralmente, dovresti assolutamente smettere di farlo. Se #!/bin/sh read by the interpretor inizia con quella riga, l'esecuzione di hello.py viene eseguita:

/bin/sh read by the interpretor hello.py

./hello.py proverà ad eseguire uno script chiamato /bin/sh (con read come argomenti), by the interpretor hello.py non si troverà (si spera) e il tuo script Python non verrà mai visto da un interprete Python.

Se stai commettendo questo errore ma non avendo il problema che sto descrivendo, stai probabilmente invocando i tuoi script Python specificando esplicitamente l'interprete (ad esempio read ), causando l'ignoranza della prima riga. Quando distribuisci i tuoi script ad altri, o li usi molto tempo dopo, potrebbe non essere chiaro che questo è necessario per farli funzionare. È meglio ripararli ora. O almeno rimuovi completamente la prima riga, in modo che quando non riescono a girare con python hello.py il messaggio di errore abbia senso.

Per gli script Python, se sai dove si trova l'interprete Python (o lo sarà), puoi scrivere la riga ./ nello stesso modo:

#!/usr/bin/python

Oppure, se si tratta di uno script Python 3, devi specificare #! , poiché python3 è quasi sempre Python 2 :

#!/usr/bin/python3

Tuttavia, il problema è che mentre si suppone che python esista sempre, e /bin/sh esiste quasi sempre nei sistemi in cui /bin/bash viene fornito con il sistema operativo, Python potrebbe esistere in una varietà di luoghi.

Pertanto, molti programmatori Python lo usano invece:

#!/usr/bin/env python

(Oppure bash per Python 3.)

Questo fa sì che lo script si basi su #!/usr/bin/env python3 nella "posizione giusta" invece di affidarsi a env nel posto giusto. Questa è una buona cosa, perché:

  • python è quasi sempre situato in env .
  • Sulla maggior parte dei sistemi, qualunque /usr/bin dovrebbe eseguire il tuo script è quello che appare per primo in python . Iniziare PATH con hello.py creare #!/usr/bin/env python eseguire ./hello.py , che è (virtualmente) equivalente all'esecuzione di /usr/bin/env python hello.py .

Il motivo per cui non puoi utilizzare python hello.py è:

  • Vuoi che l'interprete specificato sia dato da un percorso assoluto (cioè, iniziando con #!python ).
  • Il processo chiamante eseguirà / nella directory corrente. Il comportamento di cercare il percorso quando il comando non contiene una barra è un comportamento specifico della shell.

Occasionalmente un Python o un altro script che non è uno script di shell avrà una riga shebang che inizia con python dove #!/bin/sh ... è un altro codice. Questo a volte è corretto, perché ci sono alcuni modi per invocare la shell compatibile con Bourne ( ... ) con argomenti per farlo invocare un interprete Python. (Uno degli argomenti conterrà probabilmente sh .) Tuttavia, per la maggior parte degli scopi, python è più semplice, più elegante e più probabile che funzioni nel modo desiderato.

Linee Shebang in altre lingue

Molti linguaggi di programmazione e scripting e alcuni altri formati di file utilizzano #!/usr/bin/env python come commento. Per ognuno di essi, un file nella lingua può essere eseguito da un programma che lo prende come argomento specificando il programma sulla prima riga dopo # .

In alcuni linguaggi di programmazione, #! non è normalmente un commento, ma come caso speciale la prima riga viene ignorata se inizia con # . Questo facilita l'uso della sintassi #! anche se #! non rende altrimenti un commento di una riga.

Linee Shebang per file che non vengono eseguiti come script

Anche se è meno intuitivo, qualsiasi file il cui formato di file può contenere una prima riga che inizia con # seguito dal percorso completo di un eseguibile può avere una riga shebang. Se lo fai, e il file è contrassegnato come eseguibile, puoi eseguirlo come un programma ... facendolo aprire come un documento.

Alcune applicazioni usano questo comportamento intenzionalmente. Ad esempio, in VMware, i file #! definiscono le macchine virtuali. È possibile "eseguire" una macchina virtuale come se fosse uno script perché questi file sono contrassegnati come eseguibili e hanno una riga shebang che ne causa l'apertura in un'utilità VMware.

Linee di shebang per file che non vengono eseguiti come script ma agiscono come script in ogni caso

.vmx rimuove i file. Non è un linguaggio di scripting. Tuttavia, un file che avvia rm ed è contrassegnato come eseguibile può essere eseguito e, quando lo esegui, viene richiamato #!/bin/rm su di esso, cancellandolo.

Questo è spesso concettualizzato come "il file si cancella". Ma il file non funziona affatto. Questo è più simile alla situazione descritta sopra per rm file.

Tuttavia, poiché la riga .vmx facilita l'esecuzione di un comando semplicistico (inclusi gli argomenti della riga di comando), è possibile eseguire alcuni script in questo modo. Come semplice esempio di "script" più sofisticato di #! , considera:

#!/usr/bin/env tee -a

Ciò richiede l'input dell'utente in modo interattivo, lo riporta all'utente riga per riga e lo aggiunge alla fine del file "script".

Utile? Non molto. Concettualmente interessante? Totalmente! Sì. (Un po '.)

Concetti di programmazione / scripting concettualmente simili (solo per divertimento)

risposta data Eliah Kagan 09.01.2013 - 08:30
7

Uno shebang è la sequenza di caratteri costituita dal segno numerico dei caratteri e dal punto esclamativo (ad esempio "#!") quando si verifica come i primi due caratteri sulla riga iniziale di uno script.

In sistemi operativi * nix, quando viene eseguito uno script che inizia con uno shebang, il programma di caricamento del programma analizza il resto della riga iniziale dello script come una direttiva interprete; il programma interprete specificato viene invece eseguito, passando ad esso come argomento il percorso inizialmente utilizzato quando si tenta di eseguire lo script. Ad esempio, se uno script è denominato con il percorso "path / to / your-script" e inizia con la seguente riga:

#!/bin/sh

quindi il programma di caricamento viene istruito per eseguire il programma "/ bin / sh", ad es. la shell Bourne o una shell compatibile, passando "path / to / your-script" come primo argomento.

Di conseguenza, uno script è denominato con il percorso "path / to / python-script" e inizia con la seguente riga:

#!/bin/python

quindi il programma caricato viene istruito per eseguire il programma "/ bin / python", ad es. Interprete Python, passando "path / to / python-script" come primo argomento.

In breve "#" commenterà una riga mentre la sequenza di caratteri "#!" che si verificano quando i primi due caratteri sulla riga iniziale di uno script hanno un significato definito come sopra.

Per i dettagli vedi Perché alcuni script iniziano con #! ...?

Fonte: alcune sezioni di questa risposta sono derivate (con lievi modifiche) da Shebang (Unix) su Wikipedia in inglese (di collaboratori di Wikipedia ). Questo articolo è concesso in licenza con CC-BY-SA 3.0 , uguale al contenuto utente qui in AU, quindi questa derivazione è consentita con attribuzione.

    
risposta data Goran Miskovic 09.01.2013 - 07:57
4

#! è chiamato shebang quando si verifica come i primi due caratteri sulla riga iniziale di uno script. Viene utilizzato negli script per indicare un interprete per l'esecuzione. Il shebang è per il sistema operativo (kernel), non per la shell; quindi non sarà interpretato come un commento.

Cortesia: link

  

In generale, se un file è eseguibile, ma in realtà non è un eseguibile   (binario) programma, e tale linea è presente, il programma specificato   dopo #! è iniziato con lo scriptname e tutti i suoi argomenti. Queste   due caratteri # e! devono essere i primi due byte nel file!

Informazioni dettagliate: link

    
risposta data saji89 09.01.2013 - 07:34
0

No, è usato solo dalla chiamata di sistema exec del kernel Linux e viene trattato come un commento dall'interprete

Quando fai bash:

./something

su Linux, chiama la chiamata di sistema exec con il percorso ./something .

Questa linea del kernel viene chiamata sul file passato a exec : link

  

if ((bprm- & gt; buf [0]! = '#') || (bprm- & gt; buf [1]! = '!'))

Questo legge i primissimi byte del file e li confronta con #! .

Se ciò è vero, il resto della riga viene analizzato dal kernel Linux, il che rende un'altra chiamata exec con path /usr/bin/env python e il file corrente come primo argomento:

/usr/bin/env python /path/to/script.py

e funziona per qualsiasi linguaggio di scripting che utilizzi # come carattere di commento.

E sì, puoi creare un ciclo infinito con:

printf '#!/a\n' | sudo tee /a
sudo chmod +x /a
/a

Bash riconosce l'errore:

-bash: /a: /a: bad interpreter: Too many levels of symbolic links

#! è semplicemente leggibile dall'uomo, ma non è obbligatorio.

Se il file è stato avviato con diversi byte, la chiamata di sistema exec utilizzerà un gestore diverso. L'altro gestore incorporato più importante è per i file eseguibili ELF: link che controlla byte 7f 45 4c 46 (che è anche leggibile da% per .ELF ). Questo legge il file ELF, lo mette in memoria correttamente e avvia un nuovo processo con esso. Vedi anche: link

Infine, puoi aggiungere i tuoi handbang handler con il meccanismo binfmt_misc . Ad esempio, puoi aggiungere un gestore personalizzato per i file .jar . Questo meccanismo supporta anche i gestori per estensione di file. Un'altra applicazione è eseguibili in modo trasparente eseguibili di una diversa architettura con QEMU .

Non penso che POSIX specifichi comunque gli shebang: link , anche se menziona in sezioni razionali, e nella forma "se gli script eseguibili sono supportati dal sistema può accadere qualcosa".

    

Leggi altre domande sui tag