#! / bin / sh -
È (o almeno era) spesso lo shebang raccomandato per far interpretare una sceneggiatura /bin/sh
.
Perché non solo #! /bin/sh
o #!/bin/sh
?
A cosa serve -
?
#! / bin / sh -
È (o almeno era) spesso lo shebang raccomandato per far interpretare una sceneggiatura /bin/sh
.
Perché non solo #! /bin/sh
o #!/bin/sh
?
A cosa serve -
?
Risposte:
Questo è per un motivo simile al motivo per cui è necessario scrivere:
rm -- *.txt
E non
rm *.txt
A meno che non sia possibile garantire che nessuno dei .txt
file nella directory corrente abbia un nome che inizia con -
.
Nel:
rm <arg>
<arg>
è considerata un'opzione se inizia con -
o un file da rimuovere in altro modo. Nel
rm - <arg>
arg
viene sempre considerato come un file da rimuovere indipendentemente dal fatto che inizi -
o meno.
È lo stesso per sh
.
Quando si esegue uno script che inizia con
#! /bin/sh
In genere con:
execve("path/to/the-script", ["the-script", "arg"], [environ])
Il sistema lo trasforma in:
execve("/bin/sh", ["/bin/sh", "path/to/the-script", "arg"], [environ])
Di path/to/the-script
solito non è qualcosa che è sotto il controllo dell'autore dello script. L'autore non può prevedere dove verranno archiviate le copie dello script né con quale nome. In particolare, non possono garantire che il nome path/to/the-script
con cui viene chiamato non inizi -
(o +
che è anche un problema sh
). Ecco perché abbiamo bisogno del -
qui per segnare la fine delle opzioni.
Ad esempio, sul mio sistema zcat
(come la maggior parte degli altri script in realtà) c'è un esempio di uno script che non ha seguito quella raccomandazione:
$ head -n1 /bin/zcat
#!/bin/sh
$ mkdir +
$ ln -s /bin/zcat +/
$ +/zcat
/bin/sh: +/: invalid option
[...]
Ora potresti chiedere perché #! /bin/sh -
e no #! /bin/sh --
?
Mentre #! /bin/sh --
funzionerebbe con le shell POSIX, #! /bin/sh -
è più portatile; in particolare alle versioni antiche di sh
. sh
trattare -
come e precede getopt()
la fine dell'opzione e l'uso generale di --
per contrassegnare la fine delle opzioni da molto tempo. Il modo in cui la shell Bourne (dalla fine degli anni '70) analizzava i suoi argomenti, solo il primo argomento veniva preso in considerazione per le opzioni se fosse iniziato -
. Tutti i personaggi dopo -
verrebbero trattati come nomi di opzioni; se non c'erano personaggi dopo il -
, non c'erano opzioni. Quelle conchiglie bloccate e in seguito simili a quelle di Bourne riconoscono -
come un modo per segnare la fine delle opzioni.
Nella shell Bourne (ma non nelle moderne shell simili a Bourne), #! /bin/sh -euf
aggirerebbe anche il problema in quanto solo il primo argomento è stato preso in considerazione per le opzioni.
Ora, si potrebbe dire che siamo pedanti qui, ed è anche il motivo per cui ho scritto la necessità in corsivo sopra:
-
o +
o li inserisce in una directory il cui nome inizia con -
o +
.execvp()
/ execlp()
-type. E in quel caso, in genere li invochi sia perché the-script
venga cercato $PATH
nel qual caso l'argomento percorso alla execve()
chiamata di sistema in genere inizierà con /
(non -
nor +
) che come ./the-script
se si desideri the-script
eseguire nella directory corrente (e quindi il percorso inizia con ./
, -
né con +
nessuno dei due).Ora oltre al problema della correttezza teorica , c'è un'altra ragione per cui è #! /bin/sh -
stata raccomandata come buona pratica . E questo risale al tempo in cui diversi sistemi supportavano ancora gli script setuid.
Se hai uno script che contiene:
#! /bin/sh
/bin/echo "I'm running as root"
E quello script era setuid root (come con i -r-sr-xr-x root bin
permessi), su quei sistemi, quando eseguito da un normale utente, il
execve("/bin/sh", ["/bin/sh", "path/to/the-script"], [environ])
sarebbe fatto come root
!
Se l'utente creasse un collegamento simbolico /tmp/-i -> path/to/the-script
e lo eseguisse come -i
, allora avvierebbe una shell interattiva ( /bin/sh -i
) come root
.
Il -
funzionerebbe in giro che (non avrebbe funzionato intorno alla questione della razza-condizioni , o il fatto che alcune sh
implementazioni, come alcuni ksh88
quelli basati avrebbero occhiata argomenti script senza /
in $PATH
però).
Al giorno d'oggi, quasi nessun sistema supporta più lo script setuid e alcuni di quelli che ancora lo fanno (di solito non di default), finiscono per fare un execve("/bin/sh", ["/bin/sh", "/dev/fd/<n>", arg])
(dove <n>
è un descrittore di file aperto per la lettura sullo script) che aggira sia questo problema che il condizione di gara.
Si noti che si verificano problemi simili con la maggior parte degli interpreti, non solo con shell tipo Bourne. Le shell non simili a Bourne generalmente non supportano -
come marker di fine opzione, ma generalmente supportano --
invece (almeno per le versioni moderne).
Anche
#! /usr/bin/awk -f
#! /usr/bin/sed -f
Non avere il problema poiché l'argomento successivo è considerato come argomento -f
dell'opzione in ogni caso, ma non funziona ancora se path/to/script
è -
(nel qual caso, con la maggior parte sed
/ awk
implementazioni, sed
/ awk
non leggere il codice dal -
file, ma da stdin invece).
Inoltre, sulla maggior parte dei sistemi, non è possibile utilizzare:
#! /usr/bin/env sh -
#! /usr/bin/perl -w --
Come nella maggior parte dei sistemi, il meccanismo shebang consente solo un argomento dopo il percorso dell'interprete.
Per quanto riguarda se usare #! /bin/sh -
vs #!/bin/sh -
, questa è solo una questione di gusti. Preferisco il primo in quanto rende più visibile il percorso dell'interprete e facilita la selezione del mouse. C'è una leggenda che dice che lo spazio era necessario in alcune antiche versioni di Unix ma AFAIK, che non è mai stato verificato.
Un ottimo riferimento alla Shebang Unix può essere trovato su https://www.in-ulm.de/~mascheck/various/shebang
bash
accetta opzioni come ogni altra shell. Essendo una shell tipo Bourne e POSIX, bash
accetta sia #! /bin/bash -
e #! /bin/bash --
.