Guide avancé d'écriture des scripts Bash

Une exploration en profondeur de l'art de la programmation shell

Mendel Cooper

5.3

11 mai 2008

Historique des versions
Version 5.1 10 novembre 2007 mc
Version 'LINGONBERRY' : Mise à jour mineure.
Version 5.2 16 mars 2008 mc
Version 'SILVERBERRY' : Mise à jour importante.
Version 5.2.fr.1.0 10 mai 2007 gl
Mise à jour de la traduction française.

Résumé

Ce tutoriel ne suppose aucune connaissance de la programmation de scripts, mais permet une progression rapide vers un niveau intermédiaire/avancé d'instructions tout en se plongeant dans de petites astuces du royaume d'UNIX®. Il est utile comme livre, comme manuel permettant d'étudier seul, et comme référence et source de connaissance sur les techniques de programmation de scripts. Les exercices et les exemples grandement commentés invitent à une participation active du lecteur avec en tête l'idée que la seule façon pour vraiment apprendre la programmation de scripts est d'écrire des scripts.

Ce livre est adapté à une utilisation en classe en tant qu'introduction générale aux concepts de la programmation.

La dernière mise à jour de ce document, comme une « archive tar » compressée avec bzip2 incluant à la fois le source SGML et le HTML généré, peut être téléchargée à partir du site personnel de l'auteur. Une version PDF est aussi disponible (site miroir du PDF). Voir le journal des modifications pour un historique des révisions.


Pour Anita, la source de toute magie

Table des matières

Part 1. Introduction
1. Pourquoi la programmation Shell ?
2. Lancement avec un « #! »
2.1. Appeler le script
2.2. Exercices préliminaires
Part 2. Bases
3. Caractères spéciaux
4. Introduction aux variables et aux paramètres
4.1. Substitution de variable
4.2. Affectation de variable
4.3. Les variables Bash ne sont pas typées
4.4. Types spéciaux de variables
5. Guillemets et apostrophes
5.1. Placer les variables entre guillemets
5.2. Échappement
6. Sortie et code de sortie (ou d'état)
7. Tests
7.1. Constructions de tests
7.2. Opérateurs de test de fichiers
7.3. Autres opérateurs de comparaison
7.4. Tests if/then imbriqués
7.5. Tester votre connaissance des tests
8. Opérations et sujets en relation
8.1. Opérateurs
8.2. Constantes numériques
Part 3. Après l'approche basique
9. Les variables revisitées
9.1. Variables internes
9.2. Manipuler les chaînes de caractères
9.3. Substitution de paramètres
9.4. Typer des variables : declare ou typeset
9.5. Références indirectes
9.6. $RANDOM : générer un nombre aléatoire
9.7. La construction en double parenthèse
10. Boucles et branchements
10.1. Boucles
10.2. Boucles imbriquées
10.3. Contrôle de boucles
10.4. Tests et branchements
11. Substitution de commandes
12. Expansion arithmétique
13. Récréation
Part 4. Commandes
14. Commandes internes et intégrées
14.1. Commandes de contrôle des jobs
15. Filtres externes, programmes et commandes
15.1. Commandes de base
15.2. Commandes complexes
15.3. Commandes de date et d'heure
15.4. Commandes d'analyse de texte
15.5. Commandes pour les fichiers et l'archivage
15.6. Commandes de communications
15.7. Commandes de contrôle du terminal
15.8. Commandes mathématiques
15.9. Commandes diverses
16. Commandes système et d'administration
16.1. Analyser un script système
Part 5. Thèmes avancés
17. Expressions rationnelles
17.1. Une brève introduction aux expressions rationnelles
17.2. Remplacement
18. Documents en ligne
18.1. Chaînes en ligne
19. Redirection d'E/S (entrées/sorties)
19.1. Utiliser exec
19.2. Rediriger les blocs de code
19.3. Applications
20. Sous-shells
21. Shells restreints
22. Substitution de processus
23. Fonctions
23.1. Fonctions complexes et complexité des fonctions
23.2. Variables locales
23.3. Récursion sans variables locales
24. Alias
25. Constructeurs de listes
26. Tableaux
27. /dev et /proc
27.1. /dev
27.2. /proc
28. Des Zéros et des Nulls
29. Débogage
30. Options
31. Trucs et astuces
32. Écrire des scripts avec style
32.1. Feuille de style non officielle d'écriture de scripts
33. Divers
33.1. Shells et scripts interactifs et non interactifs
33.2. Précédence des opérateurs
33.3. Scripts d'appel
33.4. Tests et comparaisons : alternatives
33.5. Un script s'appelant lui-même (récursion)
33.6. « Coloriser » des scripts
33.7. Optimisations
33.8. Astuces assorties
33.9. Problèmes de sécurité
33.10. Problèmes de portabilité
33.11. Scripts sous Windows
34. Bash, version 2 et 3
34.1. Bash, version 2
34.2. Bash, version 3
35. Notes finales
35.1. Note de l'auteur
35.2. À propos de l'auteur
35.3. Où trouver de l'aide
35.4. Outils utilisés pour produire ce livre
35.5. Remerciements
35.6. Avis de non-responsabilité
Bibliographie
A. Contribution de scripts
B. Cartes de référence
C. Petit guide sur Sed et Awk
C.1. Sed
C.2. Awk
D. Codes de sortie ayant une signification particulière
E. Une introduction détaillée sur les redirections d'entrées/sorties
F. Options en ligne de commande
F.1. Options standards en ligne de commande
F.2. Options en ligne de commande de Bash
G. Fichiers importants
H. Répertoires système importants
I. Localisation
J. Commandes d'historique
K. Un exemple de fichier .bashrc
L. Convertir des fichiers batch DOS en scripts shell
M. Exercices
M.1. Analyse de scripts
M.2. Écriture de scripts
N. Historique des révisions
O. Sites miroirs
P. Liste de choses à faire
Q. Droits d'utilisation
R. Copyright
S. Table ASCII
T. Index

Liste des tableaux

14.1. Identifiants de jobs
30.1. Options de bash
33.1. Précédence des opérateurs
33.2. Nombres représentant les couleurs des séquences d'échappement
B.1. Variables spéciales du shell
B.2. Opérateurs de test : comparaison binaire
B.3. Opérateurs de test : fichiers
B.4. Substitution et expansion de paramètres
B.5. Opérations sur les chaînes
B.6. Constructions diverses
C.1. Opérateurs sed basiques
C.2. Exemples d'opérateurs sed
D.1. Codes de sortie réservés
L.1. Mots clés / variables / opérateurs des fichiers batch, et leur équivalent shell
L.2. Commandes DOS et leur équivalent UNIX
N.1. Historique des révisions

Liste des exemples

2.1. cleanup : Un script pour nettoyer les journaux de trace dans /var/log
2.2. cleanup : Un script de nettoyage amélioré
2.3. cleanup : Une version améliorée et généralisée des scripts précédents
3.1. Blocs de code et redirection d'entrées/sorties
3.2. Sauver la sortie d'un bloc de code dans un fichier
3.3. Exécuter une boucle en tâche de fond
3.4. Sauvegarde de tous les fichiers modifiés dans les dernières 24 heures
4.1. Affectation de variable et substitution
4.2. Affectation basique de variable
4.3. Affectation de variable, basique et élaborée
4.4. Entier ou chaîne?
4.5. Paramètres positionnels
4.6. wh, recherche d'un nom de domaine avec whois
4.7. Utiliser shift
5.1. Afficher des variables bizarres
5.2. Caractères d'échappement
6.1. exit / code de sortie
6.2. Inverser une condition en utilisant !
7.1. Où est le vrai?
7.2. Équivalences de test, /usr/bin/test, [ ], et /usr/bin/[
7.3. Tests arithmétiques en utilisant (( ))
7.4. Test de liens cassés
7.5. Comparaisons de nombres et de chaînes de caractères
7.6. Vérification si une chaîne est nulle
7.7. zmore
8.1. Plus grand diviseur commun
8.2. Utiliser des opérations arithmétiques
8.3. Tests de conditions composées en utilisant && et ||
8.4. Représentation des constantes numériques
9.1. $IFS et espaces blancs
9.2. Saisie avec délai
9.3. Encore une fois, saisie avec délai
9.4. read avec délai
9.5. Suis-je root ?
9.6. arglist : Affichage des arguments avec $* et $@
9.7. Comportement de $* et $@ incohérent
9.8. $* et $@ lorsque $IFS est vide
9.9. Variable tiret bas
9.10. Insérer une ligne blanche entre les paragraphes d'un fichier texte
9.11. Générer « aléatoirement » une chaîne de huit caractères
9.12. Convertir des formats de fichiers graphiques avec une modification du nom du fichier
9.13. Convertir des fichiers audio en ogg
9.14. Émuler getopt
9.15. Autres moyens d'extraire des sous-chaînes
9.16. Utiliser la substitution et les messages d'erreur
9.17. Substitution de paramètres et messages d'« usage »
9.18. Longueur d'une variable
9.19. Correspondance de modèle dans la substitution de paramètres
9.20. Renommer des extensions de fichiers :
9.21. Utiliser la concordance de modèles pour analyser des chaînes de caractères diverses
9.22. Modèles correspondant au préfixe ou au suffixe d'une chaîne de caractères
9.23. Utiliser declare pour typer des variables
9.24. Références indirectes aux variables
9.25. Passer une référence indirecte à awk
9.26. Générer des nombres aléatoires
9.27. Piocher une carte au hasard dans un tas
9.28. Simulation « Brownian Motion »
9.29. Un nombre au hasard entre deux valeurs
9.30. Lancement d'un seul dé avec RANDOM
9.31. Réinitialiser RANDOM
9.32. Nombres pseudo-aléatoires, en utilisant awk
9.33. Manipulation, à la façon du C, de variables
10.1. Des boucles for simples
10.2. Boucle for avec deux paramètres dans chaque élément de la [liste]
10.3. Fileinfo : opérer sur une liste de fichiers contenue dans une variable
10.4. Agir sur des fichiers à l'aide d'une boucle for
10.5. in [liste] manquant dans une boucle for
10.6. Générer la [liste] dans une boucle for avec la substitution de commandes
10.7. Un remplaçant de grep pour les fichiers binaires
10.8. Afficher tous les utilisateurs du système
10.9. Rechercher les auteurs de tous les binaires d'un répertoire
10.10. Afficher les liens symboliques dans un répertoire
10.11. Liens symboliques dans un répertoire, sauvés dans un fichier
10.12. Une boucle for à la C
10.13. Utiliser efax en mode batch
10.14. Simple boucle while
10.15. Une autre boucle while
10.16. Boucle while avec de multiples conditions
10.17. Syntaxe à la C pour une boucle while
10.18. Boucle until
10.19. Boucles imbriquées
10.20. Effets de break et continue dans une boucle
10.21. Sortir de plusieurs niveaux de boucle
10.22. Continuer à un plus haut niveau de boucle
10.23. Utiliser continue N dans une tâche courante
10.24. Utiliser case
10.25. Créer des menus en utilisant case
10.26. Utiliser la substitution de commandes pour générer la variable case
10.27. Simple correspondance de chaîne
10.28. Vérification d'une entrée alphabétique
10.29. Créer des menus en utilisant select
10.30. Créer des menus en utilisant select dans une fonction
11.1. Trucs de script stupides
11.2. Générer le contenu d'une variable à partir d'une boucle
11.3. Découvrir des anagrammes
14.1. Un script exécutant plusieurs instances de lui-même
14.2. printf en action
14.3. Affectation d'une variable, en utilisant read
14.4. Qu'arrive-t'il quand read n'a pas de variable
14.5. Lecture de plusieurs lignes par read
14.6. Détecter les flèches de direction
14.7. Utiliser read avec la redirection de fichier
14.8. Problèmes lors de la lecture d'un tube
14.9. Modifier le répertoire courant
14.10. Laisser let faire un peu d'arithmétique.
14.11. Montrer l'effet d'eval
14.12. Afficher les paramètres en ligne de commande
14.13. Forcer une déconnexion
14.14. Une version de rot13
14.15. Utiliser eval pour forcer une substitution de variable dans un script Perl
14.16. Utiliser set avec les paramètres de position
14.17. Inverser les paramètres de position
14.18. Réaffecter les paramètres de position
14.19. « Déconfigurer » une variable
14.20. Utiliser export pour passer une variable à un script awk embarqué
14.21. Utiliser getopts pour lire les options/arguments passés à un script
14.22. « Inclure » un fichier de données
14.23. Un script (inutile) qui se charge lui-même
14.24. Effets d'exec
14.25. Un script lançant exec sur lui-même
14.26. Attendre la fin d'un processus avant de continuer
14.27. Un script qui se tue lui-même
15.1. Utilisation de ls pour créer une liste de fichiers à graver sur un CDR
15.2. Hello or Good-bye
15.3. Badname élimine dans le répertoire courant les fichiers dont le nom contient des caractères incorrects et des espaces blancs.
15.4. Effacer un fichier par son numéro d'inode
15.5. Fichier de traces utilisant xargs pour surveiller les journaux système
15.6. Copier les fichiers du répertoire courant vers un autre répertoire en utilisant xargs
15.7. Tuer des processus par leur nom
15.8. Analyse de la fréquence des mots en utilisant xargs
15.9. Utiliser expr
15.10. Utiliser date
15.11. Calcul de Date
15.12. Analyse de fréquence d'apparition des mots
15.13. Quels fichiers sont des scripts ?
15.14. Générer des nombres aléatoires de dix chiffres
15.15. Utiliser tail pour surveiller le journal des traces système
15.16. Afficher les lignes From des courriels stockés sous forme de fichiers
15.17. Émuler grep dans un script
15.18. Solutionneur de mots croisés
15.19. Rechercher des définitions dans le dictionnaire Webster de 1913
15.20. Chercher les mots dans une liste pour tester leur validité
15.21. toupper : Transforme un fichier en majuscule.
15.22. lowercase : Change tous les noms de fichier du répertoire courant en minuscule.
15.23. du : Convertit les fichiers texte DOS vers UNIX.
15.24. rot13 : rot13, cryptage ultra-faible.
15.25. Générer des énigmes « Crypto-Citations »
15.26. Affichage d'un fichier formaté.
15.27. Utiliser column pour formater l'affichage des répertoires
15.28. nl : un script d'autonumérotation.
15.29. manview : Visualisation de pages man formatées
15.30. Utiliser cpio pour déplacer un répertoire complet
15.31. Déballer une archive rpm
15.32. Supprimer les commentaires des programmes C
15.33. Explorer /usr/X11R6/bin
15.34. Une commande strings « améliorée »
15.35. Utiliser cmp pour comparer deux fichiers à l'intérieur d'un script.
15.36. basename et dirname
15.37. Un script qui se copie lui-même en sections
15.38. Vérifier l'intégrité d'un fichier
15.39. Décoder des fichier codés avec uudecode
15.40. Trouver où dénoncer un spammeur
15.41. Analyser le domaine d'un courrier indésirable
15.42. Obtenir la cote d'une valeur de bourse
15.43. Mettre à jour FC4
15.44. Utilisation de ssh
15.45. Un script qui envoie son fichier source
15.46. Paiement mensuel sur une hypothèque
15.47. Conversion de base
15.48. Appeler bc en utilisant un document en ligne
15.49. Calculer PI
15.50. Convertir une valeur décimale en hexadécimal
15.51. Factorisation
15.52. Calculer l'hypoténuse d'un triangle
15.53. Utiliser seq pour générer l'incrément d'une boucle
15.54. Compteur de lettres
15.55. Utiliser getopt pour analyser les paramètres de la ligne de commande
15.56. Un script qui se copie lui-même
15.57. S'exercer à dd
15.58. Capturer une saisie
15.59. Effacer les fichiers de façon sûre
15.60. Générateur de nom de fichier
15.61. Convertir des mètres en miles
15.62. Utiliser m4
16.1. Configurer un nouveau mot de passe
16.2. Configurer un caractère d'effacement
16.3. Mot de passe secret : Désactiver l'écho du terminal
16.4. Détection de l'appui sur une touche
16.5. Vérification d'identd sur un serveur distant
16.6. pidof aide à la suppression d'un processus
16.7. Vérifier une image
16.8. Création d'un système de fichiers dans un fichier
16.9. Ajoute un nouveau disque dur
16.10. Utiliser umask pour cacher un fichier en sortie
16.11. killall, à partir de /etc/rc.d/init.d
18.1. broadcast : envoie des messages à chaque personne connectée
18.2. fichierstupide : Crée un fichier stupide de deux lignes
18.3. Message multi-lignes en utilisant cat
18.4. Message multi-lignes, aves les tabulations supprimées
18.5. Document en ligne avec une substitution de paramètre
18.6. Télécharger un ensemble de fichiers dans le répertoire de récupération Sunsite
18.7. Substitution de paramètres désactivée
18.8. Un script générant un autre script
18.9. Documents en ligne et fonctions
18.10. Document en ligne « anonyme »
18.11. Décommenter un bloc de code
18.12. Un script auto-documenté
18.13. Ajouter une ligne au début d'un fichier
18.14. Analyser une boîte mail
19.1. Rediriger stdin en utilisant exec
19.2. Rediriger stdout en utilisant exec
19.3. Rediriger à la fois stdin et stdout dans le même script avec exec
19.4. Éviter un sous-shell
19.5. Boucle while redirigée
19.6. Autre forme de boucle while redirigée
19.7. Boucle until redirigée
19.8. Boucle for redirigée
19.9. Rediriger la boucle for (à la fois stdin et stdout)
19.10. Rediriger un test if/then
19.11. Fichier de données nom.données pour les exemples ci-dessus
19.12. Enregistrer des événements
20.1. Étendue des variables dans un sous-shell
20.2. Lister les profils utilisateurs
20.3. Exécuter des processus en parallèle dans les sous-shells
21.1. Exécuter un script en mode restreint
23.1. Fonctions simples
23.2. Fonction prenant des paramètres
23.3. Fonctions et arguments en ligne de commande passés au script
23.4. Passer une référence indirecte à une fonction
23.5. Déréférencer un paramètre passé à une fonction
23.6. De nouveau, déréférencer un paramètre passé à une fonction
23.7. Maximum de deux nombres
23.8. Convertir des nombres en chiffres romains
23.9. Tester les valeurs de retour importantes dans une fonction
23.10. Comparer deux grands entiers
23.11. Vrai nom pour un utilisateur
23.12. Visibilité de la variable locale
23.13. Démonstration d'une fonction récursive simple
23.14. Récursion en utilisant une variable locale
23.15. La séquence de Fibonacci
23.16. Les tours d'Hanoi
24.1. Alias à l'intérieur d'un script
24.2. unalias : Configurer et supprimer un alias
25.1. Utiliser une liste ET pour tester des arguments de la ligne de commande
25.2. Un autre test des arguments de la ligne de commande en utilisant une liste and
25.3. Utiliser des listes OR en combinaison avec une liste ET
26.1. Utilisation d'un tableau simple
26.2. Formatage d'un poème
26.3. Opérations de chaînes sur des tableaux
26.4. Charger le contenu d'un script dans un tableau
26.5. Quelques propriétés spéciales des tableaux
26.6. Des tableaux vides et des éléments vides
26.7. Initialiser des tableaux
26.8. Copier et concaténer des tableaux
26.9. Plus sur la concaténation de tableaux
26.10. Le tri bulle : Bubble Sort
26.11. Tableaux imbriqués et références indirectes
26.12. Crible d'Ératosthene
26.13. Crible d'Ératosthene, optimisé
26.14. Émuler une pile
26.15. Application complexe des tableaux Exploration d'une étrange série mathématique
26.16. Simuler un tableau à deux dimensions, puis son test
27.1. Utiliser /dev/tcp pour corriger des problèmes
27.2. Trouver le processus associé à un PID
27.3. État de la connexion
28.1. Cacher le cookie jar
28.2. Créer un fichier de swap en utilisant /dev/zero
28.3. Créer un disque ram
29.1. Un script bogué
29.2. Mot clé manquant
29.3. test24, un autre script bogué
29.4. Tester une condition avec un assert
29.5. Récupérer la sortie
29.6. Nettoyage après un Control-C
29.7. Tracer une variable
29.8. Lancer plusieurs processus (sur une machine SMP)
31.1. Les comparaisons d'entiers et de chaînes ne sont pas équivalentes
31.2. Problèmes des sous-shell
31.3. Envoyer la sortie de echo dans un tube pour un read
33.1. Script d'appel
33.2. Un script d'appel légèrement plus complexe
33.3. Un script d'appel générique qui écrit dans un fichier de traces
33.4. Un script d'appel autour d'un script awk
33.5. Un script d'appel autour d'un autre script awk
33.6. Perl inclus dans un script Bash
33.7. Combinaison de scripts Bash et Perl
33.8. Un script (inutile) qui s'appelle récursivement
33.9. Un script (utile) qui s'appelle récursivement
33.10. Un autre script (utile) qui s'appelle récursivement
33.11. Une base de données d'adresses « colorisée »
33.12. Dessiner une boîte
33.13. Afficher du texte coloré
33.14. Un jeu de « courses de chevaux »
33.15. Astuce de valeur de retour
33.16. Une astuce permettant de renvoyer plus d'une valeur de retour
33.17. Passer et renvoyer un tableau
33.18. Un peu de fun avec des anagrammes
33.19. Widgets appelés à partir d'un script shell
34.1. Expansion de chaîne de caractères
34.2. Références de variables indirectes - la nouvelle façon
34.3. Simple application de base de données, utilisant les références de variables indirectes
34.4. Utiliser des tableaux et autres astuces pour gérer quatre mains aléatoires dans un jeu de cartes
A.1. mailformat : Formater un courrier électronique
A.2. rn : Un utilitaire simple pour renommer des fichiers
A.3. blank-rename : Renommer les fichiers dont le nom contient des espaces
A.4. encryptedpw : Charger un fichier sur un site ftp, en utilisant un mot de passe crypté en local
A.5. copy-cd : Copier un CD de données
A.6. collatz : Séries de Collatz
A.7. days-between : Calculer le nombre de jours entre deux dates
A.8. makedict : Créer un dictionnaire
A.9. soundex : Conversion phonétique
A.10. « life : Jeu de la Vie »
A.11. Fichier de données pour le Jeu de la Vie
A.12. behead: Supprimer les en-têtes des courriers électroniques et des nouvelles
A.13. ftpget: Télécharger des fichiers via ftp
A.14. password: Générer des mots de passe aléatoires de 8 caractères
A.15. fifo: Faire des sauvegardes journalières, en utilisant des tubes nommés
A.16. primes: Générer des nombres premiers en utilisant l'opérateur modulo
A.17. tree: Afficher l'arborescence d'un répertoire
A.18. tree2 : autre script tree
A.19. string: Manipuler les chaînes de caractères comme en C
A.20. Informations sur un répertoire
A.21. obj-oriented: Bases de données orientées objet
A.22. Bibliothèque de fonctions de hachage
A.23. Coloriser du texte en utilisant les fonctions de hachage
A.24. Encore plus sur les fonctions de hachage
A.25. Monter des périphériques de stockage USB
A.26. Convertir en HTML
A.27. Préserver les weblogs
A.28. Protéger les chaînes littérales
A.29. Ne pas protéger les chaînes littérales
A.30. Identification d'un spammer
A.31. Chasse aux spammeurs
A.32. Rendre wget plus facile à utiliser
A.33. Un script de podcasting
A.34. Sauvegarde de nuit pour un disque firewire
A.35. Une commande cd étendue
A.36. Un script de configuration d'une carte son
A.37. Localise les paragraphes de division dans un fichier texte
A.38. Tri d'insertion
A.39. Un générateur de fichiers pad pour les auteurs de shareware
A.40. Pétales autour d'une rose
A.41. Quacky : un jeu de mots de type Perquackey
A.42. Un outil de résolution général
A.43. Basics Reviewed
C.1. Compteur sur le nombre d'occurences des lettres
K.1. Exemple de fichier .bashrc
L.1. VIEWDATA.BAT : Fichier Batch DOS
L.2. viewdata.sh : Conversion du script shell VIEWDATA.BAT
P.1. Afficher l'environnement du serveur
S.1. Un script qui génère une table ASCII