Aller au contenu
Administration Linux medium

Fonctions Bash : déclarer, appeler, retourner

11 min de lecture

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 peuvent être partagées entre scripts via source.

  • Déclarer et appeler une fonction avec et sans le mot-clé function
  • Accéder aux arguments d’une fonction via $1, $2, $@
  • Utiliser local pour éviter de polluer les variables globales
  • Retourner une valeur par echo capturé avec $()
  • Renvoyer un code de sortie utilisable dans un if
  • Organiser les fonctions utilitaires dans un fichier séparé et les charger avec source

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 le echo >&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

En préparation RHCSA, les fonctions sont souvent testées dans des exercices de refactoring de script : vous devrez encapsuler une portion de code existante en fonction et l’appeler.

Deux syntaxes équivalentes :

Fenêtre de terminal
# Syntaxe recommandée en Bash
bonjour() {
echo "Bonjour depuis une fonction !"
}
# Syntaxe avec le mot-clé function (POSIX)
function bonjour {
echo "Bonjour depuis une fonction !"
}

L’appel s’écrit comme une commande — sans parenthèses :

Fenêtre de terminal
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.

Les fonctions reçoivent leurs arguments comme un script : $1, $2$@, $#.

Fenêtre de terminal
saluer() {
local prenom="$1"
local titre="${2:-M.}" # valeur par défaut si $2 absent
echo "Bonjour $titre $prenom"
}
saluer "Alice" # Bonjour M. Alice
saluer "Bob" "Dr." # Bonjour Dr. Bob

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 :

Fenêtre de terminal
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
# - redis

Sans local, une affectation dans une fonction modifie la variable globale :

Fenêtre de terminal
nom="global"
modifier() {
nom="modifié dans la fonction" # modifie la variable globale !
}
modifier
echo "$nom" # modifié dans la fonction

Avec local, la portée est limitée à la fonction :

Fenêtre de terminal
nom="global"
modifier() {
local nom="local à la fonction"
echo "Dans la fonction : $nom"
}
modifier
echo "Après : $nom"
# Dans la fonction : local à la fonction
# Après : global

Règle : déclarez toutes les variables internes d’une fonction avec local — c’est la forme défensive par défaut.

Bash ne dispose pas de return valeur_textuelle. La méthode standard consiste à echo la valeur dans la fonction, puis à la capturer avec $() :

Fenêtre de terminal
extension() {
local fichier="$1"
echo "${fichier##*.}"
}
ext=$(extension "rapport.tar.gz")
echo "Extension : $ext"
# Extension : gz
Fenêtre de terminal
date_snapshot() {
date '+%Y%m%d_%H%M%S'
}
sauvegarde="/backup/app_$(date_snapshot).tar.gz"
echo "$sauvegarde"
# /backup/app_20260410_080812.tar.gz

return sans argument retourne le code de la dernière commande. return N retourne le code N (0 = succès, 1–255 = erreur).

Fenêtre de terminal
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 :

Fenêtre de terminal
service_actif() {
systemctl is-active --quiet "$1"
}
service_actif "nginx" || { echo "nginx arrêté — abandon." >&2; exit 1; }

Bash ne supporte pas les retours multiples. La convention consiste à affecter des variables globales avec un préfixe explicite :

Fenêtre de terminal
calculer() {
local a="$1"
local b="$2"
RESULT_SOMME=$((a + b))
RESULT_PRODUIT=$((a * b))
}
calculer 6 7
echo "Somme=$RESULT_SOMME, Produit=$RESULT_PRODUIT"
# Somme=13, Produit=42

Une fonction erreur() centralisée évite de dupliquer echo >&2; exit 1 partout :

Fenêtre de terminal
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" # OK
verifier_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é.

Fenêtre de terminal
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ée

source (ou .) charge et exécute un fichier dans le contexte du shell courant — ses fonctions deviennent disponibles immédiatement :

lib/utils.sh
erreur() { echo "ERREUR : $*" >&2; exit 1; }
log_info() { echo "[INFO] $(date '+%H:%M:%S') $*"; }
log_error() { echo "[ERROR] $(date '+%H:%M:%S') $*" >&2; }
mon_script.sh
#!/bin/bash
set -euo pipefail
# shellcheck source=lib/utils.sh
source "$(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 courant — la bibliothèque est trouvée même si le script est appelé depuis un autre répertoire.

SymptômeCause probableSolution
Variable non modifiée après l’appelDéclarée avec local dans la fonctionUtiliser une variable globale avec un préfixe explicite (RESULT_)
command not found à l’appelFonction déclarée après l’appelDéplacer la déclaration avant le premier appel
$(fonction) retourne videLa fonction utilise return au lieu de echoecho la valeur ; return ne sert qu’aux codes de sortie
Modifications de $1 dans la fonction affectent le scriptPas de locallocal arg="$1" puis utiliser $arg
source lib.sh : No such fileChemin relatif au répertoire courantUtiliser source "$(dirname "$0")/lib.sh"
  • La syntaxe nom_fonction() { ... } est la forme 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 : echo dans la fonction + $(fonction) à l’appel.
  • Pour retourner un booléen : la fonction se termine par une commande ou un test [[ ]] — utilisable directement dans if.
  • source charge une bibliothèque de fonctions dans le shell courant — le chemin doit être basé sur $(dirname "$0").

Ce site vous est utile ?

Sachez que moins de 1% des lecteurs soutiennent ce site.

Je maintiens +700 guides gratuits, sans pub ni tracing. Aujourd'hui, ce site ne couvre même pas mes frais d'hébergement, d'électricité, de matériel, de logiciels, mais surtout de cafés.

Un soutien régulier, même symbolique, m'aide à garder ces ressources gratuites et à continuer de produire des guides de qualité. Merci pour votre appui.

Abonnez-vous et suivez mon actualité DevSecOps sur LinkedIn