17 min de lecture · 3 716 mots

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
DRYRUN=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 varlocale="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
dateactuelle=$(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)
        afficheraide
        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)
nomfonction() {
    # 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
    logerror "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
        logerror "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
MAXJOBS=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 processfile

# 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 largefile | 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"
}

longrunningcommand &
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
BACKUPFILE="${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 +$RETENTIONDAYS -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
sendalert() {
    local subject=$1
    local message=$2

    echo "$message" | mail -s "$subject" "$ALERTEMAIL"
    logger -t monitoring "ALERT: $subject - $message"
}

# Vérifier CPU
checkcpu() {
    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
checkdisk() {
    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
checkservices() {
    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
checkcpu
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() {
    loginfo "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() {
    loginfo "Building assets..."

    cd "$APPDIR"

    if [ -f "package.json" ]; then
        npm run build
    fi
}

# Restart services
restartservices() {
    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() {
    logwarn "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() {
    loginfo "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="${DBPASSWORD:-}"

# 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

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.

Laisser un commentaire