glossaire-linux

Scripting bash

Les briques de base pour écrire des scripts shell solides : variables, substitutions, tests, structures de contrôle, fonctions et options de robustesse. Les exemples ciblent Bash 4+ ; quand une construction n'est pas POSIX, c'est signalé.

Variables

Une variable shell n'a pas de type : tout est chaîne. Les règles à connaître concernent la déclaration (sans espaces), l'expansion (avec quotes pour la sécurité) et les nombreux modificateurs ${...}.

$VAR

Déclarer, lire et exporter une variable

Une affectation s'écrit sans espaces autour du =. Pour lire la valeur on préfixe par $, et pour les cas ambigus (concaténation avec du texte) on entoure le nom d'accolades.

Syntaxe

nom=valeur                    # affectation simple
nom="texte avec espaces"      # toujours quoter si espaces ou caracteres speciaux
echo "$nom"                   # lecture
echo "${nom}_suffixe"         # accolades obligatoires pour deslimiter le nom

export NOM=valeur             # variable d'environnement (heritee par les enfants)
local nom=valeur              # portee limitee a la fonction
readonly nom=valeur           # interdit toute modification ulterieure
$ nom="Alice"
echo "Bonjour $nom"
Bonjour Alice
Affectation puis lecture. Les " double-quotes permettent l'expansion de $nom.
$ base=/var/log
echo "${base}_archive"
/var/log_archive
Sans accolades, $base_archive serait interprété comme la variable $base_archive.
$ export PATH="$HOME/bin:$PATH"
Ajoute ~/bin en tête du PATH et propage aux processus enfants.
Toujours quoter à l'expansion. echo $fichier casse si fichier contient un espace ou un joker. Préférer echo "$fichier". La règle d'or : quote everything unless you have a reason not to.

Voir aussi : ${VAR:-def} $(cmd)

${VAR:-def}

Valeurs par défaut et manipulation de chaînes

Les accolades autour d'un nom de variable acceptent des modificateurs très puissants : valeur par défaut si vide, longueur, sous-chaîne, suppression de préfixe ou suffixe, remplacement.

Valeur par défaut et obligatoire

${var:-def}Renvoie def si var est vide ou non définie. Ne modifie pas var.
${var:=def}Idem, mais affecte aussi def à var.
${var:?msg}Affiche msg sur stderr et termine le script si var est vide.
${var:+x}Renvoie x si var est définie et non vide, sinon vide. L'inverse de :-.

Longueur, sous-chaîne, manipulation

