# Le secret de la première ligne des scripts Linux : Que signifient `#!/usr/bin/env bash` et `#!/bin/bash` ? Lorsque vous rédigez un script sous Linux, il est courant d'ajouter cette ligne en haut : ```bash #!/usr/bin/env bash ``` ou encore ```bash #!/bin/bash ``` À première vue, cela ressemble à un simple commentaire... Mais quelle est la **véritable nature** de cette ligne ? Et surtout, quelles sont les différences entre ces deux formes ? Dans cet article, nous allons décortiquer cette ligne mystérieuse pour comprendre son rôle et savoir quand utiliser l'une ou l'autre. --- ## 1. Ce n'est pas un commentaire : Qu'est-ce que le shebang ? {#sec-9f8041c620ba} Cette ligne, commençant par `#!`, est appelée **shebang**. ```bash #!/bin/bash ``` Du point de vue du shell, puisque cela commence par `#`, cela ressemble clairement à un « commentaire ». Cependant, pour le **système d'exploitation (le noyau)**, il ne s'agit pas d'un commentaire, mais d'une directive qui indique : > « Où trouver le **programme interpréteur** pour exécuter ce script. » Autrement dit : * `#!/bin/bash` → « Exécute ce fichier avec `/bin/bash`. » * `#!/usr/bin/env bash` → « Trouve l'interpréteur `bash` via `env` et exécute ce fichier avec celui-ci. » --- ## 2. Comment le noyau exécute-t-il un script ? {#sec-33d96b8d8f01} En simplifiant le processus d'exécution, cela se déroule comme suit : 1. L'utilisateur exécute un script avec les droits d'exécution. ```bash chmod +x script.sh ./script.sh ``` 2. Le noyau lit `script.sh`. 3. Il vérifie si les **deux premiers caractères** du fichier sont `#!`. 4. Si c'est le cas, il interprète le reste de la ligne comme : * « Le chemin de l'interpréteur + ses arguments » * Et exécute ce programme en lui **passant le chemin du fichier script comme argument**. Par exemple, si la première ligne de `script.sh` est : ```bash #!/bin/bash ``` Le noyau effectue en réalité une action que l'on peut conceptualiser ainsi : ```bash /bin/bash script.sh ``` Autrement dit, le noyau exécute une action similaire à celle que nous ferions en tapant directement `bash script.sh`. > Note : > Il **ne doit pas y avoir d'espace** avant `#!/`. > Le **premier caractère** du fichier doit être `#`, et le second `!`. --- ## 3. Signification et caractéristiques de `#!/bin/bash` {#sec-52f9e12dce0d} C'est la forme la plus couramment rencontrée. ```bash #!/bin/bash ``` ### Signification {#sec-a97a945792d4} * « Ce script est un **script bash**, et `bash` se trouve dans `/bin/bash`. » * Le noyau exécutera toujours `/bin/bash` pour ce script. ### Avantages {#sec-a01bf708579d} * **Clarté** : L'utilisation systématique de `/bin/bash` rend prévisible la version de bash qui sera employée. * **Performance/Simplicité** : Le script est exécuté directement, sans passer par `env`, ce qui élimine le processus de recherche du chemin. * Sur de nombreuses distributions Linux, `/bin/bash` est considéré comme un « emplacement standard » de facto. ### Inconvénients {#sec-89064c01f1ea} * **Manque de portabilité** * Sur certains systèmes, bash peut se trouver à un autre emplacement, comme `/usr/bin/bash` ou `/usr/local/bin/bash`. * Certains systèmes peuvent ne pas avoir bash du tout, et ne disposer que de `/bin/sh`. * Les chemins peuvent différer, notamment sur **macOS, les systèmes basés sur BSD, NixOS et certains environnements de conteneurs**. --- ## 4. Signification et caractéristiques de `#!/usr/bin/env bash` {#sec-97cd6f02458d} C'est la forme la plus couramment rencontrée dans les scripts modernes. ```bash #!/usr/bin/env bash ``` L'élément clé ici est `/usr/bin/env`. * `env` est un utilitaire qui aide à « définir/vérifier les variables d'environnement + rechercher des programmes dans le PATH ». * On peut considérer que le noyau exécute réellement ceci : ```bash /usr/bin/env bash script.sh ``` * `env` examine la variable d'environnement `PATH` du système pour trouver et exécuter l'exécutable `bash`. ### Avantages {#sec-9bc2075d78b3} 1. **Portabilité (fonctionne bien dans divers environnements)** * Que bash se trouve dans `/bin/bash`, `/usr/bin/bash`, ou `/usr/local/bin/bash`, * `env` le trouvera tant qu'il est correctement enregistré dans le PATH. 2. **Utilisation de la version de bash adaptée à l'environnement utilisateur** * Si l'utilisateur a personnalisé son `PATH` pour utiliser une version spécifique de bash en priorité, c'est cette version qui sera utilisée. 3. **Utilisation du même modèle pour Python et d'autres langages** ```python #!/usr/bin/env python3 ``` ### Inconvénients {#sec-0ba7b1b3de08} 1. **Nécessite la présence de /usr/bin/env** * Bien qu'il soit présent sur presque tous les systèmes Unix/Linux modernes, il pourrait manquer dans des environnements très spécifiques. 2. **Un interpréteur différent peut être sélectionné en fonction du PATH** * Si la configuration du PATH est corrompue ou si une version inattendue de bash est trouvée en premier, une version non désirée pourrait être exécutée. 3. **Nécessite une attention particulière en matière de sécurité** * Dans des environnements très sensibles à la sécurité, la préférence peut aller aux **chemins absolus** plutôt qu'à la recherche d'interpréteurs basée sur le PATH. --- ## 5. Comparaison des deux approches {#sec-f327651f1197} Voici un tableau comparatif simplifié. | Critère | #!/bin/bash | #!/usr/bin/env bash | | ---------------------------------- | ------------------------- | ------------------------------------ | | Méthode de spécification de l'interpréteur | Chemin absolu fixe | Recherche via `PATH` | | Portabilité (compatibilité multi-systèmes) | Faible (casse si le chemin diffère) | Élevée (OK si bash est dans le PATH) | | Quelle version de bash est utilisée | Toujours `/bin/bash` | Le premier `bash` trouvé dans le PATH | | Garantie de la version souhaitée | Relativement facile | Peut varier selon l'état du PATH | | Sécurité/Contrôle | Plus fort (chemin fixe) | Légèrement plus souple (dépend du PATH) | | Tendance générale actuelle | Style relativement ancien | Plus souvent recommandé de nos jours | --- ## 6. Quand utiliser quelle approche ? {#sec-a9bac1ab9ba4} Pour répondre à la question « En fin de compte, que dois-je utiliser ? », voici une ventilation par situation. ### 1) Scripts personnels / de développement d'équipe (environnements de développement courants) {#sec-fc5216000f29} * Généralement, la recommandation est la suivante : ```bash #!/usr/bin/env bash ``` * Raisons : * L'emplacement de bash peut varier sur les serveurs gérés par les développeurs, les environnements locaux, les environnements CI, etc. * La recherche et l'exécution basées sur le PATH sont plus flexibles, et les outils/scripts modernes préfèrent cette approche. ### 2) Scripts d'exploitation adaptés à un environnement serveur spécifique {#sec-204ac6ba64d3} * Par exemple, si tous les serveurs de l'entreprise ont bash installé en commun dans `/bin/bash`, * Et si l'environnement serveur est relativement fixe : ```bash #!/bin/bash ``` * Raisons : * Assure l'utilisation du même interpréteur en permanence. * Réduit les comportements inattendus dus aux modifications du PATH. ### 3) Si vous souhaitez une portabilité maximale ? {#sec-6ef1b12d728e} * Si vous envisagez un environnement où « bash pourrait ne pas être installé du tout », il faut d'abord se demander si un script dépendant de bash est la bonne approche. * Si possible, écrivez en `sh` : ```bash #!/bin/sh ``` * Cette approche fonctionnera dans un éventail beaucoup plus large d'environnements. Cependant, il ne faut pas utiliser la syntaxe propre à bash (`[[ ]]`, tableaux, traitement étendu des chaînes de caractères, etc.). --- ## 7. Conseils pratiques pour l'utilisation de `#!/usr/bin/env bash` {#sec-e5a739214684} ### 1) Méthode d'exécution du script {#sec-83e5cc5b64a5} Pour utiliser correctement le shebang, il est préférable de ne pas faire ceci : ```bash bash script.sh # ← L'exécution de cette manière rend le shebang presque inutile ``` Mais plutôt de l'utiliser comme suit : ```bash chmod +x script.sh # Accorder les droits d'exécution ./script.sh # Exécuter directement ``` C'est ainsi que le noyau lira le `#!` et utilisera l'interpréteur spécifié. ### 2) Vérification du passage des arguments {#sec-90ca3c9235bf} Prenons l'exemple de `test.sh` créé comme suit : ```bash #!/usr/bin/env bash echo "Interpréteur: $0" echo "Arguments: $@" ``` Exécution : ```bash chmod +x test.sh ./test.sh hello world ``` Sortie : ```text Interpréteur: ./test.sh Arguments: hello world ``` Ici, `$0` représente le « chemin du fichier script lui-même », et il suffit de se rappeler que le noyau l'exécute en réalité comme `/usr/bin/env bash test.sh hello world`. --- ## 8. Foire aux questions {#sec-99b0325925f3} ### J'ai déjà vu des scripts écrits sans shebang. Est-ce normal ? {#sec-751234a46d29} * C'est exact, le shebang **n'est pas toujours nécessaire**. * Si vous exécutez le script en spécifiant directement l'interpréteur, comme ci-dessous, le shebang n'est pas nécessaire. Même s'il est présent, il sera ignoré. ```bash bash myscript.sh python3 myscript.py ``` * Cependant, si vous souhaitez l'exécuter comme suit, il est absolument indispensable : ```bash ./myscript.sh ./myscript.py ``` * En particulier, pour les scripts destinés à être utilisés comme des « outils » par d'autres, le **shebang est pratiquement obligatoire**. ### « J'ai vu `#!/bin/env` fonctionner aussi, pas seulement `#!/usr/bin/env` ? » {#sec-6de89a827da4} * Sur certains systèmes, `/bin/env` peut exister. * Cependant, `/usr/bin/env` est généralement l'emplacement standard le plus universel. * À moins d'une raison spécifique, il est plus sûr d'utiliser `#!/usr/bin/env …`. --- ## 9. Résumé {#sec-971578a5a9d1} * `#!/usr/bin/env bash` ou `#!/bin/bash` ne sont **pas des commentaires, mais des directives qui indiquent au noyau avec quel interpréteur exécuter le script**. * `#!/bin/bash` * Utilise toujours `/bin/bash` → **Prévisible dans un environnement fixe, mais potentiellement moins portable**. * `#!/usr/bin/env bash` * Cherche bash dans le `PATH` → **Plus flexible et portable, mais dépend de l'état du PATH**. * Pour la rédaction de scripts « modernes » dans des environnements de développement/déploiement courants, il est recommandé d'utiliser **`#!/usr/bin/env bash` par défaut**. ![image du shebang dans un script Linux](https://blog.mikihands.com/media/editor_temp/6/692ed85d-0eb6-4fd1-ab7a-22a2d189175d.png "Image du principe de fonctionnement du shebang")