Étant donné que le fichier ne fait partie d'aucun type d'exécutable reconnu par le système, et en supposant que vous avez la permission d'exécuter ce fichier, l' execve()
appel système échoue généralement avec une erreur ENOEXEC
( pas un exécutable ).
Ce qui se passe alors dépend de l'application et / ou de la fonction de bibliothèque utilisée pour exécuter la commande.
Cela peut être par exemple un shell, la fonction execlp()
/ execvp()
libc.
La plupart des autres applications utiliseront l'une de ces applications lorsqu'elles exécuteront une commande. Ils invoqueront un shell par exemple au moyen de la system("command line")
fonction libc qui invoquera généralement sh
pour analyser cette ligne de commande (dont le chemin peut être déterminé au moment de la compilation (comme /bin/sh
vs /usr/xpg4/bin/sh
sur Solaris)), ou invoquer le shell stocké $SHELL
par eux-mêmes comme vi
avec sa !
commande, et xterm -e 'command line'
et de nombreuses autres commandes ( su user -c
invoquera le shell de connexion de l'utilisateur au lieu de $SHELL
).
Généralement, un fichier texte sans shebang qui ne commence pas par #
est considéré comme un sh
script. Ce sh
qui variera cependant.
execlp()
/ execvp()
, lors du execve()
retour, il ENOEXEC
sera généralement invoqué sh
. Pour les systèmes qui en ont plus d'un sh
car ils peuvent se conformer à plus d'une norme, sh
celle-ci sera généralement déterminée au moment de la compilation (de l'application utilisant execvp()
/ execlp()
en liant un autre bloc de code qui fait référence à un chemin différent sh
). Par exemple, sur Solaris, ce sera /usr/xpg4/bin/sh
(un standard, POSIX sh
) ou /bin/sh
(le shell Bourne (un shell obsolète) sur Solaris 10 et les versions antérieures, ksh93 dans Solaris 11).
En ce qui concerne les coquilles, il y a beaucoup de variations. bash
, AT&T ksh
, le shell Bourne interprètera généralement le script lui-même (dans un processus enfant sauf s'il exec
est utilisé) après avoir simulé un execve()
, c'est-à-dire annuler toutes les variables non exportées, fermer tous les fds close-on-exec, supprimer tous les pièges personnalisés, alias, fonctions ... ( bash
interprétera le script en sh
mode). yash
s'exécutera (avec sh
comme argv[0]
ainsi en sh
mode) pour l'interpréter.
zsh
, pdksh
, ash
Coquilles à base invoqueront généralement sh
( dont le trajet déterminé au moment de la compilation).
Pour csh
et tcsh
(et pour sh
certains des premiers BSD), si le premier caractère du fichier est #
, ils s'exécuteront eux-mêmes pour l'interpréter, et sh
autrement. Cela remonte à une époque pré-shebang où l'on csh
reconnaissait #
comme commentaires mais pas le shell Bourne, donc #
c'était un indice qu'il s'agissait d'un script csh.
fish
(au moins la version 2.4.0), renvoie simplement une erreur en cas d' execve()
échec (il ne tente pas de le traiter comme un script).
Certains shells (comme bash
AT&T ksh
) essaieront d'abord de déterminer de manière heuristique si le fichier est probablement destiné à être un script ou non. Vous pouvez donc constater que certains shells refuseront d'exécuter un script s'il contient un caractère NUL dans les premiers octets.
Notez également que si execve()
échoue avec ENOEXEC mais que le fichier a une ligne de shebang, certains shells essaient d'interpréter cette ligne de shebang eux-mêmes.
Voici donc quelques exemples:
- Quand
$SHELL
est /bin/bash
, xterm -e 'myscript with args'
aura myscript
interprété par bash
en sh
mode. Tandis qu'avec xterm -e myscript with args
, xterm
utilisera execvp()
donc le script sera interprété par sh
.
su -c myscript
sous Solaris 10 où root
est /bin/sh
et /bin/sh
est le shell de connexion, le shell Bourne aura été myscript
interprété par le shell Bourne.
/usr/xpg4/bin/awk 'BEGIN{system("myscript")'
sous Solaris 10, il sera interprété par /usr/xpg4/bin/sh
(idem pour /usr/xpg4/bin/env myscript
).
find . -prune -exec myscript {} \;
sous Solaris 10 (en utilisant execvp()
) le fera interpréter par /bin/sh
even avec /usr/xpg4/bin/find
, même dans un environnement POSIX (un bug de conformité).
csh -c myscript
l'aura interprété par csh
s'il commence par #
, sh
sinon.
Dans l'ensemble, vous ne pouvez pas être sûr du shell qui sera utilisé pour interpréter ce script si vous ne savez pas comment et par quoi il sera invoqué.
Dans tous les cas, la syntaxe read -p
est bash
-only, vous voudrez donc vous assurer que le script est interprété par bash
(et éviter cette .sh
extension trompeuse ). Soit vous connaissez le chemin de l' bash
exécutable et utilisez:
#! /path/to/bash -
read -p ...
Ou vous pouvez essayer de vous fier à une $PATH
recherche de l' bash
exécutable (en supposant qu'il bash
soit installé) en utilisant:
#! /usr/bin/env bash
read -p ...
(se env
trouve presque partout dans /usr/bin
). Alternativement, vous pouvez le rendre compatible POSIX + Bourne, auquel cas vous pouvez l'utiliser /bin/sh
. Tous les systèmes auront un /bin/sh
. Sur la plupart d'entre eux, il sera (pour la plupart) compatible POSIX, mais vous pouvez toujours y trouver de temps en temps un shell Bourne.
#! /bin/sh -
printf >&2 'Enter a user name: '
read user
printf '%s\n' "$user"