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

- 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
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-demoVérifiez ensuite où vous vous trouvez avec
pwd. Vous aurez ainsi un espace simple pour refaire les exercices plusieurs fois.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.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.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.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.txtsans risque de mauvaise interprétation.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
/tmpcomme valeur de remplacement. C’est un moyen simple de rendre une commande plus tolérante à l’absence d’entrée.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 variabledossiergarde ensuite cette valeur. C’est pratique quand un script a besoin d’un paramètre par défaut réutilisé plus loin.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.
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
.txtest retiré de la fin, et le résultat affiché estrapport. Cette famille d’expansions permet souvent d’éviter un appel inutile à un outil externe.Comparer deux sorties avec <(...)

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 àdiffquelque 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.Filtrer une entrée avec <(...) dans une commande simple
Utilisez la même idée avec
catpour 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.
Dupliquer une sortie avec >(...)

Testez maintenant la redirection vers un processus avec
tee:printf '%s ' un deux trois | tee >(wc -l) >/dev/nullteeenvoie ici le flux vers le processuswc -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.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.Combiner variables et substitution sans perdre les espaces

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.
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_fichiern’est pas défini. Vous rendez explicite le comportement attendu au lieu de laisser Bash propager une chaîne vide sans avertissement.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.