17 min de lecture · 3 722 mots

Bash Scripting : Commandes et scripts shell

Bash Scripting : Commandes et scripts shell

Structure de base

Script minimal

#!/bin/bash

Shebang - spécifie l'interpréteur

Commentaires sur une ligne

: ' Commentaire multi-lignes '

Commandes

echo "Hello World"

Exit code

exit 0 # 0 = succès, 1-255 = erreur

En-tête recommandé

#!/bin/bash

#######################################

Description: Script de sauvegarde automatique

Author: John Doe

Date: 2025-12-18

Version: 1.2.0

Usage: ./backup.sh [options]

#######################################

Options strictes

set -euo pipefail # Exit on error, undefined var, pipe failure

set -e # Exit si une commande échoue

set -u # Exit si variable non définie

set -o pipefail # Exit si erreur dans pipe

set -x # Debug mode (affiche commandes)

IFS (Internal Field Separator)

IFS=$'nt' # Séparateur = newline et tab uniquement

Couleurs ANSI

readonly RED=' 33[0;31m' readonly GREEN=' 33[0;32m' readonly YELLOW=' 33[1;33m' readonly NC=' 33[0m' # No Color

Constantes

readonly SCRIPTDIR="$(cd "$(dirname "${BASHSOURCE[0]}")" && pwd)" readonly SCRIPTNAME="$(basename "${BASHSOURCE[0]}")" readonly TIMESTAMP="$(date +%Y%m%d%H%M%S)"

Variables globales

VERBOSE=false DRY
RUN=false

Cleanup au exit

trap cleanup EXIT INT TERM cleanup() { local exitcode=$? # Nettoyage fichiers temporaires [[ -f "${TEMPFILE:-}" ]] && rm -f "$TEMPFILE" exit "$exitcode" } main() { echo "Script started at $(date)" # Code principal ici }

Exécuter main

main "$@"

Rendre script exécutable

Chmod

chmod +x script.sh chmod 755 script.sh # rwxr-xr-x

Exécution

./script.sh bash script.sh source script.sh # Exécute dans shell courant

Path

export PATH="$PATH:$HOME/scripts" script.sh # Accessible partout

Variables

Déclaration et affectation

Variables simples

nom="Jean" age=30 prix=19.99

Pas d'espace autour du =

variable = "valeur" # ERREUR

Lecture seule (constante)

readonly PI=3.14159 declare -r VERSION="1.0.0"

Variables entières

declare -i nombre=42 nombre=$nombre+10 # nombre=52

Arrays indexés

fruits=("pomme" "banane" "orange") fruits[3]="kiwi"

Arrays associatifs (dictionnaires)

declare -A couleurs couleurs[rouge]="#FF0000" couleurs[vert]="#00FF00" couleurs[bleu]="#0000FF"

Export (disponible dans sous-processus)

export DBHOST="localhost" export PATH="$PATH:$HOME/bin"

Variables locales (dans fonction)

function test() { local var
locale="valeur" }

Unset (supprimer variable)

unset nom

Utilisation variables

Lecture

echo $nom echo ${nom} # Recommandé (plus clair)

Concaténation

prenom="Jean" nomcomplet="${prenom} Dupont"

Substitution commande

date
actuelle=$(date +%Y-%m-%d) fichiers=$(ls -l)

Ou backticks (ancien)

dateactuelle=date +%Y-%m-%d

Expressions arithmétiques

result=$((5 + 3)) result=$((nombre 2)) ((compteur++)) ((compteur--))

let (arithmétique)

let "result = 5 + 3" let "compteur += 1"

Arrays

echo ${fruits[0]} # Premier élément echo ${fruits[@]} # Tous éléments echo ${fruits[
]} # Tous éléments (différent dans quotes) echo ${#fruits[@]} # Nombre d'éléments echo ${!couleurs[@]} # Clés array associatif

Longueur chaîne

