Une fonction Bash est un bloc de commandes nommé, réutilisable à l'intérieur du script. Sans fonctions, chaque logique répétée (validation d'argument, affichage d'erreur, transformation de chaîne) doit être dupliquée. Avec des fonctions bien découpées, un script de 200 lignes devient lisible et testable, et les fonctions utilitaires se partagent entre scripts via source.
Ce que vous allez apprendre
Section intitulée « Ce que vous allez apprendre »- Déclarer et appeler une fonction avec et sans le mot-clé
function - Accéder aux arguments d'une fonction via
$1,$2,$@ - Utiliser
localpour éviter de polluer les variables globales - Retourner une valeur par
echocapturé avec$() - Renvoyer un code de sortie utilisable dans un
if - Organiser les fonctions utilitaires dans un fichier séparé et les charger avec
source
Dans quel contexte ?
Section intitulée « Dans quel contexte ? »Les fonctions apparaissent naturellement dès qu'un script dépasse une vingtaine de lignes :
- encapsuler la logique de validation d'un argument dans
verifier_arg()appelée pour chaque paramètre - centraliser la gestion des erreurs dans
erreur()pour ne pas dupliquer leecho >&2; exit 1 - extraire une transformation (récupérer l'extension d'un fichier, normaliser un nom) dans une fonction réutilisable
- partager des fonctions de log (
log_info,log_warn,log_error) entre plusieurs scripts grâce àsource
L'objectif RHCSA « Create simple shell scripts » (EX200, RHEL 10) ne cite pas les fonctions : elles servent à rendre vos scripts lisibles et maintenables, pas à cocher une case de l'examen. Un script d'examen de trente lignes s'en passe très bien ; un script d'exploitation de deux cents lignes, non.
Déclarer et appeler une fonction
Section intitulée « Déclarer et appeler une fonction »Deux syntaxes existent, et elles ne sont pas portables de la même façon. La forme nom() { ... } est celle de POSIX : Bash, dash et tous les shells la comprennent. Le mot-clé function est propre à Bash et ksh : mesuré sur Debian 13, dash le refuse avec Syntax error: "}" unexpected.
# Syntaxe POSIX, recommandéebonjour() { echo "Bonjour depuis une fonction !"}
# Syntaxe avec le mot-clé function (Bash et ksh, refusée par dash)function bonjour { echo "Bonjour depuis une fonction !"}L'appel s'écrit comme une commande, sans parenthèses :
bonjour# Bonjour depuis une fonction !Une fonction doit être déclarée avant son premier appel : contrairement à certains langages, Bash exécute les fichiers de haut en bas, sans passe préalable. Appelée trop tôt, elle provoque un command not found.
Arguments d'une fonction
Section intitulée « Arguments d'une fonction »Les fonctions reçoivent leurs arguments comme un script : $1, $2… $@, $#. Ce sont les paramètres de la fonction, distincts de ceux du script : les modifier dans la fonction (avec shift ou set --) ne touche pas aux arguments du script (mesuré).
saluer() { local prenom="$1" local titre="${2:-M.}" # valeur par défaut si $2 absent echo "Bonjour $titre $prenom"}
saluer "Alice" # Bonjour M. Alicesaluer "Bob" "Dr." # Bonjour Dr. Bobshift, décaler les arguments
Section intitulée « shift, décaler les arguments »shift supprime $1 et décale tous les suivants d'un rang. Utile pour traiter le premier argument comme un titre, puis itérer sur les suivants :
afficher_liste() { local titre="$1" shift # $2 devient $1, $3 devient $2... echo "$titre :" for item in "$@"; do echo " - $item" done}
afficher_liste "Services" "nginx" "postgresql" "redis"# Services :# - nginx# - postgresql# - redisVariables locales avec local
Section intitulée « Variables locales avec local »Sans local, une affectation dans une fonction modifie la variable globale du même nom, un effet de bord difficile à suivre :
nom="global"
modifier() { nom="modifié dans la fonction" # modifie la variable globale !}
modifierecho "$nom" # modifié dans la fonctionAvec local, la portée est limitée à la fonction, et la globale reste intacte après l'appel :
nom="global"
modifier() { local nom="local à la fonction" echo "Dans la fonction : $nom"}
modifierecho "Après : $nom"# Dans la fonction : local à la fonction# Après : globalRègle : déclarez toutes les variables internes d'une fonction avec local, c'est la forme défensive par défaut.
Retourner une valeur
Section intitulée « Retourner une valeur »Par echo + $()
Section intitulée « Par echo + $() »Bash ne dispose pas de return valeur_textuelle. La méthode standard consiste à echo la valeur dans la fonction, puis à la capturer avec $() à l'appel :
extension() { local fichier="$1" echo "${fichier##*.}"}
ext=$(extension "rapport.tar.gz")echo "Extension : $ext"# Extension : gzdate_snapshot() { date '+%Y%m%d_%H%M%S'}
sauvegarde="/backup/app_$(date_snapshot).tar.gz"echo "$sauvegarde"# /backup/app_20260410_080812.tar.gzContrepartie à connaître : $( ) exécute la fonction dans un sous-shell. Une variable globale qu'elle modifie au passage est donc perdue au retour. Mesuré : avec f() { N=5; echo val; }, l'appel r=$(f) laisse N à 0, alors qu'un appel direct f le passe à 5.
N=0f() { N=5; echo "val"; }
r=$(f)echo "N après \$(f) : $N" # N après $(f) : 0f > /dev/nullecho "N après f : $N" # N après f : 5Par code de retour, pour les conditions
Section intitulée « Par code de retour, pour les conditions »return sans argument retourne le code de la dernière commande. return N retourne le code N (0 = succès, 1–255 = erreur). À ne pas confondre avec exit, qui arrête le script entier même appelé dans une fonction (mesuré : f() { exit 3; }; f termine le script avec le code 3).
fichier_lisible() { local f="$1" [[ -r "$f" ]] # retourne 0 si lisible, 1 sinon}
if fichier_lisible "/etc/passwd"; then echo "/etc/passwd : lisible"fi
if ! fichier_lisible "/etc/shadow"; then echo "/etc/shadow : non lisible (normal en user)"fi# /etc/passwd : lisible# /etc/shadow : non lisible (normal en user)Ce patron est très utilisé pour valider des préconditions avant d'agir, sur une seule ligne lisible :
service_actif() { systemctl is-active --quiet "$1"}
service_actif "nginx" || { echo "nginx arrêté, abandon." >&2; exit 1; }Retourner plusieurs valeurs
Section intitulée « Retourner plusieurs valeurs »Bash ne supporte pas les retours multiples. La convention consiste à affecter des variables globales avec un préfixe explicite, en appelant la fonction directement, pas dans $( ) :
calculer() { local a="$1" local b="$2" RESULT_SOMME=$((a + b)) RESULT_PRODUIT=$((a * b))}
calculer 6 7echo "Somme=$RESULT_SOMME, Produit=$RESULT_PRODUIT"# Somme=13, Produit=42Fonctions utilitaires courantes
Section intitulée « Fonctions utilitaires courantes »Fonction d'erreur
Section intitulée « Fonction d'erreur »Une fonction erreur() centralisée évite de dupliquer echo >&2; exit 1 partout, et garantit que tous les messages partent sur la sortie d'erreur avec le même format :
erreur() { echo "ERREUR : $*" >&2 exit 1}
verifier_arg() { local val="$1" local nom="$2" [[ -n "$val" ]] || erreur "L'argument '$nom' est obligatoire."}
verifier_arg "monapp" "APP_NAME" # OKverifier_arg "" "APP_NAME" # ERREUR : L'argument 'APP_NAME' est obligatoire.$* dans erreur() concatène tous les arguments en une seule chaîne, pratique pour un message d'erreur composé.
Fonctions de log
Section intitulée « Fonctions de log »Trois fonctions d'une ligne suffisent à horodater les messages et à séparer les niveaux : l'information part sur la sortie standard, les avertissements et erreurs sur la sortie d'erreur.
log_info() { echo "[INFO] $(date '+%H:%M:%S') $*"; }log_warn() { echo "[WARN] $(date '+%H:%M:%S') $*" >&2; }log_error() { echo "[ERROR] $(date '+%H:%M:%S') $*" >&2; }
log_info "Démarrage de l'application"log_warn "Configuration par défaut utilisée"log_error "Connexion à la base échouée"# [INFO] 08:08:12 Démarrage de l'application# [WARN] 08:08:12 Configuration par défaut utilisée# [ERROR] 08:08:12 Connexion à la base échouéeBibliothèque partagée avec source
Section intitulée « Bibliothèque partagée avec source »source (ou .) charge et exécute un fichier dans le contexte du shell courant : ses fonctions deviennent disponibles immédiatement, comme si elles étaient écrites dans le script :
erreur() { echo "ERREUR : $*" >&2; exit 1; }log_info() { echo "[INFO] $(date '+%H:%M:%S') $*"; }log_error() { echo "[ERROR] $(date '+%H:%M:%S') $*" >&2; }#!/bin/bashset -euo pipefail
# shellcheck source=lib/utils.shsource "$(dirname "$0")/lib/utils.sh"
log_info "Script démarré"[[ $# -ge 1 ]] || erreur "Usage : $(basename "$0") <argument>"log_info "Argument : $1"$(dirname "$0") pointe vers le répertoire du script, la bibliothèque est donc trouvée même si le script est appelé depuis un autre répertoire, par cron par exemple. Le commentaire # shellcheck source= aide l'analyse statique à suivre le fichier.
Dépannage
Section intitulée « Dépannage »Les erreurs de fonctions tiennent presque toutes à la portée : ce que la fonction voit, ce qu'elle modifie, et ce qui survit à l'appel. Les cas ci-dessous ont été reproduits sur Bash 5.2.
| Symptôme | Cause probable | Solution |
|---|---|---|
| Variable non modifiée après l'appel | Déclarée avec local dans la fonction | Utiliser une variable globale avec un préfixe explicite (RESULT_) |
command not found à l'appel | Fonction déclarée après l'appel | Déplacer la déclaration avant le premier appel |
$(fonction) retourne vide | La fonction utilise return au lieu de echo | echo la valeur ; return ne sert qu'aux codes de sortie |
| Une globale modifiée par la fonction reste inchangée | Fonction appelée dans $( ), donc dans un sous-shell | Appeler la fonction directement, ou retourner la valeur par echo |
| Le script entier s'arrête dans une fonction | exit au lieu de return | return N ne sort que de la fonction |
source lib.sh : No such file | Chemin relatif au répertoire courant | Utiliser source "$(dirname "$0")/lib.sh" |
À retenir
Section intitulée « À retenir »- La syntaxe
nom_fonction() { ... }est la forme POSIX, recommandée en Bash. - Déclarez toujours les variables internes avec
local, c'est la forme défensive par défaut. - Pour retourner une valeur textuelle :
echodans la fonction +$(fonction)à l'appel, sachant que$( )lance un sous-shell. - Pour retourner un booléen : la fonction se termine par une commande ou un test
[[ ]], utilisable directement dansif. sourcecharge une bibliothèque de fonctions dans le shell courant, le chemin doit être basé sur$(dirname "$0").
Contrôle de connaissances
Section intitulée « Contrôle de connaissances »Vérifiez que l'essentiel de ce guide est acquis. Les questions portent uniquement sur ce qui vient d'être expliqué ici.
Contrôle de connaissances
Validez vos connaissances avec ce quiz interactif
Informations
- Le chronomètre démarre au clic sur Démarrer
- Questions à choix multiples, vrai/faux et réponses courtes
- Vous pouvez naviguer entre les questions
- Les résultats détaillés sont affichés à la fin
Lance le quiz et démarre le chronomètre
Vérification
(0/0)Score par domaine
Un domaine regroupe plusieurs guides et reçoit plusieurs questions : son score est plus fiable qu'un score par thème, qui porte souvent sur une seule question.
Bilan
Points forts
Aucun sujet réussi à 80 % sur au moins deux questions pour l’instant.
Points faibles
Aucun sujet sous le seuil de réussite.
À faire ensuite
Des indices pour retenter votre chance ?
Continuer le cours : Déboguer un script Bash
Nouveau quiz complet avec des questions aléatoires
Retravailler uniquement les questions ratées
Retour à la liste des certifications