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"
Menu interactif
#!/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
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