texte="Hello" echo ${#texte} # 5

Substring

chaine="Hello World" echo ${chaine:0:5} # "Hello" echo ${chaine:6} # "World"

Remplacement

fichier="document.txt" echo ${fichier/txt/pdf} # "document.pdf" (première occurrence) echo ${fichier//o/0} # "d0cument.txt" (toutes occurrences)

Suppression pattern

path="/home/user/file.txt" echo ${path#/} # "home/user/file.txt" (supprime plus court) echo ${path##/} # "file.txt" (supprime plus long) echo ${path%/} # "/home/user" (supprime depuis fin) echo ${path%%/} # "" (supprime tout)

Valeurs par défaut

echo ${variable:-default} # Si vide/unset, retourne "default" echo ${variable:=default} # Si vide/unset, assigne et retourne echo ${variable:?error message} # Si vide/unset, erreur echo ${variable:+alternative} # Si défini, retourne "alternative"

Case modification

nom="jean dupont" echo ${nom^} # "Jean dupont" (première lettre maj) echo ${nom^^} # "JEAN DUPONT" (tout en maj) echo ${nom,} # première lettre min echo ${nom,,} # tout en min

Variables spéciales

Arguments script

$0 # Nom du script $1, $2, ... # Arguments positionnels $# # Nombre d'arguments $@ # Tous arguments (séparés) $ # Tous arguments (concaténés) "$@" # Préserve espaces (recommandé)

Process

$$ # PID du script $! # PID dernier processus background $? # Exit code dernière commande $
# Dernier argument dernière commande

Autres

$- # Options shell courantes $BASHVERSION $HOSTNAME $RANDOM # Nombre aléatoire 0-32767 $SECONDS # Secondes depuis lancement script $LINENO # Numéro ligne courante $FUNCNAME # Nom fonction courante

Exemple utilisation

echo "Script: $0" echo "Arguments: $@" echo "Nombre arguments: $#" echo "PID: $$" echo "Dernier exit code: $?"

Conditions

if/elif/else

Structure basique

if [ condition ]; then # code fi

if-else

if [ condition ]; then # code si vrai else # code si faux fi

if-elif-else

if [ condition1 ]; then # code condition1 elif [ condition2 ]; then # code condition2 else # code sinon fi

Une ligne

[ condition ] && echo "vrai" || echo "faux"

Test moderne [[

if [[ condition ]]; then # Supporte &&, ||, <, >, pattern matching fi

Tests de fichiers

Existence et type

[ -e fichier ] # Existe [ -f fichier ] # Fichier régulier existe [ -d dossier ] # Dossier existe [ -L lien ] # Lien symbolique existe [ -p pipe ] # Named pipe existe [ -S socket ] # Socket existe [ -b device ] # Block device existe [ -c device ] # Character device existe

Permissions

[ -r fichier ] # Readable [ -w fichier ] # Writable [ -x fichier ] # Executable [ -s fichier ] # Non vide (size > 0) [ -O fichier ] # Owned by user [ -G fichier ] # Owned by group

Comparaison fichiers

[ fichier1 -nt fichier2 ] # file1 newer than file2 [ fichier1 -ot fichier2 ] # file1 older than file2 [ fichier1 -ef fichier2 ] # Same device/inode

Exemples

if [ -f "/etc/passwd" ]; then echo "File exists" fi if [ -d "$HOME/backup" ]; then echo "Backup directory exists" else mkdir "$HOME/backup" fi if [ ! -e "config.txt" ]; then echo "Config file missing" exit 1 fi

Tests de chaînes

Vide/non vide

[ -z "$string" ] # Chaîne vide [ -n "$string" ] # Chaîne non vide [ "$string" ] # Chaîne non vide (raccourci)

Égalité

[ "$a" = "$b" ] # Égal [ "$a" == "$b" ] # Égal (bash seulement) [ "$a" != "$b" ] # Différent

Pattern matching (avec [[)

[[ "$string" == pattern ]] [[ "$string" =~ regex ]]

Exemples

nom="Jean" if [ -z "$nom" ]; then echo "Nom vide" fi if [ "$nom" = "Jean" ]; then echo "Bonjour Jean" fi if [[ "$nom" == J ]]; then echo "Nom commence par J" fi

Regex

email="test@example.com" if [[ "$email" =~ ^[a-zA-Z0-9.
%+-]+@[a-zA-Z0-9.-]+.[a-zA-Z]{2,}$ ]]; then echo "Email valide" fi

Tests numériques

Comparaisons

[ $a -eq $b ] # Equal [ $a -ne $b ] # Not equal [ $a -gt $b ] # Greater than [ $a -ge $b ] # Greater or equal [ $a -lt $b ] # Less than [ $a -le $b ] # Less or equal

Avec (( )) - syntaxe C

(( a == b )) (( a != b )) (( a > b )) (( a >= b )) (( a < b )) (( a <= b ))

Exemples

age=25 if [ $age -ge 18 ]; then echo "Majeur" else echo "Mineur" fi if (( age >= 18 && age < 65 )); then echo "Adulte actif" fi

Comparaison décimaux (nécessite bc)

prix=19.99 if (( $(echo "$prix > 20" | bc -l) )); then echo "Cher" fi

Opérateurs logiques

AND

[ condition1 ] && [ condition2 ] [ condition1 -a condition2 ] # Déprécié [[ condition1 && condition2 ]]

OR

[ condition1 ] || [ condition2 ] [ condition1 -o condition2 ] # Déprécié [[ condition1 || condition2 ]]

NOT

[ ! condition ] [[ ! condition ]]

Exemples

if [ -f "config.txt" ] && [ -r "config.txt" ]; then echo "Config lisible" fi if [[ -f "file.txt" && -w "file.txt" ]]; then echo "Fichier modifiable" fi if [ $age -ge 18 ] && [ $age -le 65 ]; then echo "Âge actif" fi

Court-circuit

[ -f "file.txt" ] && cat file.txt [ ! -d "backup" ] && mkdir backup

Case

Structure

case $variable in pattern1) # code ;; pattern2) # code ;; ) # default ;; esac

Exemples

case "$choix" in 1) echo "Option 1" ;; 2) echo "Option 2" ;; ) echo "Choix invalide" ;; esac

Patterns multiples

case "$extension" in txt|md|text) echo "Fichier texte" ;; jpg|png|gif) echo "Fichier image" ;;
) echo "Type inconnu" ;; esac

Patterns avancés

case "$fichier" in .txt) echo "Texte" ;; [0-9].log) echo "Log numéroté" ;; backup) echo "Backup" ;; ) echo "Autre" ;; esac

Avec fallthrough

case "$arg" in -v|--verbose) VERBOSE=true ;; -h|--help) afficher
aide exit 0 ;; -) echo "Option inconnue: $arg" exit 1 ;; ) fichier="$arg" ;; esac

Boucles

for

Liste simple

for item in un deux trois; do echo "$item" done

Liste de fichiers

for fichier in .txt; do echo "Traitement: $fichier" done

Range (bash 4+)

for i in {1..10}; do echo "Nombre: $i" done for i in {1..10..2}; do # Step 2 echo "$i" # 1 3 5 7 9 done for lettre in {a..z}; do echo "$lettre" done

Style C

for ((i=0; i<10; i++)); do echo "$i" done for ((i=0; i<10; i+=2)); do echo "$i" # 0 2 4 6 8 done

Array

fruits=("pomme" "banane" "orange") for fruit in "${fruits[@]}"; do echo "$fruit" done

Array avec index

for i in "${!fruits[@]}"; do echo "$i: ${fruits[$i]}" done

Sortie commande

for ligne in $(cat fichier.txt); do echo "$ligne" done

Mieux (préserve espaces)

while IFS= read -r ligne; do echo "$ligne" done < fichier.txt

Arguments

for arg in "$@"; do echo "Argument: $arg" done

Glob

for fichier in /var/log/
.log; do [ -f "$fichier" ] || continue echo "Log: $fichier" done

while

Structure basique

while [ condition ]; do # code done

Compteur

compteur=0 while [ $compteur -lt 10 ]; do echo "$compteur" ((compteur++)) done

Ou avec (( ))

compteur=0 while (( compteur < 10 )); do echo "$compteur" ((compteur++)) done

