web-dev-qa-db-fra.com

Devrais-je utiliser un Shebang avec des scripts Bash?

J'utilise Bash

$ echo $Shell
/bin/bash

et depuis environ un an, j’ai arrêté d’utiliser Shebangs avec mes scripts Bash. Puis-je bénéficier de l’utilisation de #!/bin/sh ou #!/bin/bash?

Mise à jour: Dans certaines situations, un fichier est uniquement traité comme un script avec le Shebang, exemple.

$ cat foo.sh
ls

$ cat bar.sh
#!/bin/sh
ls

$ file foo.sh bar.sh
foo.sh: ASCII text
bar.sh: POSIX Shell script, ASCII text executable
27
Steven Penny

Sur les systèmes de type UNIX, vous devez toujours démarrer les scripts avec une ligne Shebang. L'appel système execve (responsable du démarrage des programmes) s'appuie sur un exécutable ayant un en-tête d'exécutable ou une ligne Shebang.

À partir de la page de manuel execve de FreeBSD :

 The execve() system call transforms the calling process into a new
 process.  The new process is constructed from an ordinary file, whose
 name is pointed to by path, called the new process file.
 [...]

 This file is
 either an executable object file, or a file of data for an interpreter.

 [...]

 An interpreter file begins with a line of the form:

       #! interpreter [arg]

 When an interpreter file is execve'd, the system actually execve's the
 specified interpreter.  If the optional arg is specified, it becomes the
 first argument to the interpreter, and the name of the originally
 execve'd file becomes the second argument

De même depuis la page de manuel Linux :

execve () exécute le programme désigné par nom de fichier. le nom de fichier doit être soit un exécutable binaire, soit un script commençant par une ligne du fichier forme:

#! interpreter [optional-arg]

En fait, si un fichier ne possède pas le bon "nombre magique" dans son en-tête (comme un en-tête ELF ou #!), execve sera échec avec l'erreur ENOEXEC (toujours à partir de la page de manuel execve de FreeBSD):

[ENOEXEC] Le nouveau fichier de processus a l'accès approprié permission, mais a un nombre magique invalide dans son entête.


Si le fichier dispose d'autorisations exécutables, mais pas de ligne Shebang mais semble être un fichier texte, le comportement dépend du Shell dans lequel vous exécutez l'application.

La plupart des shells semblent démarrer une nouvelle instance et alimenter le fichier, voir ci-dessous.

Comme il n’existe aucune garantie que le script ait été écrit pour ce shell, cela peut fonctionner ou échouer de façon spectaculaire.

De tcsh (1) :

   On  systems which do not understand the `#!' script interpreter conven‐
   tion the Shell may be compiled to emulate it;  see  the  version  Shell
   variable.  If so, the Shell checks the first line of the file to see if
   it is of the form `#!interpreter arg ...'.  If it is, the Shell  starts
   interpreter  with  the  given args and feeds the file to it on standard
   input.

De FreeBSD's sh (1) :

If the program is not a normal executable file (i.e., if it
     does not begin with the “magic number” whose ASCII representation is
     “#!”, resulting in an ENOEXEC return value from execve(2)) but appears to
     be a text file, the Shell will run a new instance of sh to interpret it.

De bash (1):

   If this execution fails because the file is not in  executable  format,
   and  the file is not a directory, it is assumed to be a Shell script, a
   file containing Shell commands.  A subshell is spawned to  execute  it.

Vous ne pouvez pas toujours dépendre de l'emplacement d'un programme non standard comme bash. J'ai vu bash dans /usr/bin, /usr/local/bin, /opt/fsf/bin et /opt/gnu/bin pour en nommer quelques-uns.

C'est donc généralement une bonne idée d'utiliser env;

#!/usr/bin/env bash

Si vous voulez que votre script soit portable, utilisez sh au lieu de bash.

#!/bin/sh

Tandis que des standards tels que POSIX ne ne garantissent pas les chemins absolus des utilitaires standard, la plupart des systèmes de type UNIX semblent avoir sh dans /bin et env dans /usr/bin.

36
Roland Smith

Les scripts doivent toujours commencer par une ligne Shebang. Si un script ne commence pas par cela, il peut alors être exécuté par le shell actuel. Mais cela signifie que si quelqu'un qui utilise votre script exécute un shell différent de vous, le script peut se comporter différemment. En outre, cela signifie que le script ne peut pas être exécuté directement à partir d'un programme (par exemple, l'appel système C exec() ou find -exec), il doit être exécuté à partir d'un shell.

13
Barmar

Vous pourriez être intéressé par une description préliminaire par Dennis M Ritchie (dmr) qui a inventé le #!:

De Uucp Jeu 10 Janvier 01:37:58 1980 

.> De dmr jeu 10 jan. 04:25:49 1980 à distance de la recherche

Le système a été modifié de sorte que si un fichier en cours d'exécution commence par les caractères magiques #! , le reste de la On entend par ligne le nom d'un interprète pour l'exécution fichier. Auparavant (et en fait encore), Shell a effectué une grande partie de ce travail; il s’exécutait automatiquement sur un fichier texte en mode exécutable lorsque le nom du fichier texte a été saisi en tant que commande. Mettre la facilité dans le système offre les avantages suivants.

1) Les scripts Shell ressemblent davantage à de vrais fichiers exécutables, car ils peuvent être le sujet de 'exec.'

2) Si vous faites un 'ps' pendant l'exécution d'une telle commande, son vrai nom apparaît au lieu de «sh». De même, la comptabilité est effectuée sur la base de le vrai nom.

3) Les scripts shell peuvent être set-user-ID.

