Aide-mémoire Bash / Shell Linux
| Structure et Entêtes |
| Objectif | Commande |
| Entête recommandée |
#!/usr/bin/env bash set -euo pipefail # -e : arrêt sur erreur # -u : erreur si variable non définie # -o pipefail : propager erreurs dans les pipes
readonly SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" readonly SCRIPT_NAME="$(basename "$0")" |
| Exécuter un script |
chmod +x script.sh ./script.sh bash script.sh bash -x script.sh :: mode debug (affiche les commandes) bash -n script.sh :: vérifier la syntaxe sans exécuter |
| Commentaires |
# Commentaire sur une ligne
: '
Commentaire
multiligne
' |
| Variables |
| Déclaration et utilisation |
nom="Jean" :: pas d'espace autour de = echo "Bonjour $nom" echo "Bonjour ${nom}" :: délimiteur explicite readonly PI=3.14159 :: constante export VAR="valeur" :: exporter vers les sous-shells |
| Variables spéciales |
$0 :: nom du script $1 $2 ... :: arguments positionnels $# :: nombre d'arguments $@ :: tous les arguments (liste) $* :: tous les arguments (chaîne) $? :: code retour de la dernière commande $$ :: PID du script en cours $! :: PID de la dernière commande en arrière-plan $_ :: dernier argument de la commande précédente |
| Valeurs par défaut |
${var:-"defaut"} :: valeur si var vide ou non définie ${var:="defaut"} :: assigner si vide ou non définie ${var:?"message"} :: erreur si vide ou non définie ${var:+"autre"} :: "autre" si var définie et non vide |
| Arithmétique |
((n = 5 + 3)) ((n++)) ((n += 10)) result=$((10 * 3 + 1)) echo $((2 ** 10)) :: puissance : 1024
:: Virgule flottante (bc) result=$(echo "scale=2; 10/3" | bc) result=$(echo "sqrt(144)" | bc -l) |
| Manipulation de Chaînes |
| Longueur et sous-chaîne |
s="Bonjour Monde" ${#s} :: longueur : 13 ${s:0:7} :: Bonjour (pos 0, 7 chars) ${s:8} :: Monde (à partir de 8) ${s: -5} :: Monde (5 derniers) |
| Remplacements |
${s/Monde/World} :: remplacer première occurrence ${s//o/0} :: remplacer toutes ${s/#Bonj/Allo} :: si commence par Bonj ${s/%onde/ito} :: si finit par onde |
| Suppression de préfixe/suffixe |
fichier="archive.tar.gz" ${fichier#*.} :: tar.gz (préfixe court *. ) ${fichier##*.} :: gz (préfixe long *. ) ${fichier%.*} :: archive.tar (suffixe court) ${fichier%%.*} :: archive (suffixe long) |
| Casse |
${s,,} :: tout en minuscule (bash 4+) ${s^^} :: tout en majuscule ${s,} :: première lettre en minuscule ${s^} :: première lettre en majuscule |
| Tests sur chaînes |
[[ -z "$s" ]] :: vrai si chaîne vide [[ -n "$s" ]] :: vrai si non vide [[ "$s" == "val" ]] [[ "$s" != "val" ]] [[ "$s" == *"sous"* ]] :: contient "sous" [[ "$s" =~ ^[0-9]+$ ]] :: regex |
| Conditions (if / test) |
| if / elif / else |
if [[ $age -ge 18 ]]; then echo "Majeur" elif [[ $age -ge 16 ]]; then echo "Presque" else echo "Mineur" fi |
| Tests numériques |
[[ $n -eq 5 ]] :: égal [[ $n -ne 5 ]] :: différent [[ $n -gt 5 ]] :: plus grand [[ $n -ge 5 ]] :: plus grand ou égal [[ $n -lt 5 ]] :: plus petit [[ $n -le 5 ]] :: plus petit ou égal |
| Tests sur fichiers |
[[ -e fichier ]] :: existe [[ -f fichier ]] :: est un fichier régulier [[ -d chemin ]] :: est un dossier [[ -L fichier ]] :: est un lien symbolique [[ -r fichier ]] :: lisible [[ -w fichier ]] :: écritable [[ -x fichier ]] :: exécutable [[ -s fichier ]] :: non vide (taille > 0) [[ f1 -nt f2 ]] :: f1 plus récent que f2 |
| Opérateurs logiques |
[[ cond1 && cond2 ]] :: ET [[ cond1 || cond2 ]] :: OU [[ ! cond ]] :: NON
cmd1 && cmd2 :: exécuter cmd2 si cmd1 réussit cmd1 || cmd2 :: exécuter cmd2 si cmd1 échoue |
| case |
case "$var" in "oui"|"yes") echo "affirmé";; non|no) echo "négatif";; [0-9]*) echo "commence par un chiffre";; *) echo "autre";; esac |
| Boucles |
| for (liste) |
for item in a b c; do echo "$item" done
for f in *.txt; do echo "Fichier : $f" done |
| for (numérique) |
for ((i=1; i<=10; i++)); do echo $i done
for i in {1..10}; do echo $i; done for i in {0..100..10}; do echo $i; done :: pas de 10 |
| while / until |
while [[ $i -lt 10 ]]; do ((i++)) done
while IFS= read -r ligne; do echo "$ligne" done < fichier.txt
until [[ $i -ge 10 ]]; do ((i++)) done |
| Contrôle |
break :: sortir de la boucle continue :: passer à l'itération suivante break 2 :: sortir de 2 niveaux de boucles |
| Fonctions |
| Déclarer et appeler |
ma_fonction() { local arg1="$1" local arg2="$2" echo "arg1=$arg1, arg2=$arg2" } ma_fonction "valeur1" "valeur2" |
| Valeur de retour |
est_majeur() { [[ $1 -ge 18 ]] :: return 0 (succès) ou 1 (échec) }
if est_majeur 20; then echo "Majeur"; fi
:: Retourner une chaîne via stdout get_date() { date +%Y-%m-%d; } d=$(get_date) |
| Variables locales |
fonction() { local var_locale="visible uniquement ici" global_var="visible partout" } |
| Tableaux |
| Tableaux indexés |
t=("a" "b" "c") t[3]="d" echo "${t[0]}" :: a echo "${t[@]}" :: tous les éléments echo "${#t[@]}" :: nombre d'éléments t+=("e") :: ajouter unset t[2] :: supprimer élément
for item in "${t[@]}"; do echo "$item"; done |
| Tableaux associatifs (bash 4+) |
declare -A config config[host]="localhost" config[port]=3306 echo "${config[host]}" for key in "${!config[@]}"; do echo "$key = ${config[$key]}" done |
| Entrée / Sortie et Redirection |
| Redirection |
cmd > fichier :: stdout vers fichier (écrase) cmd >> fichier :: stdout vers fichier (ajouter) cmd 2> erreurs :: stderr vers fichier cmd 2>&1 :: stderr vers stdout cmd >> log 2>&1 :: tout vers log cmd > /dev/null :: supprimer stdout cmd &> /dev/null :: supprimer tout |
| Here-doc et here-string |
cat <<EOF Ligne 1 avec $variable Ligne 2 EOF
cat <<'EOF' :: pas d'interpolation $dollar non interprété EOF
grep "pattern" <<<"chaine" :: here-string |
| Lire l'entrée |
read -r nom :: lire une ligne read -r -p "Votre nom : " nom :: avec prompt read -r -s -p "Mot de passe : " mdp :: silencieux read -r -t 10 nom :: timeout 10s read -r -a tableau <<<"a b c" :: lire dans un tableau |
| Substitution de commande |
date_str=$(date +%Y-%m-%d) nb_fichiers=$(ls * | wc -l) contenu=$(cat fichier.txt) |
| Process substitution |
diff <(sort fichier1.txt) <(sort fichier2.txt) while read line; do ...; done <(grep "err" log.txt) |
| Fichiers et Dossiers |
| Opérations courantes |
cp src dst :: copier cp -r src/ dst/ :: copier dossier mv src dst :: déplacer/renommer rm fichier :: supprimer rm -rf dossier/ :: supprimer récursif mkdir -p a/b/c :: créer arborescence find . -name "*.log" :: chercher find . -name "*.log" -mtime +7 -delete :: supprimer logs > 7j find . -type f -size +10M :: fichiers > 10 Mo |
| Traitement de texte |
grep "pattern" fichier.txt grep -r "pattern" dossier/ grep -i "Pattern" :: insensible à la casse grep -v "pattern" :: inverser grep -E "regex+" :: regex étendue grep -c "pattern" :: compter les lignes
sed 's/ancien/nouveau/g' fichier sed -i 's/ancien/nouveau/g' fichier :: en place sed -n '5,10p' fichier :: lignes 5 à 10
awk '{print $1,$3}' fichier :: colonnes 1 et 3 awk -F',' '{print $2}' f.csv :: csv, col 2 awk '/pattern/{print}' f :: lignes avec pattern awk '{sum+=$1} END{print sum}' f :: somme col 1 |
| Tri et déduplication |
sort fichier.txt sort -r fichier.txt :: inversé sort -n fichier.txt :: numérique sort -k2 -t',' fichier.csv :: par colonne 2 uniq fichier.txt :: supprimer doublons contigus sort fichier.txt | uniq :: dédupliquer sort fichier.txt | uniq -c :: compter |
| Processus et Signaux |
| Gestion processus |
cmd & :: lancer en arrière-plan jobs :: lister les jobs fg %1 :: ramener au premier plan bg %1 :: reprendre en arrière-plan wait $! :: attendre le dernier background wait :: attendre tous les backgrounds nohup cmd & :: résiste à la déconnexion disown %1 :: détacher du shell |
| Signaux et trap |
trap 'echo "Interrompu"' INT :: Ctrl+C trap 'echo "Terminé"' EXIT :: à la fin trap 'nettoyage' ERR :: sur erreur
:: Nettoyage automatique trap 'rm -f "$tmp_file"' EXIT tmp_file=$(mktemp) |
| Bonnes Pratiques et Astuces |
| Logging |
LOG_FILE="/var/log/monscript.log"
log() { echo "[$(date '+%Y-%m-%d %H:%M:%S')] $*" | tee -a "$LOG_FILE" }
log "INFO" "Démarrage" log "ERROR" "Quelque chose a échoué" |
| Parsing des arguments |
while [[ $# -gt 0 ]]; do case $1 in -f|--fichier) FICHIER="$2"; shift 2;; -v|--verbose) VERBOSE=1; shift;; -h|--help) usage; exit 0;; *) echo "Option inconnue: $1"; exit 1;; esac done
:: Avec getopts (POSIX) while getopts "f:vh" opt; do case $opt in f) FICHIER="$OPTARG";; v) VERBOSE=1;; h) usage; exit 0;; esac done |
| Verrouillage (éviter doublons) |
LOCKFILE="/tmp/$(basename $0).lock"
if ! mkdir "$LOCKFILE" 2>/dev/null; then echo "Script déjà en cours (${LOCKFILE})" exit 1 fi trap 'rm -rf "$LOCKFILE"' EXIT |
| Couleurs dans le terminal |
RED='\033[0;31m' GREEN='\033[0;32m' YELLOW='\033[1;33m' BLUE='\033[0;34m' NC='\033[0m' :: No Color
echo -e "${GREEN}Succès${NC}" echo -e "${RED}Erreur : $msg${NC}" |
| Vérifier les dépendances |
require_cmd() { command -v "$1" >/dev/null 2>&1 || { echo "Erreur : '$1' est requis mais non installé." exit 1 } } require_cmd curl require_cmd jq require_cmd docker |
| Vérifier droits root |
if [[ $EUID -ne 0 ]]; then echo "Ce script doit être exécuté en root." exit 1 fi |
| shellcheck |
shellcheck script.sh :: analyser le script shellcheck -S warning script.sh :: seuil avertissement :: Installer : apt install shellcheck / brew install shellcheck |