Lecture fichier (recommandé)

while IFS= read -r ligne; do echo "$ligne" done < fichier.txt

Lecture avec séparateur

while IFS=: read -r user pass uid gid info home shell; do echo "User: $user, UID: $uid, Shell: $shell" done < /etc/passwd

Boucle infinie

while true; do echo "Ctrl+C pour arrêter" sleep 1 done

Ou

while :; do echo "Infini" sleep 1 done

Avec break

while true; do read -p "Continuer? (o/n): " reponse [ "$reponse" = "n" ] && break done

Lecture entrée utilisateur

while read -p "Nom (vide pour quitter): " nom; do [ -z "$nom" ] && break echo "Bonjour $nom" done

until

Structure (exécute jusqu'à condition vraie)

until [ condition ]; do # code done

Exemple

compteur=0 until [ $compteur -ge 10 ]; do echo "$compteur" ((compteur++)) done

Attendre fichier

until [ -f "/tmp/ready" ]; do echo "En attente..." sleep 1 done

Attendre service

until nc -z localhost 3306; do echo "Attente MySQL..." sleep 2 done

break et continue

break - Sort de la boucle

for i in {1..10}; do if [ $i -eq 5 ]; then break fi echo "$i" done # 1 2 3 4

continue - Passe à l'itération suivante

for i in {1..10}; do if [ $i -eq 5 ]; then continue fi echo "$i" done # 1 2 3 4 6 7 8 9 10

break avec niveau (boucles imbriquées)

for i in {1..3}; do for j in {1..3}; do echo "$i-$j" [ $j -eq 2 ] && break 2 # Sort des 2 boucles done done

Exemple pratique

for fichier in .txt; do [ ! -r "$fichier" ] && continue # Skip si non lisible echo "Traitement: $fichier" # Traitement... done

Fonctions

Déclaration

Syntaxe 1

function nomfonction() { # code }

Syntaxe 2 (recommandée)

nom
fonction() { # code }

Exemple simple

direbonjour() { echo "Bonjour!" } direbonjour # Appel

Avec paramètres

saluer() { local nom=$1 echo "Bonjour $nom" } saluer "Jean"

Return value (exit code seulement)

estpair() { local nombre=$1 if (( nombre % 2 == 0 )); then return 0 # vrai else return 1 # faux fi } if estpair 4; then echo "Pair" fi

Retourner valeur (via echo)

additionner() { local a=$1 local b=$2 echo $((a + b)) } resultat=$(additionner 5 3) echo "Résultat: $resultat"

Variables locales

Sans local - variable globale

fonction1() { nom="Jean" } fonction1 echo "$nom" # "Jean" (accessible)

Avec local - variable locale

fonction2() { local nom="Marie" echo "$nom" # "Marie" } fonction2 echo "$nom" # "Jean" (inchangé)

Bonnes pratiques

calculer() { local x=$1 local y=$2 local resultat=$((x + y)) echo "$resultat" }

Arguments

$1, $2, ... - arguments positionnels

$@ - tous arguments

$# - nombre d'arguments

afficherargs() { echo "Fonction: ${FUNCNAME[0]}" echo "Nombre arguments: $#" echo "Tous arguments: $@" echo "Premier: $1" echo "Deuxième: $2" } afficherargs un deux trois

Vérifier nombre arguments

verifierargs() { if [ $# -ne 2 ]; then echo "Usage: ${FUNCNAME[0]} " return 1 fi echo "Arguments valides: $1, $2" }

Arguments par défaut

saluer() { local nom=${1:-"Invité"} echo "Bonjour $nom" } saluer # "Bonjour Invité" saluer "Jean" # "Bonjour Jean"

Tous arguments

concatener() { local resultat="" for arg in "$@"; do resultat="${resultat}${arg} " done echo "${resultat% }" # Retire dernier espace } concatener "Hello" "World" "!" # "Hello World !"

Portée et export

Variables dans fonctions

GLOBAL="global" fonction() { local LOCAL="local" GLOBAL="modifié" echo "Dans fonction: LOCAL=$LOCAL, GLOBAL=$GLOBAL" } fonction echo "Hors fonction: LOCAL=$LOCAL, GLOBAL=$GLOBAL"

Hors fonction: LOCAL=, GLOBAL=modifié

Export fonction (disponible dans sous-shell)

direbonjour() { echo "Bonjour!" } export -f direbonjour bash -c 'direbonjour' # Fonctionne

Entrées/Sorties

read

Lecture simple

read nom echo "Nom: $nom"

Avec prompt

read -p "Entrez votre nom: " nom

Plusieurs variables

read -p "Prénom et nom: " prenom nom

Timeout

if read -t 5 -p "Réponse (5s): " reponse; then echo "Réponse: $reponse" else echo "Timeout!" fi

Lecture silencieuse (mot de passe)

read -sp "Mot de passe: " password echo # Nouvelle ligne

Lecture tableau

read -a fruits -p "Fruits (séparés par espace): " echo "${fruits[@]}"

Lecture caractère unique

read -n 1 -p "Continuer? (o/n): " reponse echo

Lecture depuis fichier

while IFS= read -r ligne; do echo "$ligne" done < fichier.txt

Lecture avec séparateur

while IFS=: read -r user pass uid gid; do echo "User: $user, UID: $uid" done < /etc/passwd

Lecture here-string

read var <<< "valeur"

echo et printf

echo

echo "Hello World" echo "Ligne 1nLigne 2" # n non interprété par défaut echo -e "Ligne 1nLigne 2" # -e active interprétation echo -n "Sans newline" # -n supprime newline final

Couleurs ANSI

echo -e " 33[0;31mRouge 33[0m" echo -e " 33[0;32mVert 33[0m" echo -e " 33[1;33mJaune gras 33[0m"

printf (formatage)

printf "Nom: %s, Age: %dn" "Jean" 30 printf "%-10s %5dn" "Nom" 123 # Alignement printf "%sn" "${array[@]}" # Array ligne par ligne

Formatage nombres

printf "%dn" 42 # Entier printf "%fn" 3.14159 # Float printf "%.2fn" 3.14159 # 2 décimales: 3.14 printf "%en" 1000000 # Notation scientifique printf "%xn" 255 # Hexadécimal: ff

Largeur et padding

printf "%5dn" 42 # " 42" printf "%05dn" 42 # "00042" printf "%-5dn" 42 # "42 "

Redirections

Sortie standard (stdout = 1)

echo "texte" > fichier.txt # Écrase echo "texte" >> fichier.txt # Ajoute

Erreur standard (stderr = 2)

commande 2> error.log # Erreurs vers fichier commande 2>> error.log # Ajoute erreurs

Stdout et stderr

commande > output.txt 2> error.txt commande > fichier.txt 2>&1 # stderr vers stdout commande &> fichier.txt # Les deux (raccourci) commande &>> fichier.txt # Ajoute les deux

Supprimer sortie

commande > /dev/null # Supprime stdout commande 2> /dev/null # Supprime stderr commande &> /dev/null # Supprime tout

Entrée standard (stdin = 0)

commande < fichier.txt commande 0< fichier.txt

Here document

cat << EOF > fichier.txt Ligne 1 Ligne 2 Variable: $HOME EOF

Here document sans expansion

cat << 'EOF' > fichier.txt Variable: $HOME # Non expansé EOF

Here string

grep "pattern" <<< "texte à chercher" bc <<< "5 + 3"

Tee (stdout vers fichier ET terminal)

commande | tee fichier.txt commande | tee -a fichier.txt # Ajoute

Process substitution

diff <(ls dir1) <(ls dir2) commande1 > >(commande2)

Pipes

Pipe basique

ls -l | grep ".txt" cat fichier.txt | wc -l

Pipes multiples

cat fichier.txt | grep "pattern" | sort | uniq

Pipe avec erreurs

commande 2>&1 | grep "error"

Pipe vers while

ls | while read fichier; do echo "Fichier: $fichier" done

xargs (arguments depuis stdin)

ls .txt | xargs rm find . -name ".log" | xargs gzip echo "1 2 3" | xargs -n 1 echo # Un arg par ligne

Pipe fail

set -o pipefail false | true echo $? # 1 (premier échoue)

Commandes utiles

Manipulation fichiers

ls - Lister fichiers

ls ls -l # Long format ls -lh # Human readable ls -la # Inclut cachés ls -ltr # Tri par date (inverse) ls -R # Récursif

cd - Changer répertoire

cd /path/to/dir cd ~ # Home cd - # Répertoire précédent cd .. # Parent

pwd - Répertoire courant

pwd

mkdir - Créer dossier

mkdir dossier mkdir -p path/to/nested/dir # Parents

rm - Supprimer

rm fichier rm -f fichier # Force rm -r dossier # Récursif rm -rf dossier # Force récursif

cp - Copier

cp source dest cp -r sourcedir destdir # Récursif cp -p fichier dest # Préserve attributs cp -u source dest # Uniquement si plus récent

mv - Déplacer/Renommer

mv source dest mv fichier nouveaunom

touch - Créer/mettre à jour timestamp

touch fichier touch -d "2025-01-01" fichier

cat - Afficher contenu

cat fichier cat fichier1 fichier2 # Concaténer

less/more - Paginateur

less fichier more fichier

head/tail - Début/fin fichier

head fichier # 10 premières lignes head -n 5 fichier # 5 premières lignes tail fichier # 10 dernières lignes tail -n 20 fichier # 20 dernières lignes tail -f fichier # Suivre (follow) tail -f -n 100 fichier # 100 dernières puis follow

wc - Compter

wc fichier # Lignes, mots, octets wc -l fichier # Lignes wc -w fichier # Mots wc -c fichier # Octets

find - Rechercher fichiers

find . -name "
.txt" find . -type f -name ".log" find . -type d -name "backup" find . -mtime -7 # Modifiés derniers 7 jours find . -size +100M # Plus de 100MB find . -name ".tmp" -delete find . -name ".txt" -exec rm {} ;

locate - Recherche rapide (base de données)

locate fichier updatedb # Mettre à jour base

grep - Rechercher dans fichiers

grep "pattern" fichier grep -r "pattern" . # Récursif grep -i "pattern" fichier # Insensible casse grep -v "pattern" fichier # Inverse grep -n "pattern" fichier # Numéros lignes grep -c "pattern" fichier # Compte grep -l "pattern"
.txt # Noms fichiers seulement grep -E "regex" fichier # Extended regex grep -A 3 "pattern" fichier # 3 lignes après grep -B 3 "pattern" fichier # 3 lignes avant grep -C 3 "pattern" fichier # 3 lignes autour

sed - Stream editor

sed 's/old/new/' fichier # Remplace première occurrence sed 's/old/new/g' fichier # Remplace toutes sed -i 's/old/new/g' fichier # Modifie fichier sed -n '10,20p' fichier # Lignes 10-20 sed '/pattern/d' fichier # Supprime lignes sed '5d' fichier # Supprime ligne 5

awk - Traitement texte

awk '{print $1}' fichier # Première colonne awk -F: '{print $1}' /etc/passwd # Séparateur : awk '$3 > 100' fichier # Lignes où colonne 3 > 100 awk 'NR==10' fichier # Ligne 10 awk '{sum+=$1} END {print sum}' fichier # Somme

sort - Trier

sort fichier sort -r fichier # Inverse sort -n fichier # Numérique sort -u fichier # Unique sort -k 2 fichier # Par colonne 2 sort -t: -k 3 -n /etc/passwd # Par UID

uniq - Dédupliquer (nécessite tri)

uniq fichier sort fichier | uniq uniq -c fichier # Compte occurrences uniq -d fichier # Seulement doublons

cut - Extraire colonnes

cut -d: -f1 /etc/passwd # Colonne 1 cut -d: -f1,3 /etc/passwd # Colonnes 1 et 3 cut -c1-5 fichier # Caractères 1-5

tr - Traduire caractères

tr 'a-z' 'A-Z' < fichier # Minuscule vers majuscule tr -d 'r' < fichier # Supprimer r tr -s ' ' < fichier # Squeeze espaces

diff - Différences

diff fichier1 fichier2 diff -u fichier1 fichier2 # Unified format diff -r dir1 dir2 # Récursif

file - Type fichier

file fichier

stat - Informations fichier

stat fichier

ln - Créer lien

ln -s source lien # Symbolique ln source lien # Hard link

Manipulation texte avancée

Extraire colonnes spécifiques

awk -F: '{print $1, $3}' /etc/passwd

Somme colonne

awk '{sum += $1} END {print sum}' numbers.txt

Filtrer et formatter

ps aux | awk '$3 > 50 {print $2, $11}' # Process CPU > 50%

Remplacement conditionnel

awk '{if ($3 > 1000) print $0}' /etc/passwd

Recherche pattern et action

awk '/error/ {print $1, $4}' logfile

sed multi-substitutions

sed -e 's/foo/bar/g' -e 's/old/new/g' fichier

sed avec ranges

sed '10,20s/old/new/g' fichier

Insérer ligne

sed '5iNouvelle ligne' fichier

Append ligne

sed '5aLigne ajoutée' fichier

Perl one-liner

perl -pe 's/old/new/g' fichier perl -i -pe 's/old/new/g' fichier # In-place

jq (JSON)

cat data.json | jq '.users[0].name' cat data.json | jq '.[] | select(.age > 18)'

xmllint (XML)

xmllint --xpath '//user/name' file.xml

CSV processing

csvcut -c 1,3 data.csv csvgrep -c name -m "John" data.csv

Compression

gzip

gzip fichier # Compresse (supprime original) gzip -k fichier # Garde original gzip -d fichier.gz # Décompresse gunzip fichier.gz

bzip2

bzip2 fichier bunzip2 fichier.bz2

xz

xz fichier unxz fichier.xz

tar

tar -czf archive.tar.gz dossier/ # Créer gzip tar -cjf archive.tar.bz2 dossier/ # Créer bzip2 tar -cJf archive.tar.xz dossier/ # Créer xz tar -xzf archive.tar.gz # Extraire gzip tar -xjf archive.tar.bz2 # Extraire bzip2 tar -tzf archive.tar.gz # Lister contenu tar -xzf archive.tar.gz -C /dest # Extraire vers destination

zip/unzip

zip -r archive.zip dossier/ zip archive.zip fichier1 fichier2 unzip archive.zip unzip -l archive.zip # Lister unzip archive.zip -d /dest

7z

7z a archive.7z dossier/ 7z x archive.7z

Réseau

curl - Transfert HTTP

curl https://example.com curl -o fichier.txt https://example.com/file curl -O https://example.com/file.txt # Nom original curl -I https://example.com # Headers seulement curl -X POST -d "data" https://api.example.com curl -H "Content-Type: application/json" -d '{"key":"value"}' URL curl -u user:pass https://example.com curl -L https://example.com # Suivre redirects curl -s https://example.com # Silent

wget - Téléchargement

wget https://example.com/file.txt wget -O output.txt https://example.com/file wget -c https://example.com/file.iso # Reprendre wget -r https://example.com # Récursif wget -m https://example.com # Mirror wget --user=user --password=pass URL

ping

ping example.com ping -c 4 example.com # 4 pings

netstat

netstat -tuln # Ports listening netstat -tupln # Avec process netstat -an | grep :80

ss (moderne)

ss -tuln ss -tulnp ss -s # Statistiques

nc (netcat) - Swiss army knife réseau

nc -l 8080 # Listen port 8080 nc localhost 8080 # Connect nc -zv host 80 # Port scan echo "test" | nc host port

telnet

telnet example.com 80

ssh

ssh user@host ssh -p 2222 user@host # Port custom ssh -i key.pem user@host # Key authentication ssh user@host command # Execute command

scp - Copie sécurisée

scp fichier user@host:/path scp user@host:/path/fichier . scp -r dossier user@host:/path

rsync - Sync avancé

rsync -avz source/ dest/ rsync -avz --delete source/ dest/ rsync -avz source/ user@host:/dest

nslookup/dig - DNS

nslookup example.com dig example.com dig @8.8.8.8 example.com # Serveur DNS spécifique dig +short example.com

host

host example.com

ip (moderne)

ip addr show ip route show ip link show

ifconfig (ancien)

ifconfig ifconfig eth0

Processus

ps - Lister processus

ps ps aux # Tous processus ps -ef # Format complet ps -u username # Par utilisateur ps aux | grep nginx

top - Moniteur interactif

top top -u username # Par utilisateur

htop - Meilleur que top

htop

pgrep - Trouver PID

pgrep nginx pgrep -u username

pkill - Tuer par nom

pkill nginx pkill -u username

kill - Tuer processus

kill PID kill -9 PID # Force (SIGKILL) kill -15 PID # Graceful (SIGTERM) kill -HUP PID # Reload config

killall - Tuer tous par nom

killall nginx

bg/fg - Background/foreground

command & # Lance en background jobs # Liste jobs fg %1 # Job 1 en foreground bg %1 # Job 1 en background

nohup - Détacher du terminal

nohup command &

disown - Détacher job

command & disown

nice/renice - Priorité

nice -n 10 command # Priorité basse renice -n -5 -p PID # Changer priorité

wait - Attendre fin processus

command & wait $!

timeout - Limiter durée

timeout 10s command timeout 5m longprocess

Système

df - Espace disque

df -h # Human readable df -i # Inodes

du - Usage disque

du -h # Human readable du -sh # Résumé par dossier du -sh /path # Total path

free - Mémoire

free -h

uptime - Temps d'activité

uptime

uname - Info système

uname -a uname -r # Kernel version

hostname

hostname hostname -I # IP addresses

date - Date/heure

date date +%Y-%m-%d date +%Y-%m-%d%H:%M:%S date -d "2 days ago" date -d "next Monday"

cal - Calendrier

cal cal 2025

whoami - Utilisateur courant

whoami

id - Info utilisateur

id id username

who/w - Utilisateurs connectés

who w

last - Dernières connexions

last last username

history - Historique commandes

history history 20 history | grep command !123 # Exécuter commande #123 !! # Dernière commande !$ # Dernier argument

alias - Raccourcis

alias ll='ls -lah' alias ..='cd ..' unalias ll

env - Variables environnement

env env | grep PATH printenv PATH

export - Exporter variable

export VAR=value

source - Exécuter dans shell courant

source ~/.bashrc . ~/.bashrc # Équivalent

which - Localiser commande

which python which -a python # Toutes occurrences

whereis - Localiser binaire/man

whereis python

type - Info commande

type ls type -a python

apropos - Recherche man pages

apropos network

man - Manuel

man command man -k keyword # Recherche man 5 passwd # Section spécifique

info - Documentation GNU

info bash

help - Aide builtin bash

help cd help [[ ]]

Scripts avancés

Parsing arguments

#!/bin/bash

Méthode 1: Manuelle

while [[ $# -gt 0 ]]; do case $1 in -h|--help) echo "Usage: $0 [options]" exit 0 ;; -v|--verbose) VERBOSE=true shift ;; -f|--file) FILE="$2" shift 2 ;; -o|--output) OUTPUT="$2" shift 2 ;; -) echo "Option inconnue: $1" exit 1 ;; ) ARGS+=("$1") shift ;; esac done

Méthode 2: getopts (options courtes)

while getopts "hvf:o:" opt; do case $opt in h) echo "Usage: $0 [-h] [-v] [-f file] [-o output]" exit 0 ;; v) VERBOSE=true ;; f) FILE="$OPTARG" ;; o) OUTPUT="$OPTARG" ;; ?) echo "Option invalide: -$OPTARG" exit 1 ;; :) echo "Option -$OPTARG nécessite un argument" exit 1 ;; esac done shift $((OPTIND-1))

Logging

#!/bin/bash

Configuration logging

readonly LOGFILE="/var/log/script.log" readonly LOGLEVELERROR=1 readonly LOGLEVELWARN=2 readonly LOGLEVELINFO=3 readonly LOGLEVELDEBUG=4 CURRENTLOGLEVEL=$LOGLEVELINFO

Fonction log

log() { local level=$1 shift local message="$@" local timestamp=$(date '+%Y-%m-%d %H:%M:%S') if [ "$level" -le "$CURRENTLOGLEVEL" ]; then case $level in $LOGLEVELERROR) echo -e "${RED}[$timestamp] ERROR: $message${NC}" | tee -a "$LOGFILE" >&2 ;; $LOGLEVELWARN) echo -e "${YELLOW}[$timestamp] WARN: $message${NC}" | tee -a "$LOGFILE" ;; $LOGLEVELINFO) echo "[$timestamp] INFO: $message" | tee -a "$LOGFILE" ;; $LOGLEVELDEBUG) echo "[$timestamp] DEBUG: $message" >> "$LOGFILE" ;; esac fi } logerror() { log $LOGLEVELERROR "$@"; } logwarn() { log $LOGLEVELWARN "$@"; } loginfo() { log $LOGLEVELINFO "$@"; } logdebug() { log $LOGLEVELDEBUG "$@"; }