4) Il est plus simple d'avoir des coquilles de rechange disponibles. par exemple. si tu veux Berkeley csh, il n’est pas question de savoir à quel Shell appartient interpréter un fichier.

5) Cela permettra aux autres interprètes de s’intégrer plus facilement.

Pour profiter de cette magnifique opportunité, mettez

   #! /bin/sh

dans la marge gauche de la première ligne de vos scripts Shell. Blancs après ! vont bien. Utilisez un chemin d'accès complet (aucune recherche n'est effectuée). Au moment, toute la ligne est limitée à 16 caractères, mais cette limite sera soulevé.

J'espère que cela t'aides

3
jrjc
  • Si vous écrivez des scripts bash, c’est-à-dire des scripts non portables contenant des bashismes, vous devez continuer à utiliser le #!/bin/bash Shebang pour vous assurer que le bon interpréteur est utilisé. Vous ne devez pas remplacer Shebang par #!/bin/sh car bash s'exécutera en mode POSIX, de sorte que certains de vos scripts pourraient se comporter différemment.

  • Si vous écrivez des scripts portable, c’est-à-dire qui utilisent uniquement les utilitaires POSIX et leurs options prises en charge, vous pouvez continuer à utiliser #!/bin/sh sur votre système (c’est-à-dire un où /bin/sh est un shell POSIX).

  • Si vous écrivez des scripts POSIX strictement conformes à distribuer sur diverses plates-formes et que vous êtes certain qu'ils ne seront lancés que depuis un système conforme à POSIX, vous pourriez et devriez probablement supprimer Shebang comme indiqué dans le standard POSIX:

Dans l'état actuel des choses, une application strictement conforme ne doit pas utiliser "#!" comme les deux premiers caractères du fichier.

La raison en est que la norme POSIX n'impose pas à /bin/sh d'être le shell conforme à POSIX. Il n'existe donc aucun moyen portable de spécifier son chemin dans un Shebang. Dans ce troisième cas, pour pouvoir utiliser la syntaxe 'find-exec' sur des systèmes incapables d'exécuter un script shebangless toujours exécutable, vous pouvez simplement spécifier l'interpréteur dans la commande find elle-même, par exemple:

find /tmp -name "*.foo" -exec sh -c 'myscript "$@"' sh {} + 

Ici, comme sh est spécifié sans chemin, le shell POSIX sera exécuté.

3
jlliagre

L'en-tête est utile car il spécifie quel shell utiliser lors de l'exécution du script. Par exemple, #!/bin/zsh changerait le shell en zsh au lieu de bash, où vous pouvez utiliser différentes commandes.

Par exemple, cette page spécifie ce qui suit:

En utilisant #!/Bin/sh, le Bourne Shell par défaut dans la plupart des variantes commerciales de UNIX, rend le script portable sur des machines autres que Linux, bien que vous sacrifier des fonctionnalités spécifiques à Bash ...

1
pyrrhic

$ Shell et #!/Bin/bash ou #!/Bin/sh sont différents. 

Pour commencer, #!/Bin/sh est un lien symbolique vers/bin/bash sur la plupart des systèmes Linux (sous Ubuntu, il s'agit maintenant de/bin/dash)

Mais que ce soit avec/bin/sh ou/bin/bash:

Bash et sh sont deux coquilles différentes. Fondamentalement bash est sh, avec plus fonctionnalités et une meilleure syntaxe. La plupart des commandes fonctionnent de la même manière, mais elles sont différent.

Supposons simplement que si vous écrivez un script bash, restez sur/bin/bash et non/sh car des problèmes peuvent survenir.

$ Shell ne reflète pas nécessairement le Shell en cours d'exécution . Au lieu de cela, $ Shell est le shell préféré de l'utilisateur, qui est généralement le un ensemble dans/etc/passwd. Si vous démarrez un autre shell après la journalisation Dans, vous ne pouvez pas nécessairement vous attendre à ce que $ Shell corresponde au Shell actuel plus.

Ceci est le mien par exemple, mais il pourrait aussi s'agir de/root:/bin/dash ou/root:/bin/sh, selon le shell que vous avez entré dans passwd. Donc, pour éviter tout problème, gardez le fichier passwd dans/bin/bash, puis utilisez $ Shell contre #!/Bin/bash n’aurait pas autant d’importance.

root@kali:~/Desktop# cat /etc/passwd
root:x:0:0:root:/root:/bin/bash

Sources: http://Shebang.brandonmintern.com/bourne-is-not-bash-or-read-echo-and-backslash/https: //unix.stackexchange. com/questions/43499/différence-entre-echo-Shell-et-which-bashhttp://man.cx/shhttp://man.cx/ bash

0
Chirality

En plus de ce que les autres ont dit, Shebang permet également la coloration syntaxique dans certains éditeurs de texte, par exemple vim.

0
Konrad Höffner