Comment combiner commander shell et scripts bash pour aller plus loin ?

Le commander shell et les scripts bash partagent le même interpréteur, mais leur combinaison ouvre des possibilités bien au-delà de la simple saisie de commandes au terminal. Un script bash n’est pas un programme autonome coupé de l’environnement système : il orchestre des commandes, capture leurs résultats, réagit à leurs codes de sortie et peut s’enchaîner avec d’autres scripts. C’est cette articulation qui distingue l’automatisation basique de l’automatisation robuste.

Codes de sortie et enchaînement conditionnel de commandes shell

Chaque commande shell renvoie un code de retour après son exécution. Par convention, 0 signifie succès, toute valeur non nulle indique une erreur. Ce mécanisme est la colonne vertébrale des enchaînements conditionnels.

L’opérateur && exécute la commande suivante uniquement si la précédente a réussi. L’opérateur || fait l’inverse : il ne s’exécute que si la commande précédente a échoué. Le point-virgule ; enchaîne sans condition, quel que soit le code de sortie.

Dans un script bash, récupérer ce code via $? permet de brancher explicitement la logique :

  • Vérification immédiate après une commande critique : tester $? juste après une écriture de fichier ou une connexion réseau évite de propager silencieusement une erreur dans le reste du script.
  • Combinaison avec set -euo pipefail : cette directive en tête de script arrête l’exécution dès qu’une commande échoue, qu’une variable est indéfinie ou qu’une commande dans un pipeline renvoie une erreur. Elle ne remplace pas la vérification explicite pour les opérations critiques, car -e a des exceptions selon le contexte d’appel, notamment dans les blocs conditionnels.
  • Fonctions avec valeur de retour : une fonction bash peut renvoyer un code de sortie avec return N, ce qui permet de l’utiliser directement dans un test conditionnel à l’appel.

Variables et substitution de commande dans les scripts bash

Les variables bash stockent des chaînes de caractères. La substitution de commande, notée $(commande), capture la sortie standard d’une commande dans une variable. C’est l’un des mécanismes les plus utilisés pour connecter des commandes entre elles à l’intérieur d’un script.

Quelques points de comportement à connaître avant d’aller plus loin. Une variable non protégée par des guillemets doubles peut être découpée par le shell si elle contient des espaces ou des caractères spéciaux. Toujours protéger les variables avec « $variable » est une règle qui évite une large classe de bogues silencieux.

La portée des variables mérite attention : par défaut, une variable définie dans un script n’est pas exportée vers les sous-shells. Il faut utiliser export pour la rendre disponible aux commandes enfants. À l’inverse, une variable définie dans un sous-shell (lancé entre parenthèses) n’est pas visible dans le shell parent.

Administratrice système Linux debout devant un grand écran affichant des commandes shell dans un open space technologique moderne

Boucles et conditions pour automatiser des traitements sur fichiers

La majorité des scripts bash d’administration traitent des listes de fichiers, des lignes d’un fichier de configuration ou des résultats de commandes. Les boucles for et while couvrent ces deux cas.

Une boucle for fichier in /chemin/*.log itère sur chaque fichier correspondant au motif. Une boucle while read ligne traite un fichier ligne par ligne, ce qui est adapté aux sorties de commandes longues redirigées via un pipe. Dans ce dernier cas, la boucle reçoit les données sur l’entrée standard, ce qui permet de combiner grep, awk ou sed avec le traitement bash sans créer de fichier temporaire.

Les conditions avec [[ … ]] (double crochet, spécifique à bash) offrent plus de souplesse que les crochets simples : comparaisons de chaînes sans risque de découpage, tests sur l’existence d’un fichier, expressions régulières avec =~. Cette syntaxe n’est pas disponible dans sh ou dash : un script utilisant [[ ]] doit déclarer #!/bin/bash comme shebang, pas #!/bin/sh.

Fonctions bash et réutilisation de code entre scripts

Une fonction bash regroupe un bloc de commandes sous un nom, appelle ce bloc avec des arguments positionnels ($1, $2…) et renvoie un code de sortie. Elle n’a pas de type de retour au sens d’un langage compilé : pour qu’une fonction « retourne » une valeur textuelle, la convention est d’utiliser echo à l’intérieur et de capturer le résultat par substitution de commande à l’appel.

Pour partager des fonctions entre plusieurs scripts, le mécanisme habituel est le sourcing : source ./fonctions.sh ou . ./fonctions.sh charge les définitions dans le contexte courant sans créer de sous-shell. C’est la façon standard d’organiser un projet bash en plusieurs fichiers.

ShellCheck et tests automatisés : deux angles que les guides ignorent souvent

ShellCheck est un analyseur statique qui examine un script sans l’exécuter. Il détecte les guillemets manquants, les variables non protégées, les opérateurs non portables entre bash et sh, et signale les constructions dont le comportement est ambigu. Intégré à une chaîne d’intégration continue, il remplit un rôle de revue systématique plutôt que de débogage ponctuel.

Bats (Bash Automated Testing System) est un framework de tests automatisés pour bash. Il permet d’écrire des tests qui vérifient qu’une commande ou un script produit la sortie attendue et renvoie le bon code de sortie. Bats détecte les régressions lorsqu’un script évolue, ce que ni bash -x ni ShellCheck ne font : ces deux outils analysent le code, pas le comportement à l’exécution face à des données réelles.

La combinaison des deux couvre des niveaux d’analyse complémentaires : ShellCheck repère les erreurs de syntaxe et de style avant l’exécution, Bats valide le comportement observable après. Pour un projet bash maintenu dans le temps, l’absence de tests rend chaque modification risquée, en particulier sur des scripts qui manipulent des fichiers système ou des droits utilisateur.

Un point sur la compatibilité sh/bash reste ouvert selon les environnements : dans certains systèmes embarqués ou images Docker minimales, /bin/sh pointe vers dash ou BusyBox, pas vers bash. Tester explicitement avec dash permet de détecter les incompatibilités si la portabilité est un objectif. Si le script utilise des tableaux bash ou [[ ]], la portabilité vers sh n’est de toute façon pas atteignable sans réécriture.

Ne manquez rien de l'actualité

Défi en ligne : ce jeu de piste sur Google Street View va vous rendre accro

Bienvenue dans l'ère des jeux en ligne où l'exploration virtuelle vous transporte dans des aventures captivantes. Aujourd'hui, nous plongeons dans un jeu de piste…

Personnalisation des commandes du clavier pour les joueurs de Battlefield 5

Dans l'univers des jeux vidéo, Battlefield 5 se distingue par son réalisme et son intensité. Pour maximiser vos performances dans ce jeu de tir…