Utilisation

loginfo "Script démarré" logwarn "Attention: Espace disque faible" logerror "Erreur critique" logdebug "Variable X=$X"

Gestion erreurs

#!/bin/bash

set -euo pipefail

Trap erreurs

errorhandler() { local line=$1 local exitcode=$2 logerror "Erreur ligne $line (exit code: $exitcode)" cleanup exit "$exitcode" } trap 'errorhandler ${LINENO} $?' ERR

Vérifier commande

command -v jq >/dev/null 2>&1 || { logerror "jq n'est pas installé" exit 1 }

Vérifier exit code

if ! curl -sS https://api.example.com > /tmp/response.json; then log
error "API request failed" exit 1 fi

Try-catch simulé

if ! result=$(riskycommand 2>&1); then logerror "Command failed: $result" # Recovery logic fi

Vérifier fichier

if [ ! -f "$CONFIGFILE" ]; then logerror "Config file not found: $CONFIGFILE" exit 1 fi

Assert

assert() { if ! "$@"; then log
error "Assertion failed: $" exit 1 fi } assert [ -d "/var/data" ] assert [ -r "/etc/config.conf" ]

Parallélisation

#!/bin/bash

Méthode 1: Background jobs

for file in .txt; do processfile "$file" & done wait # Attendre tous jobs