${#var}Longueur en caractères.
${var:offset:length}Sous-chaîne (offset 0-indexé). length est optionnel.
${var#prefix}Supprime le plus court préfixe matchant. ## pour le plus long.
${var%suffix}Supprime le plus court suffixe matchant. %% pour le plus long.
${var/pat/rep}Remplace la première occurrence. ${var//pat/rep} pour toutes.
${var^^}Met en MAJUSCULES. ${var,,} en minuscules. (Bash 4+)
$ port=${PORT:-8080}
echo "Ecoute sur $port"
Ecoute sur 8080
Utilise PORT si elle est définie et non vide ; sinon prend 8080. Le deux-points de ${PORT:-8080} traite également la chaîne vide comme une absence.
$ fichier=/var/log/syslog.gz
echo "${fichier##*/}"
echo "${fichier%.gz}"
syslog.gz
/var/log/syslog
##*/ retire tout jusqu'au dernier / (équivalent basename). %.gz retire l'extension.
$ chemin="src/main/app.js"
echo "${chemin//\//.}"
src.main.app.js
Remplace tous les / par des .. Le \ protège le slash dans le motif.

Voir aussi : $VAR grep

Substitution de commande

Insérer le résultat d'une commande au milieu d'une autre, ou faire un calcul entier sans appeler de programme externe.

$(cmd)

Capturer la sortie d'une commande dans une expression

$(cmd) remplace la substitution par la sortie standard de la commande en retirant tous les sauts de ligne finaux. Quoter l’expansion préserve les espaces et sauts de ligne internes. Les backticks sont une ancienne syntaxe, moins pratique à imbriquer.

Syntaxe

resultat=$(commande arg1 arg2)
echo "Maintenant : $(date +%H:%M)"
fichiers=$(ls *.log)            # eviter — utiliser un tableau plutot
imbric=$(echo $(uname -r))      # parfaitement lisible
$ aujourdhui=$(date +%Y-%m-%d)
mkdir "backup-$aujourdhui"
Capture la date pour la réutiliser dans un nom de répertoire.
$ nb_lignes=$(wc -l < access.log)
echo "Total : $nb_lignes lignes"
Capture un compte. < access.log évite que wc imprime le nom du fichier.
Toujours quoter le résultat. cd $(dirname "$0") casse si le chemin contient un espace. Toujours cd "$(dirname "$0")" avec les quotes autour de $().

Voir aussi : $((expr)) $VAR

$((expr))

Évaluation arithmétique entière

Calcul entier sans expr ni bc. Les variables sont utilisables sans $ à l'intérieur. Ne gère que des entiers ; pour des décimales, utiliser bc -l ou awk.

Opérateurs

+ - * / %Arithmétique de base. Division entière.
**Puissance.
== != < <= > >=Comparaisons (renvoient 1 ou 0).
&& ||Logique.
++ --Incrément / décrément (avant ou après).
$ a=7
b=3
echo "$((a + b))  $((a * b))  $((a / b))  $((a % b))"
10  21  2  1
Calcul entier sur deux variables. À l'intérieur de $(()), les variables s'utilisent sans $ (le contexte arithmétique sait que a est une variable). On affiche les quatre opérations : addition, multiplication, division entière (pas 2.33), modulo (le reste de 7÷3).
$ i=0
while (( i < 5 )); do echo $i; i=$((i + 1)); done
Compteur classique. (( i < 5 )) est une condition arithmétique : la boucle continue tant qu'elle est vraie. i=$((i + 1)) incrémente i sans déclencher set -e lorsque la valeur initiale vaut zéro, contrairement à ((i++)). Plus lisible que la version POSIX [ "$i" -lt 5 ] dès qu'on manipule des entiers.

Voir aussi : $(cmd) [[ ]]

Tests

Évaluer une condition pour if, while ou en ligne avec && / ||. Deux constructions au choix : la forme POSIX [ ... ] universelle, ou la forme bash [[ ... ]] plus sûre et plus expressive.

[ ... ]

Test POSIX (alias de la commande test)

[ est généralement un builtin du shell ; un exécutable externe existe aussi. Il reprend les tests de test mais exige un argument final ]. Il renvoie 0 si le test est vrai, 1 sinon et un autre statut en cas d’erreur de syntaxe. Les espaces séparant les arguments sont obligatoires.

Conditions sur les fichiers

-e fichierExiste ; suit les liens symboliques, donc faux pour un lien cassé. -L teste le lien lui-même.
-f fichierest un fichier régulier.
-d fichierest un répertoire.
-L fichierest un lien symbolique.
-r / -w / -xlisible / modifiable / exécutable.
-s fichierexiste et est non vide.
fichier1 -nt fichier2Teste si fichier1 est plus récent que fichier2 dans Bash et plusieurs autres shells. Vérifier les opérateurs disponibles si le script doit cibler d’anciennes implémentations de sh.

Comparaisons de chaînes et d'entiers

"$a" = "$b"égalité de chaînes (POSIX). != pour différent.
-z "$a"chaîne vide. -n pour non vide.
"$a" -eq "$b"égalité numérique. -ne -lt -le -gt -ge pour les autres.
$ if [ -f "$config" ]; then
    . "$config"
fi
Pattern « charger une config si elle est présente, ignorer sinon ». . (équivalent POSIX de source) exécute le fichier dans le shell courant : les variables qu'il définit deviennent disponibles. Sans le test -f en garde, le script aurait planté si le fichier n'existait pas.
$ [ -z "$nom" ] && nom="anonyme"
Forme courte : si $nom est vide, lui donner une valeur.
Toujours quoter les variables dans [ ... ]. [ -z $var ] casse si $var contient un espace ; [ -z "$var" ] non. [[ ... ]] n'a pas ce piège.

Voir aussi : [[ ]] if

[[ ... ]]

Test étendu Bash : pattern matching et regex

Construction Bash, plus sûre que [ ] : pas de découpage de mots, pas de globbing intempestif, et opérateurs supplémentaires pour le pattern matching et les regex.

Opérateurs en plus de [ ]

"$a" == motifPattern matching (jokers * ? [...]). Le motif n'est pas quoted.
"$a" =~ regexRegex étendue. Captures dans ${BASH_REMATCH[1..N]}.
cond1 && cond2ET (au lieu de -a).
cond1 || cond2OU (au lieu de -o).
$ if [[ "$nom" == *.log ]]; then echo "fichier log"; fi
Pattern matching : équivalent du globbing. Note que *.log n'est pas entre quotes.
$ if [[ "$ip" =~ ^([0-9]+)\.([0-9]+)\.([0-9]+)\.([0-9]+)$ ]]; then
    echo "premier octet : ${BASH_REMATCH[1]}"
fi
Capture quatre groupes de chiffres séparés par des points dans BASH_REMATCH[1] à [4]. Cette regex ne vérifie pas que chaque nombre est compris entre 0 et 255 : elle ne valide donc pas une adresse IPv4 complète. Elle illustre la capture d’un format textuel.

Voir aussi : [ ] if

Structures de contrôle

Les blocs if, for, while, case. Bash utilise un mot-clé de fermeture miroir : fi, done, esac.

if

Branchement conditionnel

if teste une commande (souvent [[ ]] ou [ ]) et s'exécute selon son code de retour : 0 = succès = vrai, ≠ 0 = faux. Le bloc se ferme par fi.

Syntaxe

if condition; then
    instructions
elif autre_condition; then
    instructions
else
    instructions
fi
$ if [[ -f "$fichier" ]]; then
    echo "fichier present"
elif [[ -d "$fichier" ]]; then
    echo "c'est un repertoire"
else
    echo "rien a cet endroit"
fi
Test en cascade : on vérifie d'abord si $fichier est un fichier régulier (-f), sinon on regarde s'il s'agit d'un répertoire (-d). Sans match, on tombe dans le else. elif permet d'enchaîner plusieurs conditions sans imbriquer plusieurs if.
$ command -v docker >/dev/null && echo "docker installe" || echo "docker absent"
Forme inline avec && et ||. Attention : si la branche du && échoue, celle du || s'exécute aussi.

Voir aussi : [[ ]] case

for

Boucler sur une liste

Itère sur les éléments d'une liste (mots séparés par espaces, fichiers issus d'un glob, lignes d'une commande, plage numérique). Bash propose aussi une forme C-like avec trois expressions.

Syntaxe

for var in liste; do
    instructions
done

for ((i=0; i<10; i++)); do      # forme C
    instructions
done
$ for f in *.log; do
    [ -f "$f" ] || continue
    gzip -- "$f"
done
Compresse les fichiers réguliers .log. Le test évite de traiter le motif littéral *.log si aucun fichier ne correspond ; -- protège les noms commençant par un tiret.
$ for i in {1..5}; do echo "tentative $i"; done
{1..5} est une brace expansion : le shell la transforme en 1 2 3 4 5 avant que for ne l'utilise. Variantes utiles : {a..z} pour les lettres, {1..10..2} pour un pas (1, 3, 5, 7, 9), {2024..2026} pour des années. Extension Bash, pas POSIX.
$ while IFS= read -r ligne || [ -n "$ligne" ]; do
    printf 'lu : %s
' "$ligne"
done < fichier.txt
Parcourt les lignes sans découper les espaces ni interpréter les antislashs. Le test après read traite aussi une dernière ligne non terminée par un saut de ligne.
Anti-pattern classique : for f in $(ls) casse sur les noms à espaces et n'apporte rien de plus que for f in *. Toujours for f in * pour les fichiers, jamais via ls.

Voir aussi : while xargs

while

Boucler tant qu'une condition est vraie (et son inverse until)

while cond; do ...; done exécute le bloc tant que cond renvoie 0. until est l'inverse : tant qu'elle renvoie ≠ 0. Couplé à read, c'est l'idiome pour lire un flux ligne par ligne.

$ i=0
while (( i < 3 )); do
    echo "$i"
    i=$((i + 1))
done
0
1
2
Boucle classique avec compteur. (( )) pour évaluer arithmétiquement.
$ while IFS=: read -r user _ uid _ _ home _; do
    [ "$uid" -ge 1000 ] && echo "$user -> $home"
done < /etc/passwd
Parcourt /etc/passwd ligne par ligne. IFS=: dit à read de découper sur :. read -r reçoit les 7 champs (utilisateur, mot de passe, uid, gid, commentaire, home, shell) — on n'utilise que user, uid et home, le _ sert pour les autres. Le filtre [ "$uid" -ge 1000 ] garde les UID supérieurs ou égaux à 1000, un seuil courant mais dépendant de la distribution. Cela peut inclure nobody et des comptes techniques : ce filtre ne garantit pas des comptes humains.
$ until ping -c1 -W1 host >/dev/null 2>&1; do
    sleep 2
done
Boucle d'attente classique pour synchroniser un script sur un service distant. Tant que ping retourne une erreur (hôte injoignable), on dort 2 secondes et on retente. -c1 envoie un seul paquet, -W1 plafonne l'attente à 1 s par essai (au lieu des 5 s par défaut). Utile pour patienter qu'un conteneur Docker ou une VM démarre avant la suite du script.

Voir aussi : for $((expr))

case

Sélecteur multi-branches sur motifs

L'équivalent de switch dans d'autres langages, en plus puissant car les branches sont des motifs glob (*, ?, [abc]) et peuvent être combinées avec |. Plus lisible qu'une cascade d'elif quand on teste la même variable.

Syntaxe

case "$var" in
    motif1)        instructions ;;
    motif2|motif3) instructions ;;
    *)             instructions_par_defaut ;;
