Supposons que le shell par défaut de mon compte soit zsh mais j'ai ouvert le terminal et lancé bash et exécuté un script nommé prac002.sh
, quel interpréteur de shell serait utilisé pour exécuter le script, zsh ou bash? Prenons l'exemple suivant:
papagolf@Sierra ~/My Files/My Programs/Learning/Shell % sudo cat /etc/passwd | grep papagolf
[sudo] password for papagolf:
papagolf:x:1000:1001:Rex,,,:/home/papagolf:/usr/bin/zsh
# papagolf's default shell is zsh
papagolf@Sierra ~/My Files/My Programs/Learning/Shell % bash
# I fired up bash. (See that '%' prompt in zsh changes to '$' prompt, indicating bash.)
papagolf@Sierra:~/My Files/My Programs/Learning/Shell$ ./prac002.sh
Enter username : Rex
Rex
# Which interpreter did it just use?
** EDIT: ** Voici le contenu du script
papagolf@Sierra ~/My Files/My Programs/Learning/Shell % cat ./prac002.sh
read -p "Enter username : " uname
echo $uname
. prac002.sh
, en supposant que votre script est dans le répertoire courant.. ./prac002.sh
et il fonctionnera avec le shell actuel, c'est-à-dire dot (.
), space () suivi du chemin de votre script. Cela s'appelle dot-sourcing votre script. ;-)Réponses:
Parce que le script ne commence pas par une
#!
ligne shebang indiquant quel interprète utiliser, POSIX dit que :Cette formulation est un peu ambiguë, et différents coques ont des interprétations différentes.
Dans ce cas, Bash exécutera le script en utilisant lui-même . D'un autre côté, si vous l'exécutiez à partir de zsh à la place, zsh utiliserait
sh
(quoi que ce soit sur votre système) à la place.Vous pouvez vérifier ce comportement pour ce cas en ajoutant ces lignes au script:
Vous remarquerez que, à partir de Bash, la première ligne génère votre version, tandis que la seconde ne dit jamais rien, quel que soit le shell que vous utilisez.
/bin/sh
est, disons,dash
alors aucune ligne ne sortira quoi que ce soit lorsque le script est exécuté à partir de zsh ou de dash./bin/sh
est un lien vers Bash, vous verrez la sortie de la première ligne dans tous les cas./bin/sh
est différente de celle que vous utilisiez directement, vous verrez une sortie différente lorsque vous exécutez le script directement depuis bash et depuis zsh.La
ps -p $$
commande de la réponse de rools affichera également des informations utiles sur la commande utilisée par le shell pour exécuter le script.la source
execl()
appel se produit-il lorsqu'un script shell ne contient pas de shebang et est exécuté commescriptname
? Cela ne se produit-il pas lorsqu'un script shell est exécuté en tant quebash scriptname
? Cela ne se produit-il pas lorsqu'un script shell contient un shebang et est exécuté commescriptname
?É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 erreurENOEXEC
( 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éralementsh
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 commevi
avec sa!
commande, etxterm -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 unsh
script. Cesh
qui variera cependant.execlp()
/execvp()
, lors duexecve()
retour, ilENOEXEC
sera généralement invoquésh
. Pour les systèmes qui en ont plus d'unsh
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 utilisantexecvp()
/execlp()
en liant un autre bloc de code qui fait référence à un chemin différentsh
). Par exemple, sur Solaris, ce sera/usr/xpg4/bin/sh
(un standard, POSIXsh
) 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&Tksh
, le shell Bourne interprètera généralement le script lui-même (dans un processus enfant sauf s'ilexec
est utilisé) après avoir simulé unexecve()
, 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 ensh
mode).yash
s'exécutera (avecsh
commeargv[0]
ainsi ensh
mode) pour l'interpréter.zsh
,pdksh
,ash
Coquilles à base invoqueront généralementsh
( dont le trajet déterminé au moment de la compilation).Pour
csh
ettcsh
(et poursh
certains des premiers BSD), si le premier caractère du fichier est#
, ils s'exécuteront eux-mêmes pour l'interpréter, etsh
autrement. Cela remonte à une époque pré-shebang où l'oncsh
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&Tksh
) 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:
$SHELL
est/bin/bash
,xterm -e 'myscript with args'
auramyscript
interprété parbash
ensh
mode. Tandis qu'avecxterm -e myscript with args
,xterm
utiliseraexecvp()
donc le script sera interprété parsh
.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 utilisantexecvp()
) 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é parcsh
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
estbash
-only, vous voudrez donc vous assurer que le script est interprété parbash
(et éviter cette.sh
extension trompeuse ). Soit vous connaissez le chemin de l'bash
exécutable et utilisez:Ou vous pouvez essayer de vous fier à une
$PATH
recherche de l'bash
exécutable (en supposant qu'ilbash
soit installé) en utilisant:(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.la source
Lorsque vous n'avez pas de ligne
#!
(appelée shebang ), sh est utilisé. Pour vérifier cela, vous pouvez exécuter le script suivant.Sur mon ordinateur, je reçois
même si mon shell par défaut est zsh . Il utilise bash car sur ma machine, la commande sh est implémentée par bash .
la source