Méthode 2: Limiter jobs parallèles

MAX
JOBS=4 for file in
.txt; do while [ $(jobs -r | wc -l) -ge $MAXJOBS ]; do sleep 0.1 done processfile "$file" & done wait

Méthode 3: GNU parallel

parallel processfile ::: .txt parallel -j 4 processfile ::: .txt # Max 4 jobs find . -name ".txt" | parallel processfile

Méthode 4: xargs parallel

ls
.txt | xargs -n 1 -P 4 process
file

Exemple traitement parallèle

processlogs() { local logfile=$1 echo "Processing $logfile..." grep "ERROR" "$logfile" > "${logfile}.errors" } export -f processlogs find /var/log -name ".log" | parallel -j 8 processlogs

Progress bar

#!/bin/bash

Progress bar simple

showprogress() { local current=$1 local total=$2 local width=50 local percent=$((current 100 / total)) local completed=$((width current / total)) printf "rProgress: [" printf "%${completed}s" | tr ' ' '=' printf "%$((width - completed))s" | tr ' ' ' ' printf "] %d%%" "$percent" if [ $current -eq $total ]; then echo fi }

Utilisation

total=100 for i in $(seq 1 $total); do # Traitement sleep 0.05 showprogress $i $total done

Progress bar avec pv

cat large
file | pv -s $(stat -c%s largefile) | gzip > output.gz

