MO101 - Introduction à Linux - Feuille TD3
Bienvenue dans le troisième TD du cours MO101 !
Au cours de ce TD, nous allons appronfondir nos connaissances de la ligne de commande, notamment de la fonction d'historique de bash. Ensuite, nous verrons quelques fonctions de gestion avancée de l'arborescence, en particulier la notion d'archivage, qui sera mise en application pour la remise de vos travaux pendant le contrôle. Finalement, nous ferons un court survol de quelques notions de processus sous UNIX.
Partie 1 - Un peu plus de Bash
Une fonction bien pratique de la ligne de command bash est qu'elle conserve l'historique des dernières commandes entrées. Vous avez peut-être déjà utilisé les flèches haut et bas pour parcourir cet historique pendant le TD précédent. Voici donc quelques notions de base pour utiliser cet historique :
- Touche TAB : permet de compléter les nomes de commandes/fichiers en cours de frappe (gain de temps notable !)
- Flèches haut et bas : permet de parcourir l'historique une ligne à la fois. Recopie le contenu à la ligne de commande, qui peut être automatiquement répété avec la touche Entrée;
- history : affiche la totalité de l'historique par la sortie standard. Un conseil : utilisez le tuyau et less pour le parcourir.
- Ctrl-R : permet de rechercher des commandes dans l'historique. Utilisez cette combinaison de touches, puis commencez à taper les caractères que vous recherchez, le résultat le plus récent s'affichera. Pour afficher des résultats plus anciens, réappuyez sur Ctrl-R. Quand vous avez trouvé la commande recherchée, vous pouvez la lancer avec Entrée, ou annuler la recherche avec Ctrl-C.
Tentons maintenant d'utiliser ces outils.
Q1. Affichez toutes les commandes "cd" que vous avez utilisées. Pensez à utiliser les outils vus dans le précédent TD.
Réponse : history | grep cd | less ("| less" est facultatif)
Q2. Avec Ctrl-R, retrouvez et exécutez la dernière commande "ls" que vous avez effectuée.
Réponse : Ctrl-R, puis "ls", puis _Entrée_.
Partie 2 - Gestion avancée de l'arborescence et des fichiers
Cette partie du TD se divise en trois sous-sections : l'archivage, des outils pratiques pour le suivi de votre compte UNIX à l'ENSTA, et la notion de droits d'accès. Commençons donc par l'archivage, avec la présentation de la commande tar, en deux versions :
tar -czvf archive.tar.gz fichiers
tar -xzvf archive.tar.gz
La première version permet de créer une archive appelée "archive.tar.gz" à partir de la liste de fichiers donnée par la suite des arguments, et la deuxième d'en extraire le contenu dans le dossier en cours. Pour donner la liste de fichiers à archiver, on peut évidemment utiliser les outils de sélection montrés précédement dans ce cours (par exemple, "*.csv" pour tous les fichiers ayant pour extension ".csv"). Si on donne un ou des noms de dossiers, leur contenu est inclus.
On remarque ici une façon compacte de donner des options à une commande : si chaque argument n'a qu'une lettre, ils peuvent être combinés en un seul bloc précédé d'un tiret. Ainsi, "-czvf archive.tar.gz" correspond à "-c -z -v -f archive.tar.gz" Voici la signification de chacun des arguments :
- -c, pour "create", indique que l'on souhaite créer une archive;
- -x, pour "extract", indique que l'on souhaite plutôt désarchiver cette archive;
- -z, pour "gzip", indique que l'on veut en plus compresser (ou décompresser) cette archive avec l'outil gzip;
- -v, pour verbose, indique que l'on veut voir la liste des fichiers inclus dans l'archive à l'écran au moment de l'archivage ou du désarchivage. Facultatif, mais pratique pour confirmer le contenu de l'archive;
- -f, permet de spécifier le nom du fichier de l'archive à créer ou désarchiver. L'argument qui suit immédiatement "f" est ce nom de fichier.
Vous voyez donc que l'outil tar permet à la fois d'archiver, compresser, décompresser et désarchiver des archives. En fait, tar fait plutôt appel à un autre outil, gzip, pour la compression. En effet, la commande "tar -czvf archive.tar.gz fichiers" correspond à "tar -cv fichiers | gzip > archive.tar.gz". C'est aussi pourquoi les archives ont l'extension ".tar.gz" : c'est une archive ".tar", compressée en format ".gz". L'idée est que gzip compresse un flux de données, et pas nécessairement une arborescence de fichiers. C'est le rôle de tar de conserver la structure de l'arborescence dans une archive. C'est une manifestation d'un concept important d'UNIX : on combine plusieurs petits utilitaires, tar et gzip, plutôt que d'en créer un seul immense. Cela permet également d'offrir d'autres format de compression, notamment "bzip", en remplaçant simplement gzip dans la commande (option "-j" de tar).
Il est maintenant le temps de se servir de cet outil. Commencez par récupérer l'archive pour ce TD, mais ne la désarchivez pas tout de suite :
Une fois téléchargée, l'archive devrait se trouver dans le dossier "Téléchargements" de votre dossier personnel.
Q3.a) À l'aide de la ligne de commande, commencez par transférer cette archive dans votre dossier mo101.
Réponse (si vous venez d'ouvrir un terminal et que vous êtes dans votre dossier personnel) : mv Téléchargements/archive_td3.tar.gz mo101/ Si vous êtes déjà dans le dossier Téléchargements : mv archive_td3.tar.gz ../mo101/ Ou de n'importe où : mv ~/Téléchargements/archive_td3.tar.gz ~/mo101/
Q3.b) À partir de votre dossier mo101, désarchivez l'archive du TD3 à la ligne de commande.
Réponse : tar -xzvf archive_td3.tar.gz
Vous devriez maintenant avoir son contenu dans un dossier "td3". Rendez-vous dans ce sous-dossier, et répondez à la prochaine question.
Q4. Archivez tous les fichiers "*.txt" dans une archive nommée "texte.tar.gz"
Réponse : tar -czvf texte.tar.gz *.txt
Tout au long de ce cours, nous avons manipulé des fichiers qui occupent très peu d'espace. Or, vous vous doutez sûrement que l'espace dont vous disposez sur les serveurs de l'ENSTA est limité. Pour connaître à la fois quel espace est utilisé et de combien on dispose, voici quelques outils pratiques :
- du : pour "disk usage", permet d'afficher l'espace occupé par un ou des fichiers. Sans arguments, la commande montre l'espace utilisé par le dossier en cours ainsi que tous ses sous-dossiers.
- ncdu : une version plus conviviale de du, où on peut parcourir le résultat de du à l'aide des flèches du clavier.
- df : pour "disk free", permet d'afficher l'espace libre des supports du système.
Dans le cas des commandes du et df, l'option "-h" (pour "human-readable") est conseillée, puisque l'affichage des tailles sera en unités de Ko, Mo et Go plutôt qu'en nombre de blocs de 1024 octets.
Q5. Affichez l'espace disque utilisé par le dossier "td3".
Réponse (à partir du dossier personnel) : du -h td3
Vous avez appris en amphithéâtre que l'accès aux fichiers est géré par une série de droits d'accès. En voici un cours rappel :
- Il y a trois catégories de droits d'accès selon à qui ils s'addressent : au propriétaire du fichier ("u", pour "user", ou "you"), au groupe du propriétaire ("g", pour "group"), et à tous les utilisateurs du système ("o", pour "others");
- Il y a trois types d'accès : lecture ("r", pour "read"), écriture ("w", pour "write"), et exécution ("x", pour "execute").
Nous allons voir deux commandes qui nous permettent de manipuler ces droits :
- ls -l (pour "long") : permet de lister plus de détails sur les fichiers du dossier en cours, dont les droits. Les droits sont affichés dans cet ordre : "u", "g", et "o";
- chmod {u|g|o}{+|-}{r|w|x} fichier : permet de changer les droits d'accès d'un fichier. Pour spécifier une modification, on utilise une syntaxe simple désignant à qui s'adresse le changement ("u", "g", ou "o"), si c'est un ajout ("+") ou un retrait ("-") de droit, et de quel type d'accès ("r", "w", "x"). Par exemple, la commande "chmod o-r fichier_interdit" retire le droit de lecture du fichier "fichier_interdit" aux autres utilisateurs du système.
Si ce n'est pas déjà fait, rendez-vous dans le dossier "td3" pour répondre aux prochaines questions.
Q7. Affichez les droits d'accès des fichiers dans "td3"
Réponse : ls -l
Q8. Ajoutez le droit d'exécution au propriétaire du fichier "bonjour.sh".
Réponse : chmod u+x bonjour.sh
Partie 3 - Manipulation des processus
Vous avez vu en amphithéâtre que chaque commande sous UNIX est un processus. En effet, la ligne de commande est un processus en soi qui lance de nouveaux processus pour chacune des commandes que vous lui donnez. Nous allons maintenant voir comment manipuler ces processus avec ces quelques combinaisons de touche et commandes :
- Ctrl-C : permet d'interrompre un processus;
- Ctrl-Z : permet de mettre en pause un processus et revenir au processus précédent (la ligne de commande);
- bg : pour "background", permet de redémarrer le dernier processus mis en pause, mais en arrière-plan (hors contrôle du clavier);
- fg : pour "foreground", permet de remettre au premier plan (sous contrôle du clavier) le dernier processus mis en arrière-plan.
- ps : pour "process status", affiche l'état des processus en cours du système. La commande affiche entre autre le numéro d'identification (PID) de chaque processus, son temps d'exécution, et la commande qui l'a démarré. Puisque votre système opère généralement des centaines de processus simultanément, l'affichage est automatiquement filtré pour votre session en cours. Utilisez l'outil man pour vous informer sur les différentes options d'affichage.
- kill : permet d'interrompre un processus, mais en le désignant par son PID.
Dans la partie précédente, vous avez donné des droits en exécution au fichier "bonjour.sh". Vous pouvez maintenant l'exécuter à partir du dossier td3 avec :
./bonjour.sh
Or, vous remarquerez qu'après vous avoir dit "bonjour", vous ne récupérez pas le contrôle de la ligne de commande. Explorons donc les outils présentés ci-dessus avec ces quelques questions :
Q9.a) Mettez le processus en pause et en arrière-plan.
Réponse : Ctrl-Z bg
Q9.b) Remettez le processus en premier-plan.
Réponse : fg
Q9.c) Interrompez le processus.
Réponse : Ctrl-C
Maintenant, vous pouvez redémarrer le processus et répondre à la dernière question :
Q10.a) Mettez le processus en pause.
Réponse : Ctrl-Z
Q10.b) Trouvez le PID de ce processus en arrière-plan.
Réponse : ps ou, pour plus de détails ps -f
Partie 4 - Scripts Shell
Quand on veut faire des opérations complexes qui utilisent une combinaison importante de commande Linux, il est possible de mettre ces commandes dans un fichier, c'est-à-dire "un script shell", qui va automatiser l'exécution de ces commandes.
De plus, le shell bash (et les autres shell aussi) possède des constructions similaires aux langages de programmation comme Python, C++. Il y a, en particulier, des structures conditionnelles, des boucles. L'objectif de cette partie est de vous présenter les principales constructions des scripts shell.
Q17.a) Un premier script
Afficher le contenu du script "arguments.sh"
Réponse : cat arguments.sh ou, pour naviguer facilement dans le fichier less arguments.sh Quelques commentaires sur ce premier script: - Par convention la première ligne d'un script bash commence par "#! " suivi du chemin vers l'interprète de commandes, i.e., le shell. - Il est possible de manipuler des variables dans les scripts shell (également dans le terminal !!). On donne une valeur à la variable "foo" en utilisant la syntaxe suivante "foo=expression". Le contenu de la variable "foo" est obetnu en ajoutant un symbole "$" devant le nom de la variable, c'est-à-dire, en écrivant "$foo". - Un script shell est capable de gérer des paramètres sur la ligne de commande et il existe différentes variables associées à ces paramètres.
Q17.b) Exécutez le script "arguments.sh" et observez le résultat
Réponse : Sans paramètres bash arguments.sh ou, avec paramètres bash arguments.sh a 1 b 2 c Note: En ajoutant les droits d'exécution au script "arguments.sh" (avec la commande "chmod u+x arguments.sh"), l'exécution du script se réalise en tapant la commande "./arguments.sh".
Q17.c) Etudiez et exécutez le script "expansion-variables.sh", que remarquez-vous ?
Réponse : En bash, une chaine de caractères peut être délimitée par des apostrophes ' ou des doubles guillemets ". Une variable utilisée dans une chaine délimitée par des doubles guillemets sera **expansée**, c'est-à-dire que le contenu de la variable sera affiché. A l'inverse les chaines des caractères entre apostrophes n'autorisent pas cette expansion.
Q18) Mon premier script
En vous inspirant du script "arguments.sh", écrivez un script shell nommé "arborescence.sh" qui crée, dans le répertoire "td3", l'arborescence de répertoires de la forme suivante.
td3
|-- bin/
|-- lib/
|-- var/
|-- log/
|-- msgs/
Réponse : #! /bin/bash mkdir bin lib var cd var mkdir log msgs ou en une seule ligne #! /bin/bash mkdir -p bin lib var/log var/msgs
Q19.a) La structure conditionnelle en shell
Une sctucture conditionnelle simple en Shell a la syntaxe suivante:
if commande
then
<faire quelque chose>
fi
"commande" doit renvoyer un code de retour pour savoir si elle a réussi ou si elle a échoué. Souvent on utilise la commande "test" qui permet de faire des comparaisons ou tester le type de fichier. Un raccourci existe pour la commande "test" qui est la notation crochet "[ ]" mais qui demande que le crochet ouvrant "[" soit suivi d'un espace et que le crochet fermant "]" soit précéder d'un espace donc de la forme "[ expression ]" !!
Par exemple, si on veut savoir si le premier paramètre d'un script est plus grand que 10 on peut écrire
#! /bin/bash
if [ $1 -gt 10 ]
then
echo "Plus grand que 10"
fi
Un court extrait de la page "man" de la commande "test" vous donne les opérateurs de comparaisons importants pour ces exercices
- arg1 OP arg2 : OP est dans la liste -eq, -ne, -lt, -le, -gt, ou -ge. Ces opérateurs arithmétiques renvoient vrai si arg1 est égal, différent, inférieur, inférieur ou égal, supérieur, ou supérieur ou égal à arg2, respectivement. arg1 et arg2 doivent être des entiers (positifs, ou négatifs)
- -d fichier : Vrai si le fichier existe et est un répertoire.
- -f fichier : Vrai si le fichier existe et est un fichier ordinaire.
Ecrivez un script shell, nommé "est_repertoire.sh", qui prend en paramètre un nom de fichier et affiche si le fichier est en réalité un dossier.
Réponse : #! /bin/bash if [ -d $1 ] then echo $1 : est un dossier fi
Q19.b) Compétez le script précédent pour tester si le paramètre est un dossier seulement si le nombre d'arguments du script est strictement positif.
Réponse : #! /bin/bash if [ $# -gt 0 ] then if [ -d $1 ] then echo $1 : est un dossier fi fi
Q20.a) La boucle en shell
Une boucle "for" en bash a la syntaxe suivante
for ident in liste_valeurs
do
instructions
done
"ident" est un nom de variable. "instructions" représente un ensemble de commandes. Cette boucle applique un traitement sur chaque élément de la liste "liste_valeurs", c'est le même genre de boucle "for" que celle de Python.
Par exemple, on peut afficher cinq fois bonjour avec le script suivant :
#! /bin/bash
for INDEX in 1 2 3 4 5
do
echo "Bonjour"
done
En vous inspirant de cet exemple, écrire un script "creer_fichiers.sh" qui crée 5 fichiers vides avec un nom de la forme "fichier_1.txt", "fichier_2.txt", ..., "fichier_5.txt"
Réponse : #! /bin/bash for INDEX in 1 2 3 4 5 do touch fichier_$INDEX.txt done
Q20.b) La boucle en shell, suite
Il est possible d'utiliser le résultat d'une commande pour créer la liste de valeurs "liste_valeurs" en paramètre de la boucle "for", par exemple, si on veut faire un traitement sur des fichiers ou répertoires. Cependant, il est nécessaire d'utiliser une syntaxe particulière pour récupérer le résultat d'une commande, celle-ci est la notation "$()".
Par exemple, pour faire un script qui a le même rôle que la commande "ls" on pourrait écrire
#! /bin/bash
for FICHIER in $(ls)
do
echo $FICHIER
done
La commande "seq" (cf "man seq") permet de générer des suites de valeurs entières, par exemple, "seq 1 10" génère la liste des dix premiers entiers strictement positifs. Plus précisément, la commande "seq" prend en paramètre le nombre qui débute la séquence et le nombre qui termine la séquence.
Reprenez le scripts de la question Q15.a) pour générer 100 fichiers.
Réponse : #! /bin/bash for i in $(seq 1 100) do touch fichier_$i.txt done
Q21) Un peu de calculs
Le shell Bash est spécialisé dans la manipulation de fichiers et dossiers mais est capable de calculer un peu, essentiellement avec les entiers. Pour calculer il faut utiliser la commande "expr" (cf "man expr") qui permet d'évaluer des expressions, arithmétique ou sur les chaines de caractères. Pour nos besoins nous nous limiterons aux expressions arithmétiques dont la forme est la suivante :
- arg1 OP arg2 : arg1 et arg2 sont des variables ou constantes entières et OP est un opérateur arithmétique "+,-,*,".
Ecrire un script, nommé "successeur.sh", qui ajoute un au premier paramètre du script.
Réponse : #! /bin/bash RES=$(expr $1 + 1) echo Le successeur de $1 est $RES
Q22) Mélanger boucle et conditionnelle
Ecrivez un script, nommé "statistiques.sh", qui affiche le nombres de fichiers et de répertoires contenus dans le répertoire courant.
Réponse : #!/bin/bash NBFILE=0 NBDIR=0 for ELEM in $(ls) do if test -f $ELEM then NBFILE=$(expr $NBFILE + 1) elif test -d $ELEM then NBDIR=$(expr $NBDIR + 1) fi done echo "There are $NBFILE files" echo "There are $NBDIR directories"
Partie 6 - Expresssions rationnelle
Une expressions régulière ou expression rationnelle est une chaine de caractères qui décrit un ensemble de chaines de caractères. Elle utilise une syntaxe particulière pour décrire différentes classes de caractères qui composent l'ensemble de chaines de caractères. Il existe plusieurs types de langage d'expressions régulières, nous allons ici considérer un sous ensemble des ERE (Extended Regular Expression). La commande "grep" (Grind Regular Expression) est capable d'utiliser des expressions régulières pour faire de la recherche de chaines de caractères dans un fichier (cf "man grep").
Une expression rationnelle est composée :
- de caractères ordinaires
- de méta-caractères : ., *, +, ?, ^, $, |, (), [] ?
Exemples :
- "foo" : reconnait toutes les chaines de caractères contenant foo
- "(foo|foobar)" : toute chaîne de caractères qui contient le mot foo ou le mot foobar
- "ˆfoo" : toute chaîne de caractères qui commencent par foo
- "foo$" : toute chaîne de caractères qui finit par foo
- "ˆfoo$" : seul le mot foo est reconnu, rien ne peut le précéder ni le suivre dans la chaîne de caractères
- "f.o" : ‘.’ désigne n’importe quel caractère, toute chaîne de caractéres qui contient f puis un caractère puis o
- "f[mnopq]o" : tous les caractères de la liste mnopq entre crochets autorisés à cet emplacement
- "f[m-p]o" : [m-p] tous les caractères de l’intervalle de caractères entre m et p
- "f[ˆa-lR-W0-9]o" : [ˆa-lR-W0-9] reconnaît tous les caractères autres que ceux de la liste de séquences indiquées
- "a*" : reconnaît 0 fois ou plus de a
- "(..)+" : reconnait 1 fois ou plus de .. soit un nombre pair non nul de caractères
- "f[o]+" ou "foo*" : reconnaît f suivi d'au moins 1 fois o
- "foo(bar)?" ou foo(|bar) : reconnait foo suivi de bar 0 ou 1 fois (alternative)
A noter que les opérateurs * et + sont gourmands, c'est-à-dire qu'ils essaieront toujours de reconnaitre la chaine de caractères la plus longue.
Pour cette suite de questions, nous allons utiliser l'annuaire téléphonique qui est dans le fichier "annuaire.txt".
Q23) Trouvez toutes les entrées de l'annuaire dont le prénom est Mila
Réponse : grep -E "Mila" annuaire.txt Note : pour activer l'utilisation des ERE dans grep il faut ajouter l'option -E.
Q24) Trouvez toutes les entrées de l'annuaire dont le numéro de téléphone termine par 1.
Réponse : grep -E "1$" annuaire.txt Note : pour activer l'utilisation des ERE dans grep il faut ajouter l'option -E.
Q25) Trouvez toutes les entrées de l'annuaire dont le nom de famille commence par M.
Réponse : grep -E "^M" annuaire.txt
Q26) Trouvez toutes les entrées de l'annuaire dont le nom de famille commence par B et dont le numéro de téléphone termine par le chiffre 7.
Réponse : grep -E "^B.*7$" annuaire.txt
Q27) Trouvez toutes les personnes qui ont "Bertrand" comme nom de famille et dont le numéro de téléphone commence par "03"
Réponse : grep -E "Betrand.* 03" annuaire.txt Note : attention à l'espace avant le 03
Q28) Trouvez toutes les entrées de l'annuaire dont le numéro de téléphone possède une répétition du numéro 3 supérieur à 2.
Réponse : grep -E "33+" annuaire.txt
Q29) Trouvez toutes les entrées de l'annuaire dont le prénom commence par un L et termine par un m.
Réponse : grep -E " L.+m " annuaire.txt Note : attention aux espaces avant L ou après m sinon on peut avoir un nom de famille qui commence par L et un prénom qui finit par m ou une autre solution grep -E "L[^ ]+m" annuaire.txt
Q30) Trouvez toutes les entrées de l'annuaire dont le nom de famille est "Durand" et dont le prénon est soit Jules, Louis ou Emma.
Réponse : grep -E "Durand (Jules|Louis|Emma)" annuaire.txt