Débutant

Maîtriser substitutions Bash et variables robustes

Apprenez à utiliser $( ), <( ), >( ) et l’expansion de variables Bash pour écrire des commandes plus robustes et plus lisibles.

Maîtriser substitutions Bash et variables robustes
Difficulté
Intermédiaire

La ligne de commande devient beaucoup plus fiable quand vous savez réinjecter proprement une sortie, protéger vos variables et raccorder des flux sans fichiers temporaires. Ce tutoriel vous fait pratiquer ces gestes avec Bash, pas à pas, sur des exemples simples.

Vous allez manipuler trois substitutions utiles — $(...), <(...) et >(...) — puis renforcer vos commandes grâce à l’expansion de variables. L’objectif n’est pas d’apprendre “plus de syntaxe”, mais d’éviter des commandes fragiles quand un nom contient des espaces, quand une variable est vide, ou quand vous devez brancher une commande dans une autre.

Prérequis

Ce tutoriel suppose que vous utilisez Bash, pas un shell générique. Vérifiez-le avec echo "$BASH_VERSION" : si une version s’affiche, vous êtes bien dans Bash.

Travaillez de préférence dans un répertoire de test pour éviter toute confusion avec vos fichiers personnels. Les exemples ci-dessous utilisent seulement des commandes courantes comme echo, printf, cat, diff, sort, grep et tee.

Matériel nécessaire

  • Un terminal Bash
  • Un répertoire de test où saisir les commandes
  • Les commandes courantes de base (echo, printf, cat, diff, sort, grep, tee)