Spinner

spinner() { local pid=$1 local delay=0.1 local spinstr='|/-' while ps -p $pid > /dev/null; do local temp=${spinstr#?} printf " [%c] " "$spinstr" spinstr=$temp${spinstr%"$temp"} sleep $delay printf "bbbbbb" done printf " bbbb" } long
runningcommand & spinner $!

Configuration externe

#!/bin/bash

config.conf

DBHOST=localhost

DBPORT=3306

DBNAME=mydb

Charger config

loadconfig() { local configfile=$1 if [ ! -f "$configfile" ]; then logerror "Config file not found: $configfile" return 1 fi # Source avec validation while IFS='=' read -r key value; do # Skip comments and empty lines [[ $key =~ ^[[:space:]]# ]] && continue [[ -z $key ]] && continue # Trim whitespace key=$(echo "$key" | xargs) value=$(echo "$value" | xargs) # Export variable export "$key=$value" logdebug "Loaded: $key=$value" done < "$configfile" } loadconfig "/etc/myapp/config.conf"

Ou JSON config (avec jq)

loadjsonconfig() { local configfile=$1 if ! command -v jq &> /dev/null; then logerror "jq is required" return 1 fi DBHOST=$(jq -r '.database.host' "$configfile") DBPORT=$(jq -r '.database.port' "$configfile") DBNAME=$(jq -r '.database.name' "$configfile") } loadjsonconfig "/etc/myapp/config.json"
#!/bin/bash

showmenu() {
    clear
    echo "================================"
    echo "    Menu Principal"
    echo "================================"
    echo "1. Option 1"
    echo "2. Option 2"
    echo "3. Option 3"
    echo "4. Paramètres"
    echo "5. Quitter"
    echo "================================"
}

while true; do
    showmenu
    read -p "Choisissez une option [1-5]: " choice

    case $choice in
        1)
            echo "Option 1 sélectionnée"
            # Actions...
            read -p "Appuyez sur Entrée pour continuer..."
            ;;
        2)
            echo "Option 2 sélectionnée"
            read -p "Appuyez sur Entrée pour continuer..."
            ;;
        3)
            echo "Option 3 sélectionnée"
            read -p "Appuyez sur Entrée pour continuer..."
            ;;
        4)
            echo "Paramètres"
            read -p "Appuyez sur Entrée pour continuer..."
            ;;
        5)
            echo "Au revoir!"
            exit 0
            ;;
        )
            echo "Option invalide"
            sleep 2
            ;;
    esac