esac
$ case "${1:-}" in
    start)   echo "demarrage" ;;
    stop)    echo "arret" ;;
    restart) echo "redemarrage" ;;
    *)       echo "Usage: $0 {start|stop|restart}" >&2; exit 1 ;;
esac
Squelette d'un script type wrapper de service. $1 est le premier argument passé au script. La branche *) attrape tout ce qui ne correspond pas (y compris l'absence d'argument), affiche un message d'usage sur stderr et sort avec le code 1. C'est le pattern à reproduire pour tout script qui prend une commande en argument.
$ case "$fichier" in
    *.tar.gz|*.tgz) tar xzf "$fichier" ;;
    *.tar.bz2)      tar xjf "$fichier" ;;
    *.zip)          unzip "$fichier" ;;
    *)              echo "format inconnu" >&2; exit 1 ;;
esac
Détecte le format d'archive d'après l'extension et appelle la commande de décompression adéquate. Avantage sur une cascade de if [[ ... == *.tar.gz ]] : lecture plus claire et ordre des branches immédiat. Le | liste plusieurs motifs équivalents (*.tar.gz et *.tgz) sur la même branche.

Voir aussi : if [[ ]]

Fonctions

Découper un script en blocs réutilisables. Les fonctions bash n'ont pas de paramètres nommés, juste les variables positionnelles classiques $1, $2, $@.

