Script shell fonctionne bien sans ligne de shebang? Pourquoi?

J’écrivais un script shell simple et j’ai découvert que mon script shell ne nécessitait pas de ligne shebang

#!/bin/sh 

Si je donne des permissions d’exécution à mon script et que je l’exécute en utilisant ./myscript.sh . Ça marche bien

J’utilise shell bash et /bin/sh pointe vers bash .

 lrwxrwxrwx 1 root root /bin/sh -> bash 

Je sais que la ligne shebang est utilisée pour dire à shell quel interpréteur utiliser pour le rest du script.

Si je manque la ligne de shebang dans perl, donne des droits d’exécution et lance ./myscript.pl , cela ne fonctionne pas.

Qu’est-ce qui se passe réellement ici? Si j’utilise ./ , quand la ligne de shebang est-elle réellement nécessaire?

La ligne shebang est nécessaire dans le fichier et seulement si elle est destinée à être exécutée en tant qu’exécutable (par opposition à l’invocation de sh file.sh Il n’est pas vraiment nécessaire par script, c’est au système de savoir comment trouver un interpréteur.

EDIT : Désolé pour avoir mal interprété la question. Si la ligne shebang est manquante ou non reconnue, /bin/sh est utilisé. Mais je préfère être explicite à propos de l’interprète.

Notez que ce comportement n’est pas universel, IIRC, seule une fonction de famille exec* fait (pour ne pas mentionner différentes plates-formes), ce qui constitue une autre raison d’être explicite ici.

Le shell parent, où vous avez entré ./myscript.sh , a d’abord essayé de l’ execve c’est-à-dire où la ligne shebang prendrait effet si elle était présente. Lorsque cela fonctionne, le parent n’a pas conscience de la différence entre les scripts et les ELF car le kernel s’en occupe.

L’ execve échoué, donc une ancienne fonctionnalité de compatibilité Unix, antérieure à l’existence des lignes de shebang, a été activée. Il a deviné qu’un fichier qui a une autorisation d’exécution mais n’est pas reconnu comme un fichier exécutable valide par le kernel doit être un script shell.

Habituellement, le shell parent suppose que le script est écrit pour le même shell (des shells de type Bourne minimaux exécutent le script avec /bin/sh , bash l’exécute en tant que sous-processus bash), csh effectue des devinages plus complexes en fonction du premier caractère. car il est antérieur à shebang et qu’il devait coexister avec Bourne shell).

Vous avez besoin d’une ligne de shebang quand vous savez que ces suppositions seront fausses (par exemple avec le shebang est #!/usr/bin/perl ), ou lorsque vous ne faites pas confiance aux devinettes pour travailler de manière cohérente, ou lorsque le script doit être exécutable par un processus parent qui n’est pas un shell lui-même.

La norme POSIX (Single UNIX Specification 4) n’est pas utile:

Si la première ligne d’un fichier de commandes shell commence par les caractères “#!” , les résultats ne sont pas spécifiés.

Donc, la norme implique que si vous n’avez pas de #! alors il devrait exécuter un shell POSIX. Mais les shells modernes ne sont pas conformes à POSIX. L’ancien Korn Shell 88 (ksh88) exécutait le shell Bourne (proche d’un shell POSIX) sans aucun #! ligne, mais ksh93 brise cela, de même que Bash. Avec ksh93 et ​​Bash, ils exécutent leur propre shell si non #! la ligne est présente.

Malgré l’opinion populaire, les obus Bash et Korn diffèrent. Lorsque vous écrivez un script shell, vous ne pouvez jamais être sûr de quel shell vous allez être exécuté, ni même s’il sera exécuté à partir d’un autre shell (la plupart des langages de programmation peuvent exécuter d’autres programmes). À la minute où vous utilisez quelque chose en dehors de la syntaxe Bourne / POSIX, vous serez ébranlé.

Toujours utiliser un #! ligne, ne laissez pas au hasard.