done

Menu avec select

options=("Option 1" "Option 2" "Option 3" "Quitter") select opt in "${options[@]}"; do case $REPLY in 1) echo "Option 1"; ;; 2) echo "Option 2"; ;; 3) echo "Option 3"; ;; 4) break ;;
) echo "Invalide" ;; esac done

Exemples de scripts complets

Script de backup

#!/bin/bash

set -euo pipefail

Configuration

readonly BACKUPSOURCE="/home/user/data" readonly BACKUPDEST="/backup" readonly RETENTIONDAYS=7 readonly LOGFILE="/var/log/backup.log" readonly DATE=$(date +%Y%m%d%H%M%S)

Logging

log() { echo "[$(date '+%Y-%m-%d %H:%M:%S')] $" | tee -a "$LOGFILE" }

Vérifications

if [ ! -d "$BACKUPSOURCE" ]; then log "ERROR: Source directory not found: $BACKUPSOURCE" exit 1 fi if [ ! -d "$BACKUPDEST" ]; then log "Creating backup destination: $BACKUPDEST" mkdir -p "$BACKUPDEST" fi

Backup

BACKUP
FILE="${BACKUPDEST}/backup${DATE}.tar.gz" log "Starting backup: $BACKUPSOURCE -> $BACKUPFILE" if tar -czf "$BACKUPFILE" -C "$(dirname "$BACKUPSOURCE")" "$(basename "$BACKUPSOURCE")"; then BACKUPSIZE=$(du -h "$BACKUPFILE" | cut -f1) log "Backup completed successfully: $BACKUPSIZE" else log "ERROR: Backup failed" exit 1 fi

Rotation

log "Cleaning old backups (retention: $RETENTIONDAYS days)" find "$BACKUPDEST" -name "backup.tar.gz" -type f -mtime +$RETENTION
DAYS -delete

Résumé

BACKUPSCOUNT=$(find "$BACKUPDEST" -name "backup.tar.gz" -type f | wc -l) TOTALSIZE=$(du -sh "$BACKUPDEST" | cut -f1) log "Backup summary: $BACKUPSCOUNT backups, total size: $TOTALSIZE"

Script de monitoring

#!/bin/bash

set -euo pipefail

Thresholds

readonly CPUTHRESHOLD=80 readonly MEMORYTHRESHOLD=90 readonly DISKTHRESHOLD=90 readonly ALERTEMAIL="admin@example.com"

Fonction d'alerte

send
alert() { local subject=$1 local message=$2 echo "$message" | mail -s "$subject" "$ALERTEMAIL" logger -t monitoring "ALERT: $subject - $message" }

Vérifier CPU