Étapes

  1. Créer un répertoire de test et s’y placer

    Commencez dans un dossier isolé pour exécuter les exemples sans mélanger vos fichiers. Saisissez :

    mkdir -p bash-substitutions-demo
    cd bash-substitutions-demo

    Vérifiez ensuite où vous vous trouvez avec pwd. Vous aurez ainsi un espace simple pour refaire les exercices plusieurs fois.

  2. Capturer une sortie avec $(...)

    Testez d’abord la substitution de commande la plus fréquente. Saisissez :

    fichier="rapport.txt"
    echo "Le fichier courant est : $(printf '%s' "$fichier")"

    La commande à l’intérieur de $(...) est exécutée, puis sa sortie est insérée à cet endroit. Vous obtenez une seule commande lisible, sans passer par une variable intermédiaire supplémentaire.

  3. Remplacer les syntaxes anciennes par une forme lisible

    Comparez maintenant deux écritures pour le même résultat :

    echo "Aujourd'hui : $(date +%Y-%m-%d)"
    # forme ancienne à éviter dans un nouveau script :
    # echo "Aujourd'hui : `date +%Y-%m-%d`"

    La première forme se lit mieux et s’imbrique plus facilement. Quand une commande contient elle-même des quotes ou d’autres substitutions, $(...) reste nettement plus pratique.

  4. Protéger une variable avec "${VAR}"

    Créez une variable contenant des espaces, puis affichez-la correctement :

    nom="mon rapport final.txt"
    printf '%s
    ' "$nom"
    printf '%s
    ' "${nom}"

    Les deux dernières lignes fonctionnent ici, mais la forme "${nom}" devient très utile quand le nom de variable touche d’autres caractères. Elle évite les ambiguïtés et garde la valeur comme un seul argument.

  5. Délimiter une variable avant du texte adjacent

    Observez la différence entre une variable accolée à du texte et une variable délimitée :

    base="rapport"
    printf '%s
    ' "${base}.txt"
    # évitez l'ambiguïté de formes comme :
    # printf '%s
    ' "$base.txt"

    Avec les accolades, Bash comprend exactement où le nom de variable s’arrête. Vous obtenez ici rapport.txt sans risque de mauvaise interprétation.

  6. Prévoir une valeur par défaut avec ${VAR:-valeur}

    Simulez une variable absente ou vide, puis fournissez une valeur de secours :

    unset cible
    echo "Destination : ${cible:-/tmp}"
    
    cible=""
    echo "Destination : ${cible:-/tmp}"

    Dans les deux cas, Bash affiche /tmp comme valeur de remplacement. C’est un moyen simple de rendre une commande plus tolérante à l’absence d’entrée.

  7. Initialiser une variable seulement si nécessaire avec ${VAR:=valeur}

    Testez maintenant une variante qui fixe aussi la variable :

    unset dossier
    printf '%s
    ' "${dossier:=archives}"
    printf '%s
    ' "$dossier"

    La première ligne affichée vaut archives, et la variable dossier garde ensuite cette valeur. C’est pratique quand un script a besoin d’un paramètre par défaut réutilisé plus loin.

  8. Refuser une variable absente avec ${VAR:?message}

    Ajoutez une vérification explicite quand une variable est indispensable :

    unset source
    printf '%s
    ' "${source:?La variable source est requise}"

    Bash signale une erreur au lieu de poursuivre silencieusement avec une valeur vide. Ce garde-fou est très utile dans un script qui dépend d’un chemin ou d’un nom de fichier fourni par l’utilisateur.

  9. Raccourcir une chaîne avec une expansion simple

    Exercez-vous sur une manipulation de texte sans commande externe :

    fichier="rapport.txt"
    printf '%s
    ' "${fichier%.txt}"
    

    Le suffixe .txt est retiré de la fin, et le résultat affiché est rapport. Cette famille d’expansions permet souvent d’éviter un appel inutile à un outil externe.

  10. Comparer deux sorties avec <(...)

    Ordinateur portable sur un bureau sobre avec une fenêtre de terminal divisée en deux zones côte à côte pour comparer deux sorties, une main près du pavé tactile, lumière naturelle.

    Passez maintenant à la substitution de processus en branchant deux commandes dans diff :

    diff <(printf '%s
    ' pomme banane cerise | sort) \
         <(printf '%s
    ' cerise banane pomme | sort)

    Ici, chaque <(...) fournit à diff quelque chose qu’il peut lire comme une entrée de type fichier. Après tri, les deux contenus sont identiques, donc la comparaison ne signale pas de différence.

  11. Filtrer une entrée avec <(...) dans une commande simple

    Utilisez la même idée avec cat pour visualiser un flux préparé à la volée :

    cat <(printf '%s
    ' alpha beta gamma | grep 'a')

    La commande affiche les lignes produites après filtrage. L’intérêt n’est pas de remplacer un pipe simple, mais de voir comment fournir une entrée “lisible comme un fichier” à une commande qui l’accepte.

  12. Dupliquer une sortie avec >(...)

    Vue rapprochée d’un ordinateur portable pendant une commande de terminal où une sortie est dupliquée vers deux destinations, avec les mains en train de taper.

    Testez maintenant la redirection vers un processus avec tee :

    printf '%s
    ' un deux trois | tee >(wc -l) >/dev/null

    tee envoie ici le flux vers le processus wc -l, qui compte les lignes reçues. La redirection vers /dev/null évite simplement de réafficher le contenu original dans le terminal pendant cet essai.

  13. Comparer un pipe et une substitution pour choisir la bonne forme

    Placez côte à côte deux écritures valides :

    printf '%s
    ' alpha beta gamma | grep 'a'
    cat <(printf '%s
    ' alpha beta gamma | grep 'a')

    Les deux affichent le même résultat ici, mais ne répondent pas au même besoin. Le pipe est idéal pour faire passer une sortie vers l’entrée standard de la commande suivante ; <(...) devient intéressant quand la commande suivante attend un ou plusieurs arguments lisibles comme des fichiers.

  14. Combiner variables et substitution sans perdre les espaces

    Mains en train de taper sur un ordinateur portable avec une commande de terminal qui combine une variable et une substitution de commande, dans un cadrage sobre et net.

    Créez une variable avec des espaces, puis réinjectez-la proprement dans une commande :

    motif="rapport final"
    printf '%s
    ' "$(printf '%s
    ' "$motif")"

    L’exemple est volontairement simple pour montrer le réflexe important : chaque expansion susceptible de contenir des espaces reste entre guillemets. Cette discipline vous protège quand le texte vient d’un paramètre utilisateur ou d’une autre commande.

  15. Assembler une commande plus robuste avec valeur par défaut

    Mettez ensemble une variable, une valeur de secours et une substitution de commande :

    unset nom_fichier
    echo "Fichier cible : $(printf '%s' "${nom_fichier:-sortie.txt}")"

    La commande continue à fonctionner même si nom_fichier n’est pas défini. Vous rendez explicite le comportement attendu au lieu de laisser Bash propager une chaîne vide sans avertissement.

  16. Vérifier vos expansions avant de les intégrer dans un script

    Avant d’écrire une commande plus longue, testez chaque morceau isolément dans le terminal. Par exemple :

    nom="rapport final.txt"
    printf '%s
    ' "${nom%.txt}"
    printf '%s
    ' "${dossier:-archives}"
    printf '%s
    ' "$(printf '%s' "$nom")"

    Cette habitude permet de repérer rapidement une variable vide, un guillemet oublié ou une expansion qui ne produit pas le texte attendu. Vous assemblez ensuite la version finale avec moins d’essais hasardeux.

Erreurs fréquentes & dépannage

L’erreur la plus fréquente consiste à laisser une variable non quotée, par exemple $nom au lieu de "$nom" ou "${nom}". Dès qu’une valeur contient des espaces, votre commande peut recevoir plusieurs arguments au lieu d’un seul.

Une autre confusion courante est d’utiliser <(...) alors qu’un pipe simple suffit. Gardez | pour transmettre un flux à l’entrée standard, et utilisez la substitution de processus surtout quand une commande attend des arguments lisibles comme des fichiers.

Évitez aussi d’employer une valeur vide sans l’avoir prévue. Les formes ${VAR:-valeur} et ${VAR:?message} servent précisément à rendre ce comportement explicite.

Astuces & pour aller plus loin

Adoptez une convention simple : variables toujours entre guillemets, accolades dès qu’une variable touche d’autres caractères, et formes de secours visibles au plus près des paramètres importants. Cette régularité réduit fortement les erreurs de saisie et les surprises à la relecture.

Quand vous hésitez entre plusieurs écritures, partez de la plus simple. Un pipe reste excellent pour un enchaînement direct, tandis que $(...), <(...) et >(...) deviennent vraiment utiles quand ils clarifient la structure de la commande.

Questions fréquentes

Quelle différence entre $(...) et <(...)?

$(...) insère la sortie d’une commande comme texte dans la ligne de commande. <(...) fournit à une autre commande une entrée qu’elle peut lire comme un fichier.

Dois-je toujours écrire les variables comme ${VAR} ?

Ce n’est pas obligatoire dans tous les cas, mais c’est souvent préférable dès qu’une variable touche du texte adjacent ou quand vous voulez une écriture uniforme. Dans tous les cas, gardez les guillemets quand la valeur doit rester un seul argument.

À quoi sert ${VAR:-valeur} ?

Cette forme fournit valeur si VAR est absente ou vide. Elle permet d’éviter qu’une commande parte avec un paramètre vide non prévu.

Quand utiliser >(...)?

Utilisez >(...) quand vous voulez envoyer une sortie vers un processus, par exemple avec tee pour traiter un flux en parallèle. Ce n’est pas une alternative générale à toutes les redirections classiques.

La substitution de processus fonctionne-t-elle partout ?

Ce tutoriel vise Bash. Si vous écrivez un script destiné à un autre shell, vérifiez d’abord que la syntaxe voulue y est bien prise en charge.

Conclusion

Vous avez pratiqué les gestes essentiels pour rendre vos commandes Bash plus robustes : capturer une sortie avec $(...), fournir des entrées ou des sorties à des processus avec <(...) et >(...), puis sécuriser vos paramètres grâce à des expansions de variables bien choisies.

Le gain principal ne vient pas d’une “syntaxe avancée”, mais d’un meilleur contrôle des cas réels : espaces dans les noms, variables vides, comparaisons de flux et commandes plus lisibles. Rejouez les exemples dans votre dossier de test, puis appliquez ces réflexes à vos propres scripts Bash.

Commentaires· Aucun commentaire pour l'instant

Soyez le premier à réagir.

Laisser un commentaire