Poiché il file non appartiene a nessuno dei tipi di file eseguibili riconosciuti dal sistema e supponendo che si disponga dell'autorizzazione per eseguire quel file, la execve()
chiamata di sistema in genere fallisce con un errore ENOEXEC
( non un file eseguibile ).
Ciò che accade quindi dipende dall'applicazione e / o dalla funzione di libreria utilizzata per eseguire il comando.
Può essere ad esempio una shell, la funzione execlp()
/ execvp()
libc.
La maggior parte delle altre applicazioni utilizzerà una di quelle quando eseguono un comando. Invoceranno una shell ad esempio tramite la system("command line")
funzione libc che in genere invocherà sh
l'analisi di quella riga di comando (il cui percorso può essere determinato al momento della compilazione (come /bin/sh
vs /usr/xpg4/bin/sh
su Solaris)), o invocherà la shell memorizzata $SHELL
da loro stessi come vi
con il suo !
comando o xterm -e 'command line'
molti altri comandi ( su user -c
invocherà la shell di accesso dell'utente invece di $SHELL
).
Generalmente, un file di testo privo di shebang che non inizia con #
viene considerato come uno sh
script. Quale sh
è varierà comunque.
execlp()
/ execvp()
, al execve()
ritorno ENOEXEC
in genere invocherà sh
su di esso. Per i sistemi che ne hanno più di uno sh
perché possono conformarsi a più di uno standard, il che sh
è generalmente determinato al momento della compilazione (dell'applicazione che utilizza execvp()
/ execlp()
collegando un diverso BLOB di codice che fa riferimento a un percorso diverso sh
). Ad esempio, su Solaris, sarà /usr/xpg4/bin/sh
(uno standard, POSIX sh
) o /bin/sh
(la shell Bourne (una shell antiquata) su Solaris 10 e precedenti, ksh93 in Solaris 11).
Quando si tratta di conchiglie, ci sono molte varianti. bash
, AT&T ksh
, la shell Bourne in genere interpreterà lo script stesso (in un processo figlio a meno che non exec
venga utilizzato) dopo aver simulato un execve()
, che non ha impostato tutte le variabili non esportate, chiuso tutte le fds close-on-exec, rimosso tutte le trap personalizzate, alias, funzioni ... ( bash
interpreterà lo script in sh
modalità). yash
si eseguirà (con sh
as argv[0]
so in sh
mode) per interpretarlo.
zsh
, pdksh
, ash
Conchiglie basati in genere richiamare sh
(il percorso, determinato al momento della compilazione).
Per csh
e tcsh
(e sh
per alcuni dei primi BSD), se il primo carattere del file è #
, allora si eseguiranno per interpretarlo, e in sh
altro modo. Questo risale a un periodo pre-shebang in cui csh
riconosceva #
come commenti ma non la shell Bourne, quindi #
c'era un indizio che si trattasse di uno script csh.
fish
(almeno versione 2.4.0), restituisce solo un errore se execve()
fallisce (non tenta di trattarlo come uno script).
Alcune shell (come bash
o AT&T ksh
) proveranno prima a stabilire in modo euristico se il file è probabilmente destinato a essere uno script o meno. Quindi potresti scoprire che alcune shell si rifiuteranno di eseguire uno script se nei primi byte ha un carattere NUL.
Nota anche che se execve()
fallisce con ENOEXEC ma il file ha una linea shebang, alcune shell cercano di interpretare quella linea shebang.
Quindi alcuni esempi:
- Quando
$SHELL
è /bin/bash
, xterm -e 'myscript with args'
sarà myscript
interpretato da bash
in sh
modalità. Mentre con xterm -e myscript with args
, xterm
utilizzerà execvp()
così lo script verrà interpretato da sh
.
su -c myscript
su Solaris 10 dove root
si trova la shell di login /bin/sh
ed /bin/sh
è la shell Bourne sarà myscript
interpretata dalla shell Bourne.
/usr/xpg4/bin/awk 'BEGIN{system("myscript")'
su Solaris 10 verrà interpretato da /usr/xpg4/bin/sh
(stesso per /usr/xpg4/bin/env myscript
).
find . -prune -exec myscript {} \;
su Solaris 10 (utilizzo execvp()
) verrà interpretato /bin/sh
anche con /usr/xpg4/bin/find
, anche in un ambiente POSIX (un bug di conformità).
csh -c myscript
lo interpreterà csh
se inizia con #
, sh
altrimenti.
Tutto sommato, non puoi essere sicuro di quale shell verrà utilizzata per interpretare quello script se non sai come e da cosa verrà invocato.
In ogni caso, read -p
è bash
solo sintassi, quindi ti consigliamo di assicurarti che lo script sia interpretato da bash
(ed evita quell'estensione fuorviante .sh
). O conosci il percorso bash
dell'eseguibile e usi:
#! /path/to/bash -
read -p ...
Oppure puoi provare a fare affidamento su una $PATH
ricerca bash
dell'eseguibile (supponendo che bash
sia installato) usando:
#! /usr/bin/env bash
read -p ...
(si env
trova quasi ovunque /usr/bin
). In alternativa, è possibile renderlo compatibile POSIX + Bourne, nel qual caso è possibile utilizzarlo /bin/sh
. Tutti i sistemi avranno a /bin/sh
. Sulla maggior parte di essi sarà (per la maggior parte) compatibile POSIX, ma potresti comunque trovare una shell Bourne ogni tanto.
#! /bin/sh -
printf >&2 'Enter a user name: '
read user
printf '%s\n' "$user"