È possibile avere un shebang che, invece di specificare un percorso per un interprete, abbia il nome dell'interprete e consenta alla shell di trovarlo attraverso $ PATH?
In caso contrario, c'è un motivo per cui?
È possibile avere un shebang che, invece di specificare un percorso per un interprete, abbia il nome dell'interprete e consenta alla shell di trovarlo attraverso $ PATH?
In caso contrario, c'è un motivo per cui?
Risposte:
La ricerca PATH è una caratteristica della libreria C standard nello spazio utente, così come le variabili di ambiente in generale. Il kernel non vede le variabili di ambiente tranne quando passa sopra un ambiente dal chiamante execve
al nuovo processo.
Il kernel non esegue alcuna interpretazione nel percorso execve
(dipende dalle funzioni wrapper come execvp
eseguire la ricerca PATH) o in uno shebang (che reindirizza più o meno la execve
chiamata internamente). Quindi devi inserire il percorso assoluto nello shebang¹. L' implementazione originale di shebang era solo poche righe di codice e da allora non è stata ampliata in modo significativo.
Nelle prime versioni di Unix, la shell ha fatto il lavoro di invocare se stessa quando ha notato che si stava invocando uno script. Shebang è stato aggiunto nel kernel per diversi motivi (riassumendo la logica di Dennis Ritchie :
Shebang senza percorso richiederebbe sia di aumentare il kernel per accedere alle variabili di ambiente e di elaborare PATH
, sia di far eseguire al kernel un programma di spazio utente che esegue la ricerca PATH. Il primo metodo richiede l'aggiunta di una quantità sproporzionata di complessità al kernel. Il secondo metodo è già possibile con uno #!/usr/bin/env
shebang .
¹ Se si inserisce un percorso relativo, viene interpretato relativamente alla directory corrente del processo (non alla directory contenente lo script), che non è molto utile in un shebang.
execve
né nello shebang sebbene abbia poco senso avere un percorso relativo in uno shebang.
/lib64/ld-linux-x86-64.so.2
(vedi ldd
output). Linux lo rende completamente generico: il binfmt
supporto (dalla 2.1.43) consente di registrare coppie di interpreti-path / magic-number-or-file-extension. Puoi far .exe
invocare PE32 wine
quando li esegui, invocare i file di classe Java e jar java
, ecc. Ecc.
C'è di più in corso di quanto sembri. #!
le linee vengono interpretate dal kernel Unix o Linux, #!
non è un aspetto delle shell. Ciò significa che PATH
non esiste davvero nel momento in cui il kernel decide cosa eseguire.
Il modo più comune per affrontare il non sapere quale eseguibile eseguire o chiamare perl
in modo portatile o simile è usare #!/usr/bin/env perl
. Viene eseguito il kernel /usr/bin/env
, che eredita una PATH
variabile di ambiente. env
reperti (in questo esempio) perl
in PATH
e utilizza il execve(2)
chiamata di sistema per ottenere il kernel per eseguire il perl
file eseguibile.
$ strace sleep 1
execve("/usr/bin/sleep", ["sleep", "1"], [/* 99 vars */]) = 0
La conversione al percorso completo viene eseguita dalla shell (più generale: nello spazio utente). Il kernel si aspetta un nome file / percorso a cui può accedere direttamente.
Se vuoi che il sistema trovi il tuo eseguibile guardando attraverso la variabile PATH, puoi riscrivere il tuo shebang come #!/usr/bin/env EXEC
.
Ma anche in questo caso non è il kernel che esegue la ricerca.
strace
(convertita ad un /usr/bin/strace
certo punto) con 2 argomenti.