function

Déclarer et utiliser une fonction

La déclaration nom() { ...; } est POSIX. Le mot-clé function et la commande local sont des extensions prises en charge par Bash, pas des garanties POSIX. "$@" préserve les arguments séparés ; $# donne leur nombre. return N termine la fonction avec un statut, pas une valeur arbitraire.

Syntaxe

nom() {
    local var=valeur            # local : reste dans la fonction
    echo "premier arg : $1"
    echo "tous : $@"
    echo "nombre : $#"
    return 0                    # code de sortie (defaut : celui de la derniere instruction)
}

# Appel
nom arg1 arg2 "arg trois"

Variables positionnelles

$0Nom du script (pas de la fonction).
$1 … $9Arguments. Au-delà : ${10}.
"$@"Tous les arguments comme liste de mots distincts (le bon choix dans 99 % des cas).
"$*"Tous concaténés en une seule chaîne, séparés par le premier caractère d'IFS.
$#Nombre d'arguments.
shift [N]Décale les arguments de N (defaut 1) : $2 devient $1, etc.
$ log() {
    local niveau=$1; shift
    echo "[$(date +%H:%M:%S)] [$niveau] $*"
}
log INFO "demarrage"
log ERROR "echec lecture" "$fichier"
Wrapper de log standard. Le premier argument est le niveau, on le sauvegarde dans niveau puis shift le retire — $@ ne contient plus que le message. $* concatène tous les arguments restants en une seule chaîne séparée par des espaces, donc log ERROR "echec lecture" "$fichier" produit une ligne du genre [16:20:01] [ERROR] echec lecture /etc/passwd.
$ max() {
    (( $1 > $2 )) && echo "$1" || echo "$2"
}
max 10 7
10
Une fonction « renvoie » par echo + capture $(max 10 7). return ne renvoie qu'un code 0–255.
Astuce : toujours déclarer les variables internes avec local. Sans ça elles deviennent globales et peuvent écraser celles de l'appelant.

