Ce sujet de TP comporte quelques "mini projets" qui utilisent certaines des notions vues en cours, TD ou TP. L'objectif est de réaliser 1 ou 2 (ou même plus) de ces mini projets.
Avant de commencer un des projet, il est impératif de faire la section Préliminaires.
Le rendu du TP consistera en une archive (fichier .zip
, .tar
, etc.)
comportant votre travail.
README
qui contiendra
README
principal répondant à la question 1.
Attention, les fichiers README
seront pris en compte pour l'évaluation du TP...
sujet plus graduel :
.bashrc
L'objectif de ce TP est de réaliser, en "autonomie", des scripts utilisant les notions utilisés dans les TP précédents. Les mini projets proposés ont été choisis soit pour illustrer spécifiquement des points importants, soit parce qu'ils correspondent à des vrais besoins.
(répondre à cette question juste avant d'envoyer votre dernière soumissions !)
mon_premier_script.sh
, lisez le et testez le.
affiche_fichiers
, écrivez une fonction types
qui, pour chacun de ses argument, affiche son type :
$ source mon_premier_script.sh $ types * uhesantuhensa Bureau : dossier info202 : dossier lettre.txt : fichier tmp : dossier uhesantuhensa : inconnu
Lorsque je travaille dans un terminal, certains répertoires reviennent très
souvent. C'est par exemple le cas de mon dossier personnel. Le shell offre un
raccourci pour se déplacer dans le dossier personnel : la commande cd
sans
argument.
Je ne peux par contre pas sauvegarder d'autre répertoires "favoris" pour pouvoir m'y déplacer facilement.
L'objectif de ce mini projet est de créer un petit système de "favoris" pour vos répertoires importants.
Votre script devra fournir 4 fonctions :
S
(Save) pour sauvegarder un nouveau favori. Cette fonction prend un
argument (une chaine sans espace) et ajoute le répertoire courant dans votre
liste de favoris.
C
(Change) pour se déplacer dans un répertoire favori. Cette fonction
prend un argument (un chaine sans espace) et cherche dans vos favoris. Si
le favori existe, la fonction change le répertoire de travail, sinon, elle
ne fait rien.
R
(Remove) pour supprimer un favori de la liste.
L
(List) pour afficher la liste de tous les favoris.
Exemple d'utilisation
$ source favoris.sh $ pwd /home/hyvernat/info202/TP/sujets/TP5 $ S info202-5 Le répertoire /home/hyvernat/info202/TP/sujets/TP5 est sauvegardé dans vos favoris. -> raccourci : info202-5 $ cd $ pwd /home/hyvernat/ $ C info202-5 Vous êtes maintenant dans le répertoire /home/hyvernat/info202/TP/sujets/TP5. $ pwd /home/hyvernat/info202/TP/sujets/TP5 $ R info202-5 Le favoris "info202-5" est supprimé de votre liste. $ cd $ C info202-5 Le favoris "info202-5" n'existe pas.
Votre script utilisera un fichier (caché) .favoris_bash
qui sera créé dans votre dossier personnel. Ce fichier contiendra une ligne par favori. Chaque ligne contiendra
Pour simplifier la gestion de ce fichier, il est conseillé de le définir dans une variable au début de votre script:
FAV=$HOME/.favoris_bash
Note : la variable HOME
contient le chemin absolu vers votre dossier personnel...
Pour manipuler le fichiers de favoris, il faudra utiliser les choses suivantes.
grep
qui permet d'afficher les lignes contenant une chaine
de caractères donnée. Remarque, si on veut imposer que la chaine
cherchée se trouve en début de ligne, on peut la préfixer par le
symbole ^ :
grep "abc"
donne toutes les lignes qui contiennent abc
,
grep "^abc"
donne toutes les lignes qui commencent par abc
.
grep
sont disponibles dans liste des commandes du shell
CMD > FICHIER
et CMD >> FICHIER
qui permettent de
FICHIER
par le résultat d'une commande,
FICHIER
.
Attention, il n'est en général pas possible de rediriger le résultat d'une commande sur un fichier dans le même fichier. Par exemple,
$ grep "CHAINE" fichier > fichier
n'aura pas l'effet attendu car la redirection > fichier
supprime le contenu avant que la commande grep "CHAINE" fichier
ne commence.
Pour faire ceci, il faut donc rediriger la commande dans un autre fichier temporaire, et remplacer ensuite le fichier d'origine par ce fichier temporaire.
C info202
utilisera le favori info202-5
s'il existe. La commande C
devra donc
L
afin de ne lister que les favoris contenant une chaine de caractères.
Pour éviter d'oublier des choses importantes à faire, je voudrais garder une une liste dans mon ordinateur. J'aimerais pouvoir ajouter des tâches, les lister, et en supprimer.
Remarque: je pourrais également utiliser cette fonctionnalité pour garder :
Le script doit fournir une unique fonction todo
qui offre 3 fonctionnalités :
Voici un exemple d'utilisation :
$ source todo.sh $ todo list 1 - finir TP d'info202 2 - téléphoner à tata 3 - inviter Edith à manger 4 - passer la serpillère dans l'entrée $ todo done 1 La tâche 1 (finir TP d'info202) est faite ! $ todo list 1 - téléphoner à tata 2 - inviter Edith à manger 3 - passer la serpillère dans l'entrée $ todo add 2 réviser la chimie La tâche "réviser la chimie" a été ajoutée en position 2. $ todo list 1 - téléphoner à tata 2 - réviser la chimie 3 - inviter Edith à manger 4 - passer la serpillère dans l'entrée
Votre fonction devra analyser son premier argument afin de décider quelle opération effectuer. Il faudra donc se reporter à la section arguments individuels d'une fonction et la description des conditionnelles.
La liste des tâche doit être sauvegardée dans un fichier (caché) .todo_list
qui
sera stocké dans votre dossier personnel. Ce fichier contiendra une ligne par
tâche, sans numéro.
Pour simplifier la gestion de ce fichier, il est conseillé de le définir dans une variable au début de votre script:
TACHES=$HOME/.todo_list
Note : la variable HOME
contient le chemin absolu vers votre dossier personnel...
Pour manipuler les tâches, il faudra utiliser les choses suivantes.
nl
permet d'afficher les lignes d'un fichier, en ajoutant
un numéro de ligne. Il est possible d'ajouter un séparateur entre le numéro
et la ligne si vous le souhaitez (voir man nl
pour les détails).
n
, il faudra :
n-1
premières taches dans un fichier temporaire avec la commande head
et une redirection >
,
echo
et une redirection >>
,
n
dans le fichier temporaire avec la commande tail
et une redirection >>
,
n
, il faudra
n-1
premières taches dans un fichier temporaire avec la commande head
et une redirection >
,
n+1
dans le fichier temporaire avec la commande tail
et une redirection >>
,
J'aimerais bien avoir des statistiques sur mes fichiers :
Le script devra fournir une fonction qui analyse le contenu du répertoire courant et de ses sous-répertoires et afficher des statistiques. La quantité de détails dépendra de la valeur de l'argument donné à la fonction :
1
(ou pas d'argument) : peu de détails
2
: un peu plus de détails
3
: beaucoup de détails
Voici un exemple d'exécution
$ pwd /home/hyvernat/info202/ $ statistiques Analyse de /home/hyvernat/info202/ : - 45 répertoires - 114 fichiers - taille totale : 18M $ statistiques 2 Analyse de /home/hyvernat/info202/ : - 45 répertoires - 1 répertoire caché - 0 répertoire vide - 114 fichiers dont - 3 fichiers cachés - 1 fichier vide - taille totale : 18M $ statistiques 3 Analyse de /home/hyvernat/info202/ : - 45 répertoires - 1 répertoire caché - 0 répertoire vide - 114 fichiers dont - 3 fichiers cachés - 1 fichier vide - 87 fichiers de moins de 512kio - 0 fichier de plus de 15Mio - le plus gros fichier est /home/hyvernat/info202/CM1/Img/RAM_old-plane_4k.jpg Il y a : - 5 fichiers Python - 17 fichiers image - 0 fichier vidéo - taille totale : 18M
L'ingrédient principal de cette fonction sera la commande find
et des
redirections CMD1 | CMD2
. Vous pouvez vous reporter aux sections
pertinentes dans la liste des commandes du shell.
Il n'est pas nécessaire d'écrire des boucles pour cette fonction : chaque information peut être calculée directement avec une commande shell. Par exemple, voila une manière simple de compter le nombre de répertoires vides :
$ find -type d -empty | wc -l
Pour le reste, reportez vous aux sections suivantes avant de commencer :
Pour vérifier la valeur de l'argument, il faudra se référer à :
J'ai quelques photos que je souhaite partager facilement sur ma page Internet. J'aimerais générer une petite page HTML qui affiche des petites vignettes. Un clic sur une de ces vignette devra afficher la photo originale...
La fonction devra prendre une liste de fichiers images en arguments et
Voici un exemple d'exécution :
$ source ./galerie.sh $ galerie *.??? inclusion de l'image Gerbil1.jpg inclusion de l'image Gerbil2.png inclusion de l'image Jaculus_orientalis.jpg inclusion de l'image Jerboa.png inclusion de l'image Meriones_unguiculatus.jpg inclusion de l'image Springharelg.jpg
et vous pouvez voir le résultat ici. (Pour voir le contenu du fichier, vous pouvez faire afficher le code source de la page...)
Vous pouvez utiliser les photos de cette archive (prises sur Wikipedia) pour tester votre fonction.
Il va falloir faire des boucles sur les arguments d'une fonction.
$ convert FICHIER -resize 128x128 VIGNETTE
imagemagick
.)
echo
avec une redirection >>
.
<!DOCTYPE html> <html> <head> <title>TITRE</title> <meta http-equiv="Content-Type" content="text/html; charset=utf-8"/> </head> <body> CODE HTML </body> </html>
TITRE
est le titre de la page et CODE HTML
est le contenu HTML de la page.
<ul> <li><a href="IMAGE1"><img src="VIGNETTE1"></a></li> <li><a href="IMAGE2"><img src="VIGNETTE2"></a></li> <li><a href="IMAGE3"><img src="VIGNETTE3"></a></li> <li><a href="IMAGE4"><img src="VIGNETTE4"></a></li> </ul>
Les photos prises par mon téléphone ont des noms pas très jolis :
IMG_20160312_124305306.jpg
, etc.. Pour les archiver, j'aimerais les
renommer en WeekEnd_2016-02-12_16-35-12.jpg
,
WeekEnd_2016-02-12_16-36-24.jpg
, etc.
Dans l'exemple précédent, c'est l'utilisateur qui choisit explicitement le
préfixe WeekEnd
. La date et l'heure sont automatiquement ajoutées au nom de fichier.
Voici un exemple d'utilisation :
$ source ./renomme.sh $ ls *.jpg IMG_123456789.jpg IMG_928332498.jpg IMG_987654321.jpg $ renomme Lac *.jpg IMG_123456789.jpg ==> Lac_2015-08-30_16-52-52.jpg IMG_928332498.jpg ==> Lac_2015-09-04_16-34-07.jpg IMG_987654321.jpg ==> Lac_2015-08-30_16-53-27.jpg $ ls *.jpg Lac_2015-08-30_16-52-52.jpg Lac_2015-08-30_16-53-27.jpg Lac_2015-09-04_16-34-07.jpg
Vous pouvez utiliser les photos de cette archive (prises sur Wikipedia) pour tester votre fonction.
Reportez vous aux sections
Vous aurez besoin de récupérer l'extension d'un fichier contenu dans une variable. Pour ceci, l'incantation magique suivante convient : si la variable s'appelle img
, on peut faire
ext=${img##*.}
Attention, dans le shell, le symbole _
peut faire partie du nom d'une
variable. Pour cette raisson, $img_$prefix
ne sera pas interprété comme "la
variable $img
suivie d'un _
suivi de la variable $prefix
", mais
comme "la variable $img_
(qui n'existe probablement pas) suivie de la
variable $prefix
". La solution est de mettre le nom de la variable entre
accolades : ${img}_$prefix
.
La galerie photo de mon téléphone Android affiche les photos par date de modification des fichiers. Lors de la restauration d'une sauvegarde, les fichiers sont recréés et les photos sont donc affichées dans le désordre.
Comme la date de prise de la photo se trouve dans le fichier (données "EXIF"), j'aimerais écrire un script pour remettre de l'ordre dans tout ça.
Il s'agit d'écrire une fonction shell qui prend une liste de fichiers en arguments et change la date de modification de chacun de ces fichiers en fonction des informations EXIF (Exchangeable image file format).
Si ces informations ne sont pas présentes, les méta-données des fichier ne sont pas modifiées.
Voici un exemple d'exécution :
$ source maj_dates.sh $ ls -tr *.jpg Belledonne_soleil.jpg Belledonne.jpg Bauges_Mont_Blanc.jpg Bauges_Belledonnes.jpg Bauges.jpg $ maj_dates *.jpg Modification du fichier Bauges.jpg Modification du fichier Bauges_Belledonnes.jpg Modification du fichier Bauges_Mont_Blanc.jpg Modification du fichier Belledonne.jpg Modification du fichier Belledonne_soleil.jpg Fin de la fonction $ ls -tr *.jpg Belledonne.jpg Bauges.jpg Bauges_Belledonnes.jpg Bauges_Mont_Blanc.jpg Belledonne_soleil.jpg
Note, ls -tr
permet d'afficher la liste des fichiers dans l'ordre
chronologique de dernière modification.
Vous pouvez utiliser les photos de cette archive (prises sur Wikipedia) pour tester votre fonction.
Commencez par lire les sections suivantes :
touch
. Les commandes cut
et tr
peuvent
être utiles : commandes cut et tr
Un script shell est un petit programme écrit dans le langage du shell. C'est un fichier contenant des commandes et des constructions similaires à celles trouvées dans les langages de programmation plus "évolués".
La première ligne d'un tel fichier doit être
#!/bin/bash
afin que le système le reconnaisse comme script shell.
On peut définir une fonction dans un script bash de la manière suivante :
function test() { CMD1 CMD2 CMD3 ... }
Cela permet d'ajouter une commande : une fois que le fichier est lu par le shell, par exemple par
$ source FICHIER
la commande test
effectuera les commandes CMD1
, CMD2
, etc.
Comme avec Python et Idle, le fait d'avoir écrit une fonction n'est pas suffisant pour pouvoir l'exécuter. Il faut "charger" le fichier contenant la définition des fonctions avant de pouvoir les utiliser.
Avec Idle, il fallait choisir le menu "Run", "Run module" (ou le raccourci clavier "F5").
Dans le shell, on peut charger un fichier avec la commande
$ source FICHIER
D'autres fonctionnalités intéressantes sont :
echo
echo
echo "FIN de la fonction "
=
:
var="..."
=
.
Pour utiliser la valeur d'une variable, il faut précéder son nom du signe $
echo "La valeur de var est $var"
var=$(CMD)
CMD
est la commande à exécuter.
if
. La
syntaxe est
if [ TEST ] then ... elif [ TEST ] then ... elif [ TEST ] then ... else ... fi
[
et
avant le symbole ]
!
TEST
est une condition, qui porte en général sur des variables :
-z "$var"
pour tester si la variable est vide ou non,
-f "$var"
pour tester si la variable contient un nom de fichier qui existe,
"$var" == "hello"
pour tester si la variable contient la chaine hello
,
$ man test
Les boucles du langage bash ressemblent à
for i in LIST do ... done
où LIST
est une liste de chaines, séparées par des espaces. Par exemple
$ for i in chat chien souris > do > echo "animal : $i" > done animal : chat animal : chien animal : souris
Les arguments d'une fonction sont automatiquement mis dans une variable spéciale
appelée $@
. Si le fichier script.sh
contient
#!/bin/bash function animaux() { for a in "$@" do echo "animal : $a" done echo "FIN de la fonction" }
alors l'exécution donne
$ source script.sh $ animaux chat chien chauve souris canard animal : chat animal : chien animal : chauve animal : souris animal : canard FIN de la fonction $ animaux FIN de la fonction
Comme expliqué dans la section boucle sur les arguments d'une fonction, la liste des arguments d'une fonction est appelée $@
.
Pour accéder aux premiers arguments individuellement, il faut utiliser les
variables $1
, $2
, ... $9
.
Pour accéder aux arguments suivants (après le numéro 9), il faut "décaler" les
arguments. La commande shift
supprime le premier argument et décale les
suivants. Ainsi, après un shift
, la variable $1
contient l'argument
numéro 2, etc.
Par exemple, si le fichier args.sh
contient
#!/bin/bash function montre_args() { echo "Tous les arguments : $@" echo "Argument 1: $1" shift echo "Autres arguments : $@" }
on aura
$ source ./args.sh $ montre_args ananas pomme poire kiwi Tous les arguments : ananas pomme poire kiwi Argument 1: ananas Autres arguments : pomme poire kiwi
Les calcul arithmétique en bash doivent obligatoirement se trouver dans un $((...))
.
$ echo "1 + 2" 1 + 2 $ echo "$((1 + 2))" 3
On peut utiliser des variables, et stocker le résultat dans une variable:
$ V=117 $ echo "la valeur de V est $V" la valeur de V est 117 $ V=$(( $V / 2 )) $ echo "la valeur de V est $V" la valeur de V est 58
Attention le résultat d'une opération arithmétique n'est pas une commande :
$ $((1 + 2)) bash: 3 : commande introuvable
Les commandes head
et tail
permette de récupérer des lignes au début ou à la fin d'un fichier :
head FICHIER
affiche par défaut les 10 premières lignes de FICHIER
. Il est possible de changer cette valeur avec head -n N FICHIER
. Pour afficher toutes les lignes, sauf les N
dernières, on peut utiliser head -n -N FICHIER
.
tail FICHIER
affiche par défaut les 10 dernières lignes de FICHIER
. Il est possible de changer cette valeur avec tail -n N FICHIER
. Pour afficher toutes les lignes à partir de la N
ème, on peut utiliser tail -n +N FICHIER
.
La commande touch
permet de modifier la date de dernier accès et date de
dernière modification d'un fichier :
$ ls -l examen.pdf -rw-r--r-- 1 hyvernat hyvernat 114087 2017-04-10 09:58:14 examen.pdf $ touch -t 200902132331.30 examen.pdf -rw-r--r-- 1 hyvernat hyvernat 114087 2009-02-13 23:31:30 examen.pdf $ touch examen.pdf -rw-r--r-- 1 hyvernat hyvernat 114087 2017-04-24 09:38:44 examen.pdf
La date donnée à touch
a la forme SSAAMMJJhhmm.ss
, où SS
(siècle),
AA
(année) et .ss
(seconde) sont facultatifs.
La commande tr
permet de modifier certains caractères, ou d'en supprimer.
Cette commande agit sur l'entrée standard :
$ echo "giraffe" | tr "abcde" "ABCDE" girAffE
-d
$ echo "giraffe" | tr -d "abcde" girff
a
, b
, c
, d
et e
de la chaine giraffe
, on obtient girff
.
La commande cut
permet de récupérer seulement certaines parties d'une
chaine : on précise un délimiteur, les numéros des champs qui nous intéressent.
Cette commande agit sur l'entrée standard :
echo "Hello World !" | cut -d" " -f2 World
RR,GG,BB
echo "b0,62,bf" | cut -d"," -f1,3 b0,bf
La commande file
essaie de deviner le type des fichiers donnés en argument :
$ file test.py log tmp TP4 Lac.jpg test.py: Python script, ASCII text executable log: ASCII text tmp: empty TP4: directory Lac.jpg: JPEG image data, JFIF standard 1.01, resolution (DPI), density 72x72, segment length 16, Exif Standard: [TIFF image data, big-endian, direntries=14], baseline, precision 8, 320x480, frames 3
Il est possible d'afficher un type de fichier plus succinct : le type MIME en donnant l'option -i
à la commande :
$ file -i test.py log tmp TP4 Lac.jpg test.py: text/x-python; charset=us-ascii log: text/plain; charset=us-ascii tmp: inode/x-empty; charset=binary TP4: inode/directory; charset=binary Lac.jpg: image/jpeg; charset=binary
Il n'est parfois pas nécessaire d'afficher le nom du fichier. Cela se fait en ajoutant l'option -b
:
$ file -bi test.py log tmp TP4 Lac.jpg text/x-python; charset=us-ascii text/plain; charset=us-ascii inode/x-empty; charset=binary inode/directory; charset=binary image/jpeg; charset=binary
La commande du
(disk usage) prend une liste de fichiers en argument et
affiche la taille occupée (en Kio) par chaque fichier. L'option -c
permet
d'afficher également l'espace total utilisé par les fichiers et l'option -h
permet d'afficher un taille en utilisant des unités "raisonnables" (k, M, G).
Par exemple :
$ du -ch *.html *.pdf 12K Fabrication d'un micro-processeur.html 56K cours.html 2.2M 2I010_2016_support.pdf 12K survie.pdf 12K t.pdf 2.3M total
Attention, sans aucun argument, la commande du
calcule la taille
occupée par tous les fichiers contenu dans le répertoire courant et ses
sous-répertoires.
Les données EXIF peuvent contenir de nombreuses informations renseignées par l'appareil photo :
exiftool
est un utilitaire qui permet de récupérer ces informations
$ exiftool Bauges.jpg ... Create Date : 2011:08:11 12:41:02.00 Shutter Speed Value : 1/200 ... Flash : No Flash Focal Length : 32.0 mm ...
Il est possible de récupérer un unique champs de la manière suivante :
$ exiftool -CreateDate Bauges.jpg Create Date : 2011:08:11 12:41:02.00
L'option -b
est utile dans les scripts car elle permet de récupérer seulement la valeur du champs :
$ exiftool -b -CreateDate Bauges.jpg 2011:08:11 12:41:02.00$
Si la commande exiftool
n'existe pas sur votre système, vous pouvez :
libimage-exiftool-perl
(Debian / Ubuntu) si vous avez les droits administrateurs,
exiftool-10-50
(http://www.sno.phy.queensu.ca/~phil/exiftool/) et :
$ tar zxvf Image-ExifTool-10.50.tar.gz
$ alias exiftool="CHEMIN/Image-ExifTool-10.50/exiftool"
CHEMIN
est le chemin absolu de téléchargement.
(Attention, si vous fermez votre terminal ou votre session, il faudra recréer l'alias.)
-