È 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 execveal nuovo processo.
Il kernel non esegue alcuna interpretazione nel percorso execve(dipende dalle funzioni wrapper come execvpeseguire la ricerca PATH) o in uno shebang (che reindirizza più o meno la execvechiamata 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/envshebang .
¹ 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.
execvené nello shebang sebbene abbia poco senso avere un percorso relativo in uno shebang.
/lib64/ld-linux-x86-64.so.2(vedi lddoutput). Linux lo rende completamente generico: il binfmtsupporto (dalla 2.1.43) consente di registrare coppie di interpreti-path / magic-number-or-file-extension. Puoi far .exeinvocare PE32 winequando 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 PATHnon 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 perlin modo portatile o simile è usare #!/usr/bin/env perl. Viene eseguito il kernel /usr/bin/env, che eredita una PATHvariabile di ambiente. envreperti (in questo esempio) perlin PATHe utilizza il execve(2)chiamata di sistema per ottenere il kernel per eseguire il perlfile 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/stracecerto punto) con 2 argomenti.