Shell scripting Bash & redirections
Sommaire
Le shell n'est pas seulement une invite de commandes : c'est un langage complet, et l'outil d'automatisation de base d'un administrateur système.
1. Flux standards et redirections
Toute commande dispose de trois flux, identifiés par un numéro de canal.
| Flux | Canal | Description | Redirection |
|---|---|---|---|
| STDIN | 0 | Entrée standard (clavier) | < |
| STDOUT | 1 | Sortie standard (écran) | > écraser, >> ajouter |
| STDERR | 2 | Sortie d'erreur | 2>, 2>> |
ls > liste.txt # écrase le fichier
ls >> liste.txt # ajoute à la fin
ls /inexistant 2> erreurs.log # seulement les erreurs
ls > sortie.log 2>&1 # les deux flux dans le même fichier
ls &> sortie.log # écriture équivalente, plus courte
ls /inexistant 2> /dev/null # faire taire les erreurs
wc -l < fichier.txt # lire depuis un fichier
/dev/null est un fichier spécial qui absorbe tout ce qu'on lui envoie : la « corbeille » du
système. Utile pour supprimer un affichage sans supprimer la commande.
L'ordre compte : 2>&1 signifie « envoyer STDERR là où pointe actuellement
STDOUT ». Écrit avant la redirection de STDOUT, il ne fonctionne pas.
cmd > f.log 2>&1 est correct, cmd 2>&1 > f.log ne l'est pas.
2. Tubes et enchaînements
ps aux | grep apache | wc -l # tube : la sortie devient l'entrée
commande1 ; commande2 # enchaîner quoi qu'il arrive
commande1 && commande2 # commande2 seulement si commande1 réussit
commande1 || commande2 # commande2 seulement si commande1 échoue
ls /tmp > /dev/null && echo "La commande a réussi"
mkdir /tmp/test || echo "Échec de la création"
Le tube (|) redirige STDOUT vers STDIN de la commande suivante. C'est ce qui
permet de composer de petits outils plutôt que d'écrire un gros programme — le principe fondateur d'Unix.
&& et || s'appuient sur le code de retour :
0 signifie succès, toute autre valeur un échec.
3. grep, awk, sed et compagnie
grep "erreur" /var/log/syslog # lignes contenant un motif
grep -i "erreur" fichier # sans tenir compte de la casse
grep -v "info" fichier # inverser : lignes NE contenant PAS
grep -r "mot" /etc/ # récursif
grep -c "404" access.log # compter les lignes correspondantes
cut -d: -f1 /etc/passwd # 1er champ, séparateur ':'
sort fichier.txt | uniq -c # trier puis compter les doublons
wc -l fichier.txt # compter les lignes
awk '{print $1, $7}' access.log # afficher des colonnes
awk -F: '$3 >= 1000 {print $1}' /etc/passwd # comptes utilisateurs
sed 's/ancien/nouveau/g' f.txt # substituer (affichage)
sed -i 's/ancien/nouveau/g' f.txt # substituer dans le fichier
Exemple d'enchaînement typique : les dix adresses IP les plus présentes dans un journal Apache.
awk '{print $1}' access.log | sort | uniq -c | sort -rn | head -10
4. Écrire un script
#!/bin/bash
# backup.sh — sauvegarde quotidienne
# Auteur : ... Date : ...
echo "Backup exécuté à $(date)" >> ~/backup.log
chmod +x backup.sh
./backup.sh
- Le shebang
#!/bin/bashdoit occuper la toute première ligne : il indique l'interpréteur à utiliser. $(commande)exécute la commande et remplace l'expression par son résultat (substitution de commande). Ancienne syntaxe équivalente : les accents graves.- Un script non exécutable peut tout de même être lancé par
bash script.sh.
5. Variables
NOM="BTS SIO" # pas d'espace autour du '='
echo "Bonjour $NOM" # guillemets doubles : la variable est remplacée
echo 'Bonjour $NOM' # guillemets simples : affichage littéral
echo "${NOM}_2025" # accolades pour délimiter le nom
FICHIER="/var/log/syslog"
echo "Taille : $(wc -l < "$FICHIER") lignes"
Variables réservées
| Variable | Contenu |
|---|---|
$0 | Nom du script |
$1, $2… | Arguments passés au script |
$# | Nombre d'arguments |
$@ | Tous les arguments |
$? | Code de retour de la dernière commande (0 = succès) |
$$ | PID du script en cours |
Variables d'environnement
env # lister les variables d'environnement
echo $PATH $HOME $USER
maVar="Bonjour" # variable de shell : locale à la session
export maVar # devient variable d'environnement, héritée par les enfants
export PATH=$PATH:. # ajouter le répertoire courant au PATH
Différence à retenir : une variable simplement déclarée n'apparaît pas dans env et n'est
pas visible depuis un script, car celui-ci s'exécute dans un shell enfant.
export la fait passer aux processus fils. C'est exactement ce que teste l'exercice du TP.
Toujours entourer les variables de guillemets doubles : "$FICHIER". Sans eux, un nom
contenant un espace est découpé en plusieurs arguments — source d'erreurs difficiles à diagnostiquer.
6. Conditions
if [ "$1" == "admin" ]; then
echo "Accès autorisé"
elif [ -z "$1" ]; then
echo "Aucun argument fourni"
else
echo "Accès refusé"
fi
| Test | Vrai si… |
|---|---|
-f fichier | Le fichier existe et est un fichier ordinaire |
-d dossier | Le répertoire existe |
-e chemin | L'élément existe, quel que soit son type |
-r, -w, -x | Droit de lecture / écriture / exécution |
-z "$var" | La chaîne est vide |
-n "$var" | La chaîne n'est pas vide |
"$a" == "$b" | Chaînes égales |
$a -eq $b | Nombres égaux (-ne, -lt, -gt, -le, -ge) |
Les espaces à l'intérieur des crochets sont obligatoires : [ "$a" == "b" ] et non
["$a"=="b"]. [ est une commande, pas une ponctuation.
case
case "$1" in
start) echo "Démarrage" ;;
stop) echo "Arrêt" ;;
restart) echo "Redémarrage" ;;
*) echo "Usage : $0 {start|stop|restart}" ;;
esac
7. Boucles
# for sur une liste de fichiers
for item in *.txt; do
echo "Fichier trouvé : $item"
done
# for numérique
for i in {1..5}; do
echo "Itération $i"
done
# while, ligne par ligne dans un fichier
while read ligne; do
echo "> $ligne"
done < fichier.txt
# until
compteur=0
until [ $compteur -ge 3 ]; do
echo $compteur
compteur=$((compteur + 1))
done
$(( )) réalise les calculs arithmétiques. break sort de la boucle,
continue passe à l'itération suivante.
8. Fonctions et code de retour
#!/bin/bash
verifier_fichier() {
if [ ! -f "$1" ]; then
echo "Erreur : $1 introuvable" >&2
return 1
fi
return 0
}
if [ $# -eq 0 ]; then
echo "Usage : $0 <fichier>" >&2
exit 1
fi
if verifier_fichier "$1"; then
echo "toto" >> "$1"
echo "Ligne ajoutée à $1"
else
exit 1
fi
- Les arguments d'une fonction s'utilisent comme ceux d'un script :
$1,$2… returnrenvoie un code de retour (0 à 255), pas une valeur. Pour renvoyer une donnée, on l'affiche et l'appelant la capture avec$(ma_fonction).- Les messages d'erreur vont sur STDERR (
>&2) : ils restent visibles même si la sortie normale est redirigée vers un fichier. exit 0pour un succès,exit 1ou plus pour un échec — c'est ce que liront cron,&&et les outils de supervision.