check
cpu() { local cpuusage=$(top -bn1 | grep "Cpu(s)" | awk '{print $2}' | cut -d'%' -f1) cpuusage=${cpuusage%.} # Partie entière if [ "$cpuusage" -gt "$CPUTHRESHOLD" ]; then sendalert "CPU Alert" "CPU usage is ${cpuusage}% (threshold: ${CPUTHRESHOLD}%)" fi }

Vérifier mémoire

checkmemory() { local memusage=$(free | grep Mem | awk '{print int($3/$2 100)}') if [ "$memusage" -gt "$MEMORYTHRESHOLD" ]; then sendalert "Memory Alert" "Memory usage is ${memusage}% (threshold: ${MEMORYTHRESHOLD}%)" fi }

Vérifier disque

check
disk() { while read -r line; do local usage=$(echo "$line" | awk '{print $5}' | sed 's/%//') local mount=$(echo "$line" | awk '{print $6}') if [ "$usage" -gt "$DISKTHRESHOLD" ]; then sendalert "Disk Alert" "Disk usage on $mount is ${usage}% (threshold: ${DISKTHRESHOLD}%)" fi done < <(df -h | tail -n +2) }

Vérifier services

check
services() { local services=("nginx" "mysql" "redis") for service in "${services[@]}"; do if ! systemctl is-active --quiet "$service"; then sendalert "Service Alert" "Service $service is not running" fi done }

Exécution

check
cpu checkmemory checkdisk checkservices echo "Monitoring completed at $(date)"

Script de déploiement

#!/bin/bash

set -euo pipefail

Configuration

readonly APPNAME="myapp" readonly APPDIR="/var/www/$APPNAME" readonly GITREPO="https://github.com/user/repo.git" readonly BRANCH="main" readonly BACKUPDIR="/backup/deployments"

Couleurs

readonly GREEN=' 33[0;32m' readonly RED=' 33[0;31m' readonly YELLOW=' 33[1;33m' readonly NC=' 33[0m' loginfo() { echo -e "${GREEN}[INFO]${NC} $"; } logwarn() { echo -e "${YELLOW}[WARN]${NC} $"; } logerror() { echo -e "${RED}[ERROR]${NC} $"; }

Backup avant déploiement

backup() { log
info "Creating backup..." local backupfile="${BACKUPDIR}/${APPNAME}$(date +%Y%m%d%H%M%S).tar.gz" mkdir -p "$BACKUPDIR" if tar -czf "$backupfile" -C "$(dirname "$APPDIR")" "$(basename "$APPDIR")"; then loginfo "Backup created: $backupfile" else logerror "Backup failed" return 1 fi }

Pull code

pullcode() { loginfo "Pulling latest code..." cd "$APPDIR" if [ -d ".git" ]; then git fetch origin git checkout "$BRANCH" git pull origin "$BRANCH" else logerror "Not a git repository" return 1 fi }

Install dependencies

installdeps() { loginfo "Installing dependencies..." cd "$APPDIR" if [ -f "package.json" ]; then npm install --production fi if [ -f "composer.json" ]; then composer install --no-dev --optimize-autoloader fi if [ -f "requirements.txt" ]; then pip install -r requirements.txt fi }

Build assets

build() { log
info "Building assets..." cd "$APPDIR" if [ -f "package.json" ]; then npm run build fi }

Restart services

restart
services() { loginfo "Restarting services..." sudo systemctl restart nginx sudo systemctl restart php-fpm || true sudo systemctl restart "$APPNAME" || true }

Health check

healthcheck() { loginfo "Running health check..." local url="http://localhost/health" local maxattempts=30 local attempt=1 while [ $attempt -le $maxattempts ]; do if curl -sf "$url" > /dev/null; then loginfo "Health check passed" return 0 fi logwarn "Health check attempt $attempt/$maxattempts failed" sleep 2 ((attempt++)) done logerror "Health check failed after $maxattempts attempts" return 1 }

Rollback

rollback() { log
warn "Rolling back to previous version..." local latestbackup=$(find "$BACKUPDIR" -name "${APPNAME}.tar.gz" | sort -r | head -n 1) if [ -z "$latestbackup" ]; then logerror "No backup found for rollback" return 1 fi rm -rf "$APPDIR" tar -xzf "$latestbackup" -C "$(dirname "$APPDIR")" restartservices loginfo "Rollback completed" }

Main deployment

main() { log
info "Starting deployment of $APPNAME..." backup || exit 1 pullcode || { logerror "Pull failed"; exit 1; } installdeps || { logerror "Dependency installation failed"; exit 1; } build || { logerror "Build failed"; exit 1; } restartservices if healthcheck; then loginfo "Deployment completed successfully" else logerror "Deployment failed health check" read -p "Rollback? (y/n): " -n 1 -r echo if [[ $REPLY =~ ^[Yy]$ ]]; then rollback fi exit 1 fi } main "$@"

Bonnes pratiques

Sécurité

Toujours citer variables

rm "$fichier" # Bon rm $fichier # Mauvais si espaces

Vérifier input utilisateur

read -p "Nom fichier: " fichier if [[ ! "$fichier" =~ ^[a-zA-Z0-9.-]+$ ]]; then echo "Nom fichier invalide" exit 1 fi

Éviter eval

eval "$commande" # Dangereux

"$commande" # Préféré

Permissions strictes

chmod 700 script.sh chmod 600 config.conf

Pas de mot de passe en clair

PASSWORD="secret" # Mauvais

read -sp "Password: " PASSWORD # Bon

Ou depuis variable environnement

PASSWORD="${DB
PASSWORD:-}"

Vérifier commandes avant utilisation

command -v jq >/dev/null 2>&1 || { echo "jq requis" exit 1 }

Nettoyer fichiers temporaires

TEMPFILE=$(mktemp) trap "rm -f $TEMPFILE" EXIT

Performance

Éviter sous-shells inutiles

count=$(cat file | wc -l) # Sous-shell

count=$(wc -l < file) # Direct

Opérations string vs commandes externes

length=$(echo "$string" | wc -c) # Lent

length=${#string} # Rapide

Boucles efficaces

for i in $(seq 1 1000); do # Lent

for ((i=1; i<=1000; i++)); do # Rapide

Read fichier ligne par ligne

while IFS= read -r line; do # Traitement done < file # Bon

Éviter cat inutiles

cat file | grep pattern # Inutile

grep pattern file # Direct

Arrays vs variables multiples

Bon pour données liées

files=(file1 file2 file3) for file in "${files[@]}"; do process "$file" done

Debugging

`bash

Mode debug

set -x # Active trace
set +x # Désactive trace

Debug partiel

set -x

Code à tracer

set +x

Debug function

debug() {
[ "$DEBUG" = "true" ] && echo "DEBUG: $" >&2
}

DEBUG=true debug "Variable X=$X"

Vérifier syntaxe sans exécuter

bash -n script.sh

ShellCheck (linter)

shellcheck script.sh

Trace avec timestamp

PS4='+ $(date "+%H:%M:%S") ${BASH_SOURCE}:${LINENO}: '
set -x

Une remarque, un retour ?

Cet article est vivant — corrections, contre-arguments et retours de production sont les bienvenus. Trois canaux, choisissez celui qui vous convient.