Voir aussi : $VAR trap

Robustesse

Bash est très permissif par défaut : un script continue après une commande qui échoue, utilise une variable vide comme si de rien n'était, et ignore les erreurs au milieu d'un pipe. Ces options changent ce comportement pour des scripts qui plantent vite et fort plutôt que silencieusement.

set -e

Sortir au premier code d'erreur non nul

Active errexit : provoque la sortie sur certaines erreurs non testées. Ses exceptions dépendent du contexte (conditions, listes logiques, fonctions appelées dans ces contextes, pipelines). Il ne remplace pas une gestion explicite des erreurs ; vérifier le comportement attendu avant de l’activer dans un script existant.

$ #!/usr/bin/env bash
set -e
cd /tmp/build
./configure
make
sudo make install
Si ./configure échoue, make ne sera pas lancé. Sans set -e, le script continuait au risque d'exécuter sudo make install sur un build invalide.
Limites : set -e ne s'applique pas aux commandes en condition de if, while ou until, ni aux commandes non finales des listes cmd1 || cmd2 et cmd1 && cmd2. La dernière commande reste concernée : true && false termine le script sous set -e. Pour autoriser un échec ponctuel : cmd || true.

Voir aussi : set -u pipefail

set -u

Erreur si on lit une variable non définie

Active nounset : référencer une variable jamais affectée provoque une erreur et termine un shell non interactif, même sans set -e. Évite les bugs liés aux fautes de frappe ou aux variables d'environnement absentes.

$ set -u
echo "$NON_DEFINIE"
bash: NON_DEFINIE: unbound variable
Avec set -u, tout accès à une variable jamais affectée fait sortir le script en erreur. Sans cette option, echo "$NON_DEFINIE" aurait silencieusement imprimé une ligne vide — bug classique quand on tape $user au lieu de $User. La détection précoce vaut largement l'obligation d'initialiser les optionnelles avec ${VAR:-}.
Échappatoire propre : pour les variables vraiment optionnelles, utiliser la syntaxe ${VAR:-} qui renvoie une chaîne vide sans déclencher l'erreur.

Voir aussi : set -e ${VAR:-def}

set -o pipefail

Le code de sortie d'un pipe est celui du dernier maillon en échec à droite

Par défaut, cmd1 | cmd2 retourne le code de cmd2. Si cmd1 échoue mais cmd2 réussit, le pipe passe pour un succès. Avec pipefail, le statut du pipeline est celui de la commande la plus à droite dont le code est non nul, ou zéro si toutes réussissent. Par exemple, (exit 7) | (exit 3) renvoie 3. Le tableau Bash PIPESTATUS contient les statuts individuels ; le lire immédiatement après le pipeline.

$ set -o pipefail
curl -fsS http://example.test/data | jq .users
Si curl échoue (DNS, 404), jq recevrait juste un flux vide et renverrait un succès. Avec pipefail, le script voit l'échec de curl.
Combo standard set -euo pipefail combine trois options utiles mais ne constitue pas une garantie de robustesse. Par exemple, un producteur interrompu par head peut renvoyer SIGPIPE et faire échouer le pipeline. Tester les erreurs attendues explicitement ; set -x affiche les commandes après expansion et peut révéler des secrets.

Voir aussi : set -e set -u |

trap

Définir une action à l'arrivée d'un signal ou à la sortie

trap associe une action à un signal ou à un événement du shell. EXIT s’exécute lors de la sortie normale du shell et des erreurs qui le font sortir. Ne pas supposer qu’il couvre tous les signaux : installer aussi les gestionnaires INT, TERM et HUP nécessaires. SIGKILL et SIGSTOP ne peuvent pas être interceptés.

Syntaxe

trap 'instruction' SIGNAL [SIGNAL...]
trap -        SIGNAL    # restaurer le comportement par defaut
trap ''       SIGNAL    # ignorer le signal
$ tmp=$(mktemp -d) || exit 1
trap 'rm -rf -- "$tmp"' EXIT
trap 'exit 130' INT
trap 'exit 143' TERM
trap 'exit 129' HUP
# ... le script utilise $tmp ...
mktemp crée un répertoire temporaire et son échec est traité avant de continuer. EXIT le nettoie à la sortie ; les gestionnaires INT, TERM et HUP provoquent une sortie avec le statut conventionnel adapté. SIGKILL, un crash système ou une coupure peuvent empêcher le nettoyage.
$ trap 'echo "interrompu" >&2; exit 130' INT
trap 'echo "termine" >&2; exit 143' TERM
Installe deux gestionnaires distincts : 130 = 128 + SIGINT (2), 143 = 128 + SIGTERM (15). Les deux affichent un message puis terminent le script.

Voir aussi : kill set -e

I/O et arguments

Lire l'entrée utilisateur, formater la sortie de manière prévisible, et parser les arguments d'un script en respectant les conventions POSIX.

read

Lire une ligne depuis stdin (ou afficher un prompt)

Builtin shell, toujours à utiliser avec -r (sinon les backslashes sont interprétés). Coupe sur $IFS par défaut (espaces/tabs/\n) : passer IFS= pour préserver les espaces.

Options

-rMode brut (raw) : ne pas interpréter les \. À mettre presque toujours.
-p "PROMPT"Affiche un prompt avant de lire.
-sMode silencieux (caractères non échoés) — pour les mots de passe.
-t SECTimeout en secondes : sort en erreur si rien n'arrive.
-n NLit au maximum N caractères, ou moins si le délimiteur de ligne est rencontré ; -N N a un comportement différent dans Bash.
-a TABLit dans un tableau, en découpant sur $IFS.
$ read -rp "Continuer ? [o/N] " rep
[[ "$rep" =~ ^[oOyY]$ ]] || exit 0
Confirmation interactive avec valeur par défaut sûre (vide = abandon). -p intègre le prompt dans read au lieu d'un echo -n séparé.
$ read -rsp "Mot de passe : " pass
echo
echo "Mot de passe saisi : ${#pass} caractères"
-s n'affiche pas ce que l'utilisateur tape. Le echo seul rajoute le saut de ligne manquant. Pattern standard pour collecter une passphrase sans la stocker dans ~/.bash_history.
$ while IFS=: read -r user _ uid _ _ home _; do
    [ "$uid" -ge 1000 ] && echo "$user $home"
done < /etc/passwd
Lecture ligne-à-ligne avec champs nommés. IFS=: coupe sur :, les _ servent pour les colonnes ignorées. Pattern POSIX pour traverser un fichier structuré.
$ if read -rt 5 -p "Démarrer ? " rep; then
    echo "Réponse : $rep"
else
    echo "Timeout — démarrage par défaut"
fi
read échoue sur expiration, fin de fichier ou erreur ; la branche else regroupe ici ces cas. Le message Timeout est donc une simplification à adapter si l’on doit les distinguer.

Voir aussi : printf getopts while

printf

Formatage portable et prévisible (style printf C)

Plus prévisible et plus portable qu'echo : pas d'arguments interprétés différemment selon l'OS, contrôle exact des largeurs, des alignements et des conversions. À privilégier dès qu'on dépasse echo "$x".

Spécificateurs courants

%sChaîne.
%d / %iEntier.
%f / %.2fFlottant (avec précision).
%xHexadécimal.
%-20sAligné à gauche, largeur 20.
%05dPadding avec zéros à gauche.
%qÉchappé pour ré-injection en shell.
%(FORMAT)TDate au format strftime (Bash 4.2+).
$ printf '%-15s %s\n' "Nom :" "Alice"
printf '%-15s %s\n' "Email :" "alice@example.test"
Nom :           Alice
Email :         alice@example.test
Tableau aligné. %-15s = chaîne alignée à gauche dans 15 caractères. Plus simple qu'printf '%-15s %s\n' … + column.
$ printf '%(%Y-%m-%dT%H:%M:%S%z)T\n' -1
2026-05-07T14:32:11+0200
Date ISO 8601 sans appeler date. -1 = maintenant. Plus rapide quand on en a besoin dans une boucle (pas de fork-exec à chaque fois).
$ printf 'cd %q && ./run.sh\n' "$dossier"
%q échappe la chaîne pour qu'elle puisse être ré-évaluée par le shell sans risque. Si $dossier contient des espaces ou des caractères spéciaux, ils sont protégés correctement — utile pour générer un script à exécuter ailleurs.
$ printf '%s\n' ligne1 ligne2 ligne3
ligne1
ligne2
ligne3
Quand le format est plus court que la liste d'arguments, il est réutilisé. Idiomatique pour générer N lignes à partir d'un tableau.

Voir aussi : read echo date

getopts

Parser les options courtes d'un script (POSIX)

Builtin POSIX (à ne pas confondre avec getopt, qui est un binaire externe et accepte les options longues). Conçu pour les flags de type -v, -h, -f FILE. Le format de la chaîne d'options est : une lettre = un flag sans argument, une lettre suivie de : = flag avec argument obligatoire.

Variables peuplées par getopts

$opt (ou le nom choisi)La lettre de l'option en cours, ou ? si inconnue.
$OPTARGL'argument fourni à l'option (pour les options en :).
$OPTINDIndex de l'argument à traiter ensuite. Utile pour shift $((OPTIND-1)) à la fin.
$ #!/usr/bin/env bash
verbose=0
output=""
while getopts ":vho:" opt; do
    case "$opt" in
        v) verbose=1 ;;
        h) echo "Usage: $(basename "$0") [-v] [-h] [-o FICHIER] args..."; exit 0 ;;
        o) output="$OPTARG" ;;
        \?) echo "Option inconnue : -$OPTARG" >&2; exit 1 ;;
        :) echo "Option -$OPTARG demande un argument" >&2; exit 1 ;;
    esac
done
shift $((OPTIND-1))
echo "verbose=$verbose output=$output args restants : $*"
Squelette complet. Le : initial dans ":vho:" active le mode silencieux (les erreurs passent par les cas \? et : au lieu de getopts qui imprime à stderr). shift $((OPTIND-1)) retire les options traitées, laissant $@ avec uniquement les arguments positionnels.
Pas d'options longues : getopts ne sait pas gérer --verbose. Pour les options longues et combinables (style GNU), utiliser le binaire getopt (paquet util-linux) qui produit une chaîne normalisée à reparser, ou ré-écrire un parser manuel avec un case sur $1.

Voir aussi : function ($1, $@, shift) case