In bash
o sh
, suppongo che tutto ciò che inizia con #
è un commento .
Ma negli bash
script scriviamo:
#!/bin/bash
E negli script Python, c'è:
#!/bin/python
Questo significa che di #
per sé è un commento, mentre #!
non lo è?
In bash
o sh
, suppongo che tutto ciò che inizia con #
è un commento .
Ma negli bash
script scriviamo:
#!/bin/bash
E negli script Python, c'è:
#!/bin/python
Questo significa che di #
per sé è un commento, mentre #!
non lo è?
Risposte:
#!
riga viene utilizzata prima dell'esecuzione dello script, quindi ignorata quando viene eseguito lo script.Stai chiedendo quale sia la differenza tra una linea shebang e un commento normale.
Una riga che inizia con #!
è tanto un commento quanto qualsiasi altra riga che inizia con #
. Questo è vero se #!
è la prima riga del file o in qualsiasi altro luogo. #!/bin/sh
ha un effetto , ma non viene letto dall'interprete stesso .
#
non è un commento in tutti i linguaggi di programmazione ma, come sapete, è un commento nelle shell in stile Bourne tra cui sh
e bash
(così come la maggior parte delle shell in stile non Bourne, come csh
). È anche un commento in Python . Ed è un commento in una varietà di file di configurazione che in realtà non sono affatto script (come /etc/fstab
).
Supponiamo che uno script di shell inizi con #!/bin/sh
. Questo è un commento e l'interprete (la shell) ignora tutto sulla riga dopo il #
personaggio.
Lo scopo di una #!
linea non è di fornire informazioni all'interprete. Lo scopo della #!
linea è di dire al sistema operativo (o qualunque processo avvii l'interprete) cosa usare come interprete .
Se si richiama lo script come file eseguibile, ad esempio eseguendolo ./script.sh
, il sistema consulta la prima riga per vedere se inizia #!
, seguito da zero o più spazi, seguito da un comando. In tal caso, esegue quel comando con il nome dello script come argomento. In questo esempio, viene eseguito /bin/sh script.sh
(o, tecnicamente, /bin/sh ./script.sh
).
Se invochi lo script chiamando esplicitamente l'interprete, la #!
linea non viene mai consultata. Quindi, se corri sh script.sh
, la prima riga non ha alcun effetto. Se script2.sh
la prima riga è #!/usr/games/nibbles
, in esecuzione sh script2.sh
non tenterà di aprire lo script nibbles
(ma lo ./script2.sh
farà).
Noterai che in nessun caso l'estensione dello script ( .sh
), se ne ha una, influisce sul modo in cui viene eseguita. In un sistema simile a Unix, ciò non influisce normalmente su come viene eseguito lo script. Su alcuni altri sistemi, come Windows, la #!
linea shebang potrebbe essere completamente ignorata dal sistema e l'estensione potrebbe determinare ciò che esegue gli script. (Ciò non significa che devi fornire le estensioni degli script, ma è uno dei motivi per cui, se lo fai, dovrebbero essere corretti.)
#!
è stato scelto per servire questo scopo proprio perché #
inizia un commento. La #!
linea è per il sistema, non per l'interprete, e dovrebbe essere ignorata dall'interprete.
Tu (originariamente) hai detto che usi #!/bin/sh
per gli bash
script. Dovresti farlo solo se lo script non richiede alcuna delle bash
estensioni - sh
deve essere in grado di eseguire lo script. sh
non è sempre un collegamento simbolico a bash
. Spesso, anche su tutti i sistemi Debian e Ubuntu remoti di recente , sh
è un collegamento simbolico a dash
.
Hai anche detto (nella prima versione della tua domanda, prima di modificarlo) che avvii i tuoi script Python con #!/bin/sh read by the interpretor
. Se lo intendi letteralmente, allora dovresti assolutamente smettere di farlo. Se hello.py
inizia con quella riga, l'esecuzione ./hello.py
viene eseguita:
/bin/sh read by the interpretor hello.py
/bin/sh
proverà ad eseguire uno script chiamato read
(con by the interpretor hello.py
i suoi argomenti), read
(si spera) non verrà trovato e il tuo script Python non verrà mai visto da un interprete Python.
Se stai commettendo questo errore ma non hai il problema che sto descrivendo, probabilmente stai invocando i tuoi script Python specificando esplicitamente l'interprete (ad esempio, python hello.py
), facendo sì che la prima riga venga ignorata. Quando distribuisci i tuoi script ad altri o li usi molto tempo dopo, potrebbe non essere chiaro che questo è necessario per farli funzionare. È meglio risolverli ora. O almeno rimuovere completamente la prima riga, in modo che quando non riescono a funzionare con ./
il messaggio di errore abbia senso.
Per gli script Python, se sai dove si trova (o sta per essere) l'interprete Python, puoi scrivere la #!
riga allo stesso modo:
#!/usr/bin/python
Oppure, se si tratta di uno script Python 3, è necessario specificare python3
, poiché python
è quasi sempre Python 2 :
#!/usr/bin/python3
Tuttavia, il problema è che mentre /bin/sh
dovrebbe sempre esistere, e /bin/bash
quasi sempre esiste su sistemi in cui bash
è presente il sistema operativo, Python può esistere in una varietà di luoghi.
Pertanto, molti programmatori Python usano questo invece:
#!/usr/bin/env python
(O #!/usr/bin/env python3
per Python 3.)
Questo fa sì che lo script faccia affidamento env
sull'essere nel "posto giusto" invece di fare affidamento sul python
fatto di essere nel posto giusto. Questa è una buona cosa, perché:
env
si trova quasi sempre in /usr/bin
.python
sia il tuo script da eseguire è quello che appare per primo nel file PATH
. A partire hello.py
da #!/usr/bin/env python
make ./hello.py
run /usr/bin/env python hello.py
, che è (praticamente) equivalente a running python hello.py
.Il motivo per cui non #!python
è possibile utilizzare è che:
/
).python
nella directory corrente . Cercare il percorso quando il comando non contiene una barra è un comportamento specifico della shell.Occasionalmente uno script Python o altro che non è uno script shell avrà una riga shebang che inizia con #!/bin/sh ...
dove si ...
trova un altro codice. Questo a volte è corretto, perché ci sono alcuni modi per invocare la shell ( sh
) compatibile con Bourne con argomenti per farlo invocare un interprete Python. (Probabilmente uno degli argomenti conterrà python
.) Tuttavia, per la maggior parte degli scopi, #!/usr/bin/env python
è più semplice, più elegante e più probabile che funzioni nel modo desiderato.
Molti linguaggi di programmazione e di scripting, e alcuni altri formati di file, usano #
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, #
normalmente non è un commento, ma come caso speciale la prima riga viene ignorata se inizia con #!
. Questo facilita l'uso della #!
sintassi anche se #
altrimenti non fa una riga un commento.
Sebbene sia 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 .vmx
file definiscono le macchine virtuali. Puoi "eseguire" una macchina virtuale come se fosse uno script perché questi file sono contrassegnati come eseguibili e hanno una linea shebang che li fa aprire in un'utilità VMware.
rm
rimuove i file. Non è un linguaggio di scripting. Tuttavia, #!/bin/rm
è possibile eseguire un file che viene avviato e contrassegnato come eseguibile e, quando lo si esegue, rm
viene richiamato su di esso, eliminandolo.
Questo è spesso concettualizzato come "il file si elimina da solo". Ma il file non è davvero in esecuzione. Questo è più simile alla situazione sopra descritta per i .vmx
file.
Tuttavia, poiché la #!
riga facilita l'esecuzione di un semplice comando (inclusi gli argomenti della riga di comando), è possibile eseguire alcuni script in questo modo. Come semplice esempio di uno "script" più sofisticato di #!/bin/rm
, considera:
#!/usr/bin/env tee -a
Questo prende l'input dell'utente in modo interattivo, lo fa ritornare all'utente riga per riga e lo aggiunge alla fine del file "script".
Utile? Non molto. Concettualmente interessante? Totalmente! Sì. (Un po '.)
Script / programmi che sono più lingue contemporaneamente , ad esempio, per simulare la funzionalità hashbang nei sistemi operativi che non lo possedevano .
(Questi programmi sono chiamati poliglotti , ma ciò non deve essere confuso con l'altro senso di poliglotta nello sviluppo del software , un programma / progetto in cui parti diverse sono scritte in lingue diverse.)
Metacommands in QBasic / QuickBASIC, che segnalavano al compilatore (per codice compilato) opzioni per la generazione di codice, ma facevano parte dei commenti e quindi venivano ignorati durante la compilazione / interpretazione effettiva.
-x
bandiera Pythons ?
-x
"salta [s] la prima riga ..." la 2a riga viene numerata 1
anziché 2
la 3a riga 2
anziché 3
, ecc. Ecco perché non dovresti usare quella bandiera. ;) -x
è per lo scripting su sistemi operativi non Unix che hanno una sintassi simile a shebang che non inizia #
(quindi non un commento Python).
perl script.pl
vs ./script.pl
), allora l'interprete sarà leggere la linea shebang per analizzare le bandiere, come -w
. Tuttavia, non è consigliabile fare affidamento su questa funzione.
Uno shebang è la sequenza di caratteri costituita dal segno del numero di caratteri e dal punto esclamativo (ad esempio "#!") Quando si presenta come i due caratteri iniziali sulla riga iniziale di uno script.
Sotto i sistemi operativi * nix, quando viene eseguito uno script che inizia con uno shebang, il programma di caricamento programma analizza il resto della riga iniziale dello script come una direttiva interprete; viene invece eseguito il programma interprete specificato, passando ad esso come argomento il percorso inizialmente utilizzato durante il tentativo 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 al programma di caricamento del programma viene richiesto di eseguire il programma "/ bin / sh", ad esempio la shell Bourne o una shell compatibile, passando "path / to / your-script" come primo argomento.
Di conseguenza, uno script viene chiamato con il percorso "path / to / python-script" e inizia con la seguente riga:
#!/bin/python
quindi al programma caricato viene richiesto di eseguire il programma "/ bin / python" invece ad es. interprete Python, passando "path / to / python-script" come primo argomento.
In breve "#" commenterà una riga mentre la sequenza di caratteri "#!" che si presentano come i primi due caratteri sulla riga iniziale di uno script hanno significato delineato 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 (dai collaboratori di Wikipedia ). Questo articolo è concesso in licenza in base a CC-BY-SA 3.0 , come il contenuto dell'utente qui su AU, quindi questa derivazione è consentita con attribuzione.
#!
viene chiamato shebang
quando si presenta come i due caratteri iniziali 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 verrà interpretato come un commento.
Per gentile concessione: http://en.wikipedia.org/wiki/Shebang_%28Unix%29
In generale, se un file è eseguibile, ma in realtà non è un programma eseguibile (binario), e tale linea è presente, il programma specificato dopo #! viene avviato con lo scriptname e tutti i suoi argomenti. Questi due personaggi # e! devono essere i primi due byte nel file!
Informazioni dettagliate: http://wiki.bash-hackers.org/scripting/basics#the_shebang
No, viene utilizzato solo dalla exec
chiamata di sistema del kernel Linux e trattato come un commento dall'interprete
Quando fai su bash:
./something
su Linux, questo chiama la exec
chiamata di sistema con il percorso ./something
.
Questa riga del kernel viene chiamata sul file passato a exec
: https://github.com/torvalds/linux/blob/v4.8/fs/binfmt_script.c#L25
if ((bprm->buf[0] != '#') || (bprm->buf[1] != '!'))
Legge i primi byte del file e li confronta con #!
.
Se il confronto è vero, il resto della riga viene analizzato dal kernel Linux, che effettua un'altra exec
chiamata con percorso /usr/bin/env python
e file corrente come primo argomento:
/usr/bin/env python /path/to/script.py
e questo funziona con qualsiasi linguaggio di scripting che utilizza #
come carattere di commento.
E sì, puoi fare 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
#!
sembra essere leggibile dall'uomo, ma non è necessario.
Se il file si avviava con byte diversi, la exec
chiamata di sistema utilizzava un gestore diverso. L'altro gestore incorporato più importante è per i file eseguibili ELF: https://github.com/torvalds/linux/blob/v4.8/fs/binfmt_elf.c#L1305 che verifica la presenza di byte 7f 45 4c 46
(che risulta essere umano leggibile per .ELF
). Confermiamo leggendo i primi 4 byte di /bin/ls
, che è un eseguibile ELF:
head -c 4 "$(which ls)" | hd
produzione:
00000000 7f 45 4c 46 |.ELF|
00000004
Quindi quando il kernel vede quei byte, prende il file ELF, lo mette in memoria correttamente e avvia un nuovo processo con esso. Vedi anche: https://stackoverflow.com/questions/8352535/how-does-kernel-get-an-executable-binary-file-running-under-linux/31394861#31394861
Infine, puoi aggiungere i tuoi gestori shebang con il binfmt_misc
meccanismo. Ad esempio, è possibile aggiungere un gestore personalizzato per i .jar
file . Questo meccanismo supporta anche i gestori per estensione del file. Un'altra applicazione è eseguire in modo trasparente eseguibili di un'architettura diversa con QEMU .
Tuttavia , non credo che POSIX specifichi shebang: https://unix.stackexchange.com/a/346214/32558 , anche se menzionato nelle sezioni logiche e nel modulo "se gli script eseguibili sono supportati dal sistema qualcosa potrebbe accadere".
#include
. Anche lì, il#
non è inteso come un commento.