Académique Documents
Professionnel Documents
Culture Documents
Copyright
Copyright c Jules Aubert <jules.aubert@ext.devinci.fr>
1
Table des matières
1 Lecture 4
1.1 Qu’est-ce que le shell ? . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4
1.2 Historique . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4
1.3 Variation . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4
2 Shell script 5
2.1 Qu’est-ce qu’un script shell ? . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 5
2.2 Entrée / Sortie . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 5
2.2.1 Entrées . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 5
2.2.2 Sorties . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 5
2.3 Séquence de commandes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 6
2.3.1 Calcul . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 6
2.4 Variables . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 6
2.4.1 Variables communes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 7
2.5 Builtins . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 7
2.6 Structures de contrôle . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 7
2.6.1 if then else . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 7
2.6.2 Boucles . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 8
2.6.3 switch case . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 8
2.6.4 Test . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 8
2.7 Exercise : salutation.sh . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 9
2.8 Exercise : count_files.sh . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 9
2.9 Fonctions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 9
2.10 Globbing . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 9
2.11 Quoting . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 9
2.11.1 Double quotes (") . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 10
2.11.2 Simple quotes (’) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 10
2.11.3 Back-quotes (‘) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 10
5 Expressions régulières 14
5.1 Regex basiques . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 14
5.1.1 Le point . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 14
5.1.2 Début ˆ et fin $ . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 14
5.1.3 Alternative . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 15
5.1.4 Liste . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 15
5.1.5 Intervalle . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 15
2
5.1.6 Classe . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 15
5.1.7 Répétition . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 16
5.1.8 Groupement . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 16
5.1.9 Rétro référence . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 16
5.2 Regex étendues . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 17
6 Grep 18
6.1 Introduction . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 18
6.1.1 Percée . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 18
7 Sed 19
7.1 Syntax . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 19
7.2 Méchanique . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 19
7.3 Commandes simples . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 20
7.3.1 La commande de substitution : s . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 20
7.3.2 La commande de suppression : d . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 20
7.3.3 La commande de remplacement : y . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 20
7.3.4 La commande d’affichage : p, l and - . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 21
7.4 Adresses . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 21
7.4.1 Commandes de blocs : ’{}’ . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 21
7.4.2 Bloc de remplacement : ’c’ . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 21
7.5 Labels . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 21
7.6 Commandes avancées . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 22
8 Exercises 23
8.1 Mise en route . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 23
8.2 squeeze.sh . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 23
8.3 get_line.sh . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 23
8.4 log.sh . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 23
8.5 sum.sh . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 24
8.6 Spell checker . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 24
8.7 Sed . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 24
8.7.1 L’espace fini . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 24
8.7.2 Grep . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 24
8.7.3 Head . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 25
8.7.4 Head | Tail . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 25
8.8 Compter en binaire . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 25
3
Chapitre 1
Lecture
Les systèmes d’exploitation de la famille UNIX utilisent souvent une architecture en couches. Le mot anglais shell a été
choisi car il s’agit d’une interface permettant l’accès aux services du noyau. C’est une sorte de coquille autour du noyau.
1.2 Historique
L’histoire du shell sous sa forme actuelle est étroitement liée à celle d’UNIX. Le début du shell était un programme plutôt
rudimentaire : le Bourne Shell (du nom de son créateur : Stephen Bourne) C’est un interpréteur en ligne de commande. Son
originalité était d’enchaîner les sorties des commandes aux entrées des autres en utilisant des pipes.
Aujourd’hui, le Bourne Shell classique est obsolète, et les développements comme le Bash se sont propagés dans les
systèmes UNIX. Cependant, le Bourne Shell a été standardisé par des spécifications tel que SUS (Single UNIX
specification) et on trouve toujours un équivalent dans les systèmes UNIX modernes.
Le langage (de programmation) utilisé par les différents shells ne sont pas tous compatibles. Donc si tu veux écrire des des
scripts shells portables sur tous les systèmes UNIX, il est recommandé d’utilisé la syntaxe du Bourne shell standardisée et
seulement les commandes de bases du monde UNIX.
1.3 Variation
Le Bourne shell et le shell historique des systèmes UNIX et hérite d’idées initiées par Multics (fin des années 1960s). Le C
shell (Csh) est le shell traditionnel des systèmes BSD (Berkeley Software Distribution). Le Csh utilise une syntaxe similaire
au C et innove avec le Jobs Controls ; cette fonctionnalité sera reprises par le Bourne shell et ses descendants.
En 1988 apparaît Ksh, inspiré par les deux shells précédents (la syntaxe du Bourne shell et les Jobs Controls de Csh). Bash
(écrit en 1987) est le shell basique utilisé par une majorité de systèmes UNIX (Linux, MacOSX, Solaris, etc.). Il reprend les
fonctionnalités de ses prédécesseurs et dépend du projet GNU.
Zsh est un shell plus récent, qui date de 1990 et est inspiré des shells précédents. Il apporte de nouvelles fonctionnalités
telles que la complétion de commandes améliorée, plus d’options et d’arguments, un historique partagé, la correction
d’erreurs typographiques...
TCsh est le shell des systèmes BSD, c’est une amélioration de Csh.
4
Chapitre 2
Shell script
Pour résoudre ces problèmes, il existe une pratique répandue dans le monde UNIX : les shell scripts. Un script shell n’est
ni plus ni moins qu’un fichier dans lequel vous écrivez toutes les commandes nécessaires pour effectuer votre traitement.
Par la suite, ce fichier peut être lu par votre shell qui exécutera les commandes les unes après les autres. On peut donc
considérer un script shell comme un programme interprété.
Nous devons toujours spécifier quel programme sera chargé pour interpréter ton fichier. Sous un système UNIX, nous
utilisons un shebang 1 pour cela. Il se compose des caractères "# !" suivi du chemin absolu de l’interpréteur de commande
"/bin/sh". Le chemin de l’interpréteur peut être suivi par des options pour cela.
Le corps du script shell est une séquence de commandes internes ou externes au shell. Il finit par renvoyer une valeur de
retour, traditionnellement 0 en cas de succès et une autre valeur en cas d’échec.
2.2.1 Entrées
— La ligne de commande : c’est le moyen le plus pratique pour configurer un script. L’inconvénient de ce système
est qu’il nécessite une analyse complète de la ligne de commande pour vérifier la validité des arguments au départ,
sans nécessairement l’ordre de ceux-ci. C’est assez fastidieux pour l’auteur du script.
— L’entrée standard (correspondant au fd 2 0.) : en temps normal, le clavier. C’est un moyen intuitif de
communiquer entre l’utilisateur et le script, mais il n’est pas largement utilisé car un script shell n’a généralement
aucune interaction avec un humain vu qu’il est conçu à l’origine pour automatiser l’exécution des commandes.
— Les fichiers : l’utilisation de fichiers de configuration pour un script shell est facile et recommandée pour un script
qui s’exécutera automatiquement.
2.2.2 Sorties
— La valeur de retour : un programme sur UNIX retourne une valeur. Cette valeur, entre 0 et 255, est utilisé pour
facilement tester s’il s’est arrêté normalement ou avec une erreur différent de 0. De cette façon, si le code a bien été
1. shebang : de la contraction imprécise de sharp et hash bang
2. Sur UNIX, les fichiers ouverts sont identifiés par des nombres, appelés des descripteurs de fichiers (file descriptors (fd)). L’entrée standard
est numéroté 0, la sortie standard est 1 et la sortie d‘erreur est 2
5
pensé, il est facile et rapide d’identifier une erreur. La valeur de retour est enregistré dans une variable spéciale du
shell.
— La sortie standard (correspondant au fd 1) : habituellement l’écran. Il permet d’afficher des informations à
l’utilisateur. Il peut être redirigé vers un fichier pour une analyse ultérieure, ou redirigé vers un autre programme qui
l’utilisera comme entrée.
— La sortie d’erreur (correspondant au fd 2) : habituellement l’écran. C’est le deuxième canal de sortie, le premier
étant plutôt dédié aux sorties normales. Stderr, comme son nom l’indique, est privilégié lorsqu’il s’agit d’émettre un
message d’erreur ou des informations système.
— Les fichiers : ils peuvent servir de moyen de stockage pour le résultat.
2.3.1 Calcul
Le shell a un évaluateur d’expressions arithmétiques, $((exp)) où exp est une expression arithmétique qui accepte les
opérations conventionnelels : addition, soustraction, multiplication, division, modulo. Ces opérations peuvent être utilisées
avec des nombres relatifs mais pas décimaux en bash (ça dépend de votre shell).
1 $ x =3
2 $ y =6
3 $ echo $ (( x + (4 - y ) % 3) )
4 1
5 $ echo $ (( $x + (4 - $y ) % 3) )
6 1
2.4 Variables
Les variables shell sont des chaînes de caractères nommées dont le contenu peut changer pendant l’exécution. On instantie
une variable de cette façon : var=valeur.
Avertissement : il n’y a pas d’espace de chaque côté du signe ’=’. L’identifiant doit commencer par un caractère
alphabétique majuscule ou minuscule ou un underscore ’_’ suivi de 0 ou plus caractères alphanumériques, ou un underscore.
On accède au contenu de la variable en utilisant son nom préfixé par le symbole ’$’ : $var. Il est aussi possible d’utiliser la
forme suivante pour éviter une confusion : ${var}.
Le shell a des variables spéciales : ce sont des variables qui contiennent des informations sur le processus en cours, la valeur
de retour du dernier programme, le nombre d’arguments d’un script ou d’une fonction, etc.
6
Dans le shell, il y a deux types de variables :
— les variables internes au shell, qui ne peuvent être utilisées dans le shell courant et être créées comme expliqué
précédemment
— les variables d’environnement, qui sont utilisées dans le shell actuel ainsi que dans des éventuels sous-shells. En
réalité, elles peuvent être utilisées par n’importe quel programme lancé depuis le shell où tu as défini ces dîtes
variables
Avertissement : Les sous-shells n’ont pas d’accès direct au variables d’environnement du shell parent. Il possèdent une
copie. Ainsi, les sous-shells ne peuvent pas changer les variables d’environnement du shell d’origine. Ils peuvent éditer leurs
copies, mais le changement ne sera visible que dans le shell où les changements on eu lieu. Pour créer des variables
d’environnement, nous procédons de la même façon que pour créer des variables internes au shell. Toutefois, il faudra
utiliser la commande export pour demander au shell d’exporter cette variable dans l’environnement
2.5 Builtins
La plupart des commandes que tu utilises sont des programmes distincts. C’est le cas, par exemple, de ls ou cp. Les builtins
sont des commandes intégrées au shell et exécutées par le shell lui-même. Ce sont généralement des fonctionnalités de bas
niveau du shell telles que cd ou des fonctions de gestion de variables d’environnement comme export. Pour vérifier si une
commande est un builtin ou non, nous pouvons utiliser le builtin builtin. Voici une liste partielle des builtins les plus
utilisés, la liste des builtins disponibles pour le CLI (Command Line Interface) est donnée dans le manuel de votre shell.
exit Quittez le shell actuel avec l’argument donné comme valeur de retour.
Si la valeur est omise, 0 est renvoyé par défaut
cd Changez de répertoire et déplacez-vous dans le dossier spécifié par l’argument
echo Affiche les arguments sur stdout (sortie standard))
source Exécuter un script shell dans le shell en cours
shift Supprime les N premiers arguments de la ligne de commande (par défaut 1)
eval Construire une commande à partir des arguments donnés
7
1 if CONDITION ; then
2 COMMANDS
3 elif CONDITION ; then
4 COMMANDS
5 else
6 COMMANDS
7 fi
2.6.2 Boucles
Il y a deux façons de faire des boucles dans le shell. Elles ont des syntaxes similaires :
— while : Tant que la condition est vraie, la boucle tourne.
— until : Tant que la condition est fausse, la boucle tourne.
1 while CONDITION ; do
2 COMMANDS
3 done
4
5 until CONDITION ; do
6 COMMANDS
7 done
Ce type de boucle peut parcourir une liste. Tant que la liste n’est pas terminée, VARIABLE prend pour chaque tour de
boucle une nouvelle valeur de LIST. LIST est une séquence de mots séparés par l’IFS actuel (Internal Field Separator ). Le
IFS détermine comment le shell reconnaît les champs ou limite les mots lors de l’interprétation des chaînes. Par défaut,
l’IFS est l’espace, la tabulation et le retour à la ligne, mais nous pouvons le changer. Par exemple, donnez-lui la valeur ’ :’
pour extraire des informations de $PATH.
2.6.4 Test
Le shell contient un builtin nommé test. Ce builtin permet de tester une condition sur des variables, des valeurs
numériques et / ou des fichiers. Il renvoie 0 si la condition est vérifiée, 1 sinon.
8
2.7 Exercise : salutation.sh
Commandes autorisées : builtins, date, cut
2.9 Fonctions
Les fonctions sont comme des petits shell scripts Les arguments peuvent être accédés via des variables spéciales, $1, ..., $9.
Une fonction possède une valeur de retour.
1 $ bigger () { du $1 /* | sort -n ; }
2 $ cd test ; bigger .
3 4 ./ AUTHORS
4 4 ./ doc
5 4 ./ src
6 12 ./ README
7 28 ./ TODO
8 $
2.10 Globbing
Parfois, tu devras appliquer le même traitement à un grand nombre de fichiers. Il serait très fastidieux de lister tous les
fichiers à la main. Le globbing te permet d’exprimer les noms de fichiers sous la forme de patterns. Un pattern est une
chaîne de caractères, il décrit certaines caractéristiques d’un nom de fichier. Par exemple, nous pouvons faire correspondre
le nom des fichiers avec au moins 8 caractères, la deuxième lettre est un ’t’ et les lettres 4 et 6 sont des voyelles. Pour cela,
nous utilisons wildcards ou metacharacters. Ce sont des caractères spéciaux dans le contexte de globbing, représentant un
ou plusieurs caractères.
? 1 caractère
* 0 plus de caractères
[aeiouy] 1 des caractères entre les crochets
[a-t] 1 des caractères entre ’a’ et ’t’, les limites sont inclues
[ˆabc] ou [ !abc] 1 caractère autre que ceux mentionnés
1 $ echo /[ a - e ]??
2 / bin / dev / / etc
3 $ echo / h * e
4 / home
2.11 Quoting
Le quoting change la façon dont le shell va interpréter certaines expressions. Pour ce faire, entourez simplement l’expression
de guillemets simples, doubles ou inversés. Chacun de ces symboles a un comportement différent.
9
2.11.1 Double quotes (")
— Inhibe le globbing du shell
— Assemble plusieurs mots dans un seul argument 3
— Autorise l’expansion de variable, c’est-à-dire le remplacement du nom de la variable par sa valeur
10
Chapitre 3
3.1 Redirections
Dans le monde UNIX, tout est un fichier : l’écran, le disque dur, la mémoire du logiciel que vous utilisez, et bien sûr les
fichiers sur le disque dur 1 . Il est courant de vouloir que le shell écrive dans des fichiers au lieu de les afficher à l’écran. La
redirection permet la redirection des flux d’entrée / sortie. Ils sont utilisés, par exemple, pour s’assurer que la sortie
standard d’un programme est redirigée vers un fichier 2 .
— CMD > file : CMD la sortie est écrite dans le fichier. Si ce fichier n’existe pas, il est créé. S’il existe déjà, son
contenu est écrasé
— CMD >> file : ajoute CMD la sortie dans le fichier. Si le fichier n’existe pas, il est créé
— CMD < file : le contenu du fichier est utilisé comme entrée standard pour CMD.
Nous pouvons aller encore plus loin en jouant avec des descripteurs de fichiers, pour rediriger certaines entrées et / ou
sorties, mais pas toutes. Pour indiquer depuis quel descripteur de fichier nous voulons rediriger, entrez simplement son
numéro avant le symbole de redirection. Pour indiquer vers quel descripteur de fichier nous voulons rediriger le flux, il suffit
d’entrer le numéro du descripteur suivant le symbole de redirection.
1 $ echo foo > file
2 $ cat file
3 foo
4 $ echo bar >> file
5 $ cat file
6 foo
7 bar
8 $ cat < file
9 foo
10 bar
11 $ # redirecting stderr to / dev / null
12 $ badcommand 2 > / dev / null
13 $ # redirecting both outputs to / dev / null
14 $ badcommand & > / dev / null
15 $ # redirecting stderr to stdout
16 $ command 2 > $1
17 $ cat << EOF >> file
18 this is a tiny text editor ! it can be useful
19 to write reports in a shell script .
20 EOF
21 $ cat file
22 this is a tiny text editor ! it can be useful
23 to write reports on a shell script .
24 $
11
1 $ toto = foo
2 $ echo $toto
3 foo
4 $ echo $ ( toto = bar ; echo $toto )
5 bar
6 $ echo $toto
7 foo
3.2.2 Source
source (ou simplement ’.’) est un builtin qui t’autorise à lancer un shell script dans le shell courant. Cette fonctionnalité
est utilisé pour initialiser des variables, des fonctions ou des alias.
3.2.3 Exec
L’utilité première du builtin exec est de replacer le shell par des commandes en arguments. Cette builtin est aussi utilisé
pour faire des redirections vers de nouveaux descripteurs de fichier pour le shell courant si aucune commande n’est spécifiée.
1 $ exec 3 >/ tmp / file . txt
2 $ echo " The ␣ shell ␣ is ␣ good
3 ␣ ␣ >␣ but ␣ with ␣ exec
4 ␣ ␣ >␣ it ␣ goes ␣ really ␣ far " >&3
5 $ echo " Hell ␣ yeah " >&3
6 $ cat / tmp / file . txt
7 The shell is good but with exec , it goes really far
8 Hell yeah
Et mot à mot :
1 # !/ bin / sh
2
3 while read line ; do
4 for word in $line ; do
5 echo $word
6 done
7 done < file . txt
12
Chapitre 4
4.3 Références
http://www.multicians.org/shell.html The Origin of the Shell
http://pubs.opengroup.org/onlinepubs/9699919799/ POSIX
http://www.unix.org/version4/ Single UNIX Specification
13
Chapitre 5
Expressions régulières
Les expressions régulières, appelées regexp ou regex, sont un support essentiel pour de nombreux utilitaires UNIX tels que
grep et sed, que nous étudierons.
Une expression régulière est un pattern qui décrit un ensemble de chaînes. Les expressions régulières sont construites en
tant qu’arithmétique : elles utilisent des opérateurs différents pour combiner des expressions plus petites.
Il existe plusieurs types d’expressions régulières : les basiques et les étendues. La plupart des utilitaires offrent l’un ou
l’autre via des options de ligne de commande. La différence entre ces deux formes consiste principalement à préfixer
certaines constructions par un backslash (’\’) comme nous le verrons plus bas.
Une expression régulière est mappée à une chaîne de caractères, caractère par caractère.
Note : Dans les exemples, j’utilise l’opérateur =∼ (la notation utilisée en Perl et Ruby), ce qui signifie un test de
correspondance (un match) : le terme gauche étant la chaîne de test et le droit l’expression régulière.
Certains caractères ont des significations particulières : ils sont appelés des métacaractères.
5.1.1 Le point .
Le métacaractère point (.) représente une instance de n’importe quel caractère :
1 AxB =~ A . B = > match
2 A B =~ A . B = > match
3 A123B =~ A . B = > mismatch
4 A =~ A . = > mismatch
5 AxB =~ A \. B = > mismatch
6 A . B =~ A \. B = > match
Attention : Les symboles ˆ et $ reprennent leur signification littérale si ils ne sont pas au début (ou respectivement la fin)
de la regex :
14
1 A$B =~ A$B = > match
2 A ^ =~ A ^ = > match
3 ( empty string ) =~ ^ $ = > match
4 ^ $ =~ ^ $ = > mismatch
5 b$ =~ b$ = > mismatch
6 b$ =~ b \ $ = > match
5.1.3 Alternative
Le caractère |, précédé d’un backslash \, représente une alternative entre deux éléments :
1 abd =~ ab \| cd = > match
2 acd =~ ab \| cd = > match
3 axd =~ ab \| cd = > mismatch
4 aed =~ ab \| c \| ed = > match
5.1.4 Liste
Les listes sont des raccourcis aux alternatives : au lieu d’écrire a\|b\|c, on peut écrire [abc] :
1 abd =~ a [ bce ] d = > match
2 acd =~ a [ bcd ] d = > match
3 axd =~ a [ bce ] d = > mismatch
Attention : Dans une liste, les métacaractères reprennent leur signification littérale
1 \ =~ [.*\] = > match
2 [ =~ [] abc [] = > match
3 ] =~ [] abc [] = > match
4 a =~ [] abc [] = > match
Si le premier caractère d’une liste est ˆ, la signification de la liste est inversée et devient "tout excepté un caractère de la
liste" :
1 a =~ [^ abc ] = > mismatch
2 e =~ [^ abc ] = > match
5.1.5 Intervalle
Les intervalles sont des raccourcis pour décrire des caractères successifs dans une liste.
1 z3 =~ [a - z ][0 -9] = > match
2 zz =~ [a - z ][0 -9] = > mismatch
3 a4 =~ a [1 -35] = > mismatch
4 a5 =~ a [1 -35] = > match
5 a6 =~ a [1 -35 -7] = > match
Ici, [1-35] ne signifie pas "n’importe quel nombre de 1 à 35" mais "n’importe quel caractère entre 1 et 3 ou 5". Sois sûr de
lire caractère par caractère.
Pour utiliser le caractère - dans une liste, il doit être placé en première position.
1 - =~ [ -A - C ] = > match
2 B =~ [ -A - C ] = > match
5.1.6 Classe
Les classes sont des intervalles prédéfinies, qui peuvent être paramétrées par la variable d’environnement LC_ALL, pour
répondre à différents encodages de caractères. L’encodage qui nous intéresse est ISO-8859-1, réalisé ) travers
LC_ALL=fr_FR.
15
Nom Signification ASCII ISO-8859-1
alpha Lettres alphabétiques dans la [A-Za-z] [A-Za-zÁÀÄ...ùûý]
locale courante
digit Nombres décimaux [0-9] ditto ASCII
xdigit Nombres hexadécimaux [0-9A-Fa-f] ditto ASCII
alnum Nombres ou lettres [ :alpha :][ :digit :] [ :alpha :][ :digit :]
alphanumériques
lower Lettres minuscules dans la [a-z] [a-záàäâ...üý]
locale courante
upper Lettres majuscules dans la [A-Z] [A-ZÁÀÄ...ùûý]
locale courante
blank Caractères blancs [ \t] ditto ASCII
space Caractères d’espacement \t\n\f\r\v ditto ASCII
punct Signes de ponctuations []- !"#$%&’()*. :+ ditto ASCII
;\<=> ?@ˆ_{}∼
graph Symboles ayant une réprésentation [[ :alnum :][ :punct :]] ditto ASCII
graphqiue (sauf l’espace)
print Caractères imprimables [[ :graph :][ :space :]] ditto ASCII
cntrl Caractères de contrôles ASCII code <31 and 127 ditto ASCII
Si tu veux plus d’information, réfère toi au man de regex(7) et wctype(3).
5.1.7 Répétition
Pour décrire la répétition, nous avons les métacaractères suivants :
— * zéro ou plus d’occurrences de l’élément précédent
— + une ou plus d’occurrences de l’élément précédent
— ? zéro ou une occurrence de l’élément précédent
— {n,m} au moins n et m occurrences de l’élément précédent
— {n,} au moins n occurrences de l’élément précédent
— {n} exactement n occurrences de l’élément précédent
1 ac =~ ab \+ c = > mismatch
2 abc =~ ab \+ c = > match
3 abbbc =~ ab \+ c = > match
4
5 ac =~ ab * c = > match
6 abc =~ ab * c = > match
7 abbbc =~ ab * c = > match
8
9 ac =~ ab \? c = > match
10 abc =~ ab \? c = > match
11 abbbc =~ ab \? c = > mismatch
12
13 abc =~ ab \{2 ,3\} c = > mismatch
14 abbc =~ ab \{2 ,3\} c = > match
15 abbbc =~ ab \{2 ,3\} c = > match
16 abbbbc =~ ab \{2 ,3\} c = > mismatch
Note que la répétition de caractères combinée à des métacaractères représentants des alternatives ne s’attend pas à ce que
toutes les occurences soient le même caractère :
1 a12345c =~ a .\{5\} c = > match
2 axyzxc =~ a [ xyz ]\+ c = > match
5.1.8 Groupement
Nous pouvons grouper différents caractères dans un seul élément avec (). Cette forme est très utile, spécialement dans la
combinaison avec d’autres métacaractères :
1 123 =~ \(123\) \{2\} = > mismatch
2 123123 =~ \(123\) \{2\} = > match
3
4 abc =~ \( abc \) \|\( def \) = > match
5 def =~ \( abc \) \|\( def \) = > match
6 xyz =~ \( abc \) \|\( def \) = > match
7
8 AxBAyB =~ \( A . B \) \{2\} = > match
16
1 axbcyabc =~ \(.\) x \(..\) y \1\2 = > match
2 axbcyabd =~ \(.\) x \(..\) y \1\2 = > mismatch
Note que les groupes peuvent être nichés dans ce cas, le N-ième groupe est défini par la N-ième parenthèse :
1 aceacec =~ \([ ab ]\([ cd ]\) [ ef ]\) \1\2 = > match
2 acecace =~ \([ ab ]\([ cd ]\) [ ef ]\) \1\2 = > mismatch
17
Chapitre 6
Grep
6.1 Introduction
grep est un outil qui recherche dans des fichiers donnés (ou à partir d’une entrée standard si aucun fichier n’est donné, ou
si le flag - est donné), en utilisant une ligne de commande, des lignes correspondant à une expression régulière spécifique.
Par défaut, grep affiche des lignes qui correspondent à une expression régulière simple donnée en paramètre.
6.1.1 Percée
Voici quelques questions à mettre en pratique avec le fichier /etc/passwd :
— Comment avoir toutes les lignes commençant avec le caractère ’x’ ou qui contiennent la chaîne de caractères “jules” ?
— Même question qu’au dessus, avec les expressions régulières étendues.
— Comment afficher les lignes qui ne contiennent pas le pattern "sh" ?
— Comment afficher le nombre de lignes qui contiennent le mot "root" ?
— Comment afficher le numéro de la ligne qui contient le pattern "root" ?
Avertissement : Rappelle-toi que le shell étend les arguments avant d’exécuter la commande.
Prenez l’habitude de protéger vos expressions régulières par des quotes.
18
Chapitre 7
Sed
sed est un éditeur de flux interactif : il lit une par une les lignes d’un fichier (ou de l’entrée standard) applique les
commandes d’édition et retourne le résultat sur la sortie standard. Par défaut, il ne modifie pas le fichier traité mais
l’affiche sur la sortie standard. L’atout de sed est de pouvoir être utilisé dans un pipeline.
7.1 Syntax
Pour appeler sed :
1 $ sed -e ’ program ␣ sed ’ file -a - deal
ou
1 $ sed -f program - file file - treat
Il est également possible de créer des scripts sed, pour cela il faut remplacer le traditionnel shebang # !/bin/sh par
# !/bin/sed -f.
7.2 Méchanique
La mécanique de sed est la suivante :
1. Lit une ligne sur le flux d’entrée (jusqu’à rencontrer un caractère de fin de ligne)
2. Traitement de la ligne en la passant à toutes les commandes rencontrées dans le script
3. Affiche la ligne résultante à la sortie standard à moins que sed ne soit invoqué avec l’option -n
Il est également possible d’appeler sed avec l’option -i. Dans ce cas, les commandes modifient directement le fichier entré
au lieu de l’afficher sur la sortie standard. Certains arguments peuvent être ajoutés aux suffixe -i (ça ne fonctionne pas avec
toutes les versions de sed).
Chaque instruction d’un fichier sed est composée d’une commande ou d’un bloc de commandes (ajouter une ligne,
supprimer une ligne, remplacer une chaîne de caractères, etc.) et peut être précédée par une adresse pour appliquer la
commande à un sous-groupe de lignes.
Exemple :
1 # !/ bin / sed - rf
2 # This is a comment
3 /[ a - z ]+[ a - z0 -9]*/ {
4 y /0123456789/1234567890/
5 p
6 }
7 d
Par défaut, sed utilise les expressions régulières basiques. Pour utiliser les expressions régulières étendues (comme grep), il
faut invoquer sed avec l’option ’r.
19
7.3 Commandes simples
7.3.1 La commande de substitution : s
La fonction de substitution change la première occurence d’une chaine de caractères avec une autre. C’est de loin la
commande la plus utilisé dans les scripts sed.
— pattern est une expression régulière (simple ou étendue selon l’option donnée à l’invocation de sed, simple par défaut)
— replacement est une chaine de caractère qui remplace pattern dans le résultat. Cette chaine peut contenir deux
wildcards :
— & sera remplacé la chaine complète qui a été mappée par pattern
— \n, où n est un chiffre entre 1 et 9 est remplacé par le n-ème groupe dans le pattern. Un groupe correspond à ce
qu’il y a entre crochets dans le pattern.
— Options disponibles :
— G : remplace tous les patterns rencontrés dans la ligne actuelle ;
— N : remplace seulement la N-eme occurrence du pattern dans la ligne ;
— I : ne pas être sensible à la casse ;
— P : affiche la ligne à la sortie standard si une substitution est effectuée ;
— W fichier : écrit la ligne vers ’fichier’ si une substitution est effecutée.
Il peut y avoir plusieurs options simultanément.
La fonction de substitution peut, évidemment, être utilisée avec une expression régulière.
1 # replaces all ’ Strawberry ’ or ’ strawberry ’ stringd by ’ STRAWBERRY ’
2 sed -e ’s /[ SS ] trawberry / STRAWBERRY / g ’ file
3
4 # replaces all ’ Stawberry ’ or ’ strawberry ’ strings
5 # with ’ _Strawberry_ ’ or ’ _strawberry_ ’
6 sed -e ’s /[ Ss ] trawberry / _ & _ / g ’ file
Note : Tu peux utiliser n’importe quel type de séparateur (pas juste ’/’). Pour reprendre son utilisation normale dans les
patterns, il doit être précédé par le caractère
textbackslash. C’est pareil pour la commande y.
1 $ sed -e ’s , titi ,/ titi , g ’ file
2 $ sed -e ’ ,: ,\ , , g ’ file
3 $
20
7.3.4 La commande d’affichage : p, l and -
La commande p (print) affiche la ligne selectionnée sur la sortie standard. C’est essentiel lorsque sed est invoqué avec
l’option -n.
La commande l (list) affiche la ligne sélectionnée sur la sortie standard, avec le caractère de contrôle en clair (\t au lieu de
tab, etc.) et en code ASCII (deux chiffres en octal) pour les caractères non imprimables.
1 $ echo -e ’ te \ tst ’| sed -n ’p ’
2 te st
3 $ echo -e ’ te \ tst ’| sed -n ’l ’
4 te \ tst$
5 $
7.4 Adresses
La plupart des commandes peuvent être précédées d’une adresse, qui a comme rôle d’indiquer à quelle ligne appliquer la
commande. Les différents formats d’adresse sont utilisés comme suit :
— le nombre ’ n’ spécifie que seulement la n-eme ligne du ficher est concernée par la commande (les lignes commencent
à 1) ;
— ’ $’ est la dernière ligne du dernier fichier entré ;
— ’/ expression/’ sélectionne toutes les lignes contenant l’expression régulière ;
— ’% expression%’ a le même effet que le format de l’adresse précédente mais offre l’opportunité d’entourer
l’expression régulière en utilisant un caractère différent que le slash / (n’importe quel caractère peut être utilisé au
lieu de %) ;
— ’ n, m’ sélectionne toutes les lignes depuis la ligne n jusqu’à la ligne m ;
— ’ addr1, addr2’ sélectionne toutes les lignes entre le pattern addr1 et le pattern addr2. addr1 peut être remplacé
par le numéro d’une ligne. Cependant, la recherche pour addr2 commencent seulement après la ligne addr1 si
addr2 est une regex ;
— ’ addr !’ supprime toutes les lignes sélectionnées par addr, et sélectionne les autres.
Voici quatre exemples qui appellent la commande ’p’ sur les lignes sélectionnées :
1 / test / p # prints lines containing " test "
2 4 ,8 p # prints lines 4 to 8
3 / if / ,/ fi / p # prints lines between the pattern ’if ’ and ’fi ’
4 $!p # prints all lines except the last
C’est principalement utile lorsque plusieurs commandes doivent être appliquées aux mêmes lignes.
Elle peut remplacer les lignes associées dans le texte donné. Par exemple :
1 / fool / c \ censored line
Cette commande remplacera toute ligne contenant "fool" par le texte "censored line"
7.5 Labels
Les labels sont utilisés pour faire des boucles et des tests. Un label peut être défini avec cette syntaxe : :label (en
remplaçant label par le nom de ton choix).
21
— la commande ’t label ’ cause un saut dans le script à la position où label est défini seulement si la dernière commande
de substitution modifie le pattern.
Il y a aussi d’autres extensions GNU des différentes commandes présentées. Bien que souvent utiles, il est recommandé de
ne pas les utiliser pour garder la portabilité de vos scripts.
22
Chapitre 8
Exercises
8.2 squeeze.sh
Commandes autorisées : builtins, tr
Ecris un script qui remplace tous les espaces contiguës par un seul underscore ’_’ et tous les astérisques ’*’ par un point ’.’
dans l’argument donné en ligne de commandes. Note : ** devient ..
1 $ ./ squeeze . sh ’ my ␣ ␣ ␣ ␣ ␣ source ␣ ␣ file ␣ ␣ ␣ ␣ ␣ ␣ ␣ ␣ ␣ * c ’
2 my_ source_file . c
Lis le man avec attention, un option spécifique de tr peut se rendre très utile.
8.3 get_line.sh
Commandes autorisées : head,tail
Ecris un script qui affiche la nième ligne d’un fichier. Le premier argument donné au script sera le nom du fichier, et le
second la ligne à obtenir. Si la ligne donné en argument est trop haute, le script affichera simplement la dernière ligne.
1 $ cat file . txt
2 Line number 1
3 Line number 2
4 Line number 3
5 Line number 4
6 Line number 5
7 Line number 6
8 $ ./ get_line . sh file . txt 3
9 Line number 3
8.4 log.sh
Commandes autorisées : builtins, tee
Ecris un script qui prend une commande et ses arguments en entrée, et l’exécute. Tu as besoin de :
— Rediriger sa sortie standard dans le fichier log.out ;
23
— Afficher sa sortie standard sur la sortie standard ;
— Rediriger sa sortie d’erreur dans le fichier log.err ;
— Rien ne doit être affiché sur la sortie d’erreur.
Exemple
1 $ log . sh / bin / echo toto
2 toto
3 $ cat log . err
4 $ cat log . out
5 toto
6 $ ./ log . sh ls unknown
7 $ cat log . out
8 $ cat log . err
9 ls : unknown : No such file or directory
8.5 sum.sh
Commandes autorisées : builtins, sed, tr
Ecris un script qui calcule la somme de tous ses arguments, 0 s’il n’y en a aucun. On suppose que chaque argument est un
nombre entier valide.
Les détails de l’opération doivent être affichés, suivis du résultat.
1 $ ./ sum . sh 3 4 5
2 3 + 4 + 5 = 12
3 $ ./ sum . sh
4 0 = 0
5 $ ./ sum . sh 3
6 3 = 3
Le fichier /usr/share/dict/words contient un dictionnaire pour la langue Anglaise. Nous voulons vérifier qu’un texte ne
contienne pas d’erreur. Ecris un script qui montre dans l’ordre alphabétique tous les mots donnés dans un fichier qui ne
sont pas présents dans le dictionnaire. La vérification ne soit pas être sensible à la casse.
Conseils :
— Le script ne devrait faire qu’une dizaine de lignes. Tu peux en avoir plus si tu veux, mais s’il te plait, ne part dans
du code long et compliqué.
— Lire le man est toujours une bonne idée.
8.7 Sed
Pour ces quelques exercices, tu dois programmer exclusivement avec ses. Tu peux écrire les commandes dans un fichier
’.sed’ ou directement dans la ligne de commande de ton shell.
8.7.2 Grep
Tu dois utiliser sed au lieu de grep. Ecrit un script sed qui n’affiche que les lignes qui correspondent à l’expression régulière
de ton choix. Puis édite le script pour simuler le ’-v’ de grep.
24
8.7.3 Head
Tu dois simuler la commande head en utilisant sed. Ecris un script sed qui affiche les cinq premières lignes du fichier.
Astuce : Pour gérer la sauvegarde, il peut être utile de remplacer le caractère ’1’ de la fin avec un autre caractère,
temporairement.
1 $ echo ’ 10 ’ | ./ binary . sed
2 11
3 $ echo ’ 11 ’ | ./ binary . sed
4 100
5 $ echo ’ 101001 ’ | ./ binary . sed
6 101010
7 $
Propose un patch au script pour afficher tous les nombres binaires de 0 à 1100.
1 $ echo ’0 ’ | ./ bcompteur . sed
2 0
3 1
4 10
5 11
6 100
7 101
8 110
9 111
10 1000
11 1001
12 1010
13 1011
14 1100
25