De quelle version de Perl disposez-vous ?
vanvincq@CP2L ~/Bureau/CPLL/JournalDeBord $ perl -v
This is perl, v5.10.1 (*) built for x86_64-linux-gnu-thread-multi
(with 56 registered patches, see perl -V for more detail)
Copyright 1987-2009, Larry Wall
Perl may be copied only under the terms of either the Artistic License or the
GNU General Public License, which may be found in the Perl 5 source kit.
Complete documentation for Perl, including FAQ lists, should be found on
this system using "man perl" or "perldoc perl". If you have access to the
Internet, point your browser at http://www.perl.org/, the Perl Home Page.
Écrivez une fonction bonjour qui prend le prénom d'une personne en paramètre et qui lui souhaite bonjour. L'appel bonjour('Julie') affichera Bonjour Julie ! à l'écran.
#!/usr/bin/perl -w use strict; # simple fonction de salutations sub bonjour { my ($prenom) = @_; # un argument attendu print "Bonjour $prenom !\n"; } bonjour('Clément');
vanvincq@CP2L ~/Bureau $ ./bonjour.pl
Bonjour Clément !
Dans une deuxième étape, testez si la fonction est appelée sans paramètre : bonjour(). Dans ce cas l'affichage suivant sera Bonjour belle inconnue !
#!/usr/bin/perl -w use strict; # simple fonction de salutations sub bonjour { my ($prenom) = @_; # un argument attendu if (defined($prenom)) { print "Bonjour $prenom !\n"; } else { print "Bonjour belle inconnue !\n"; } } bonjour('Clément'); bonjour();
vanvincq@CP2L ~/Bureau $ ./bonjour.pl
Bonjour Clément !
Bonjour belle inconnue !
Dans une dernière étape, faite en sorte de pouvoir donner le prénom de votre belle en argument de votre script (tableau @ARGV) et de le passer en paramètre à votre fonction.
#!/usr/bin/perl -w use strict; # simple fonction de salutations sub bonjour { my ($prenom) = @_; # un argument attendu if (defined($prenom)) { print "Bonjour $prenom !\n"; } else { print "Bonjour belle inconnue !\n"; } } bonjour('Clément'); bonjour(); bonjour(@ARGV);
vanvincq@CP2L ~/Bureau $ ./bonjour.pl Chloé
Bonjour Clément !
Bonjour belle inconnue !
Bonjour Chloé !
Écrivez une fonction TableMult qui affiche la table de multiplication de 1 à n en utilisant foreach. Les colonnes pourront être alignées sur cinq caractères à l'aide de la fonction printf, par exemple vous pouvez utiliser printf("%5s,...");
#!/usr/bin/perl -w sub TableMult { my ($chiffre) = @_; foreach my $i (1..$chiffre) { foreach my $j (1..$chiffre) { printf("%5d", $j*$i); } print "\n"; } } TableMult(@ARGV);
vanvincq@CP2L ~/Bureau $ ./tableMultiplication.pl 8
1 2 3 4 5 6 7 8
2 4 6 8 10 12 14 16
3 6 9 12 15 18 21 24
4 8 12 16 20 24 28 32
5 10 15 20 25 30 35 40
6 12 18 24 30 36 42 48
7 14 21 28 35 42 49 56
8 16 24 32 40 48 56 64
Écrire un programme qui successivement :
crée un tableau contenant 1, 2 et 3,
ajoute 4 puis 5 à la fin du tableau,
affiche le tableau (les éléments seront séparés par des espaces),
ajoute 0 puis -1 au début du tableau,
remplace la valeur d'indice 3 par 9,
multiplie par 2 chaque terme du tableau (fonction map),
ne garde dans le tableau que les termes positifs (fonction grep),
trie le tableau par ordre décroissant (fonction sort).
#!/usr/bin/perl -w # Création du tableau my @tableau = (1, 2, 3); # Ajout de 4 et 5 à la fin du tableau push(@tableau, 4, 5); # Affichage du contenu (en utilisant le foreach) foreach (@tableau) { print "$_ "; } print "\n"; # Ajout de 0 et -1 au début du tableau unshift(@tableau, -1, 0); print "@tableau\n"; # Remplace la valeur d'indice 3 par 9 $tableau[3] = 9; print "@tableau\n"; # Multiplie chaque élément du tableau par 2 map { $_ *= 2 } @tableau; # ou @tableau = map { $_ * 2 } @ tableau; print "@tableau\n"; # Ne garder que les termes > 0 @tableau = grep { $_ > 0 } @tableau; print "@tableau\n"; # Trie décroissant @tableau = sort( { $b <=> $a } @tableau); print "@tableau\n";
vanvincq@CP2L ~/Bureau $ ./tableau.pl
1 2 3 4 5
-1 0 1 2 3 4 5
-1 0 1 9 3 4 5
-2 0 2 18 6 8 10
2 18 6 8 10
18 10 8 6 2
Écrivez une fonction Diviseurs qui calcul et affiche tous les diviseurs d'un nombre passé en paramètre (utilisez l'opérateur modulo).
#!/usr/bin/perl -w sub Diviseurs { my ($entier) = @_; print "Liste des diviseurs de $entier :\n"; foreach my $i (1..$entier) { if ($entier % $i == 0) { printf("%d\n", $entier/$i); } } } Diviseurs(@ARGV);
vanvincq@CP2L ~/Bureau $ ./diviseurs.pl 10054965
Liste des diviseurs de 10054965 :
10054965
3351655
2010993
670331
44295
14765
8859
3405
2953
1135
681
227
15
5
3
1
Écrire un programme qui :
Place dans un tableau la liste des fichiers et répertoires de votre home.
Ne conserve dans ce tableau que les executables (droit Unix 'x') (fonction Grep).
Trie ce tableau par ordre de taille de fichier (attention à ne pas confondre la taille du nom de fichier).
Place dans un second tableau la taille respective de chaque fichier du tableau (fonction map).
#!/usr/bin/perl -w # Récupération de tous les fichiers et répertoires du /home my @mesFichiers = glob('~/.* ~/*'); # On ne garde que les exécutables @mesFichiers = grep {-x $_ } @mesFichiers; # Trie du tableau par taille de fichier @mesFichiers = sort { (-s $a) <=> (-s $b) } @mesFichiers; # On place la taille des fichiers dans un autre tableau my @mesTailles = map { -s $_ } @mesFichiers; # Plus simple que la version précédente : # my @mesTailles = map { (stat($_))[7] } @mesFichiers; # Pour i allant de 0 à la taille du tableau "mesTailles" foreach my $i (0..@mesTailles - 1) { print "$mesFichiers[$i] $mesTailles[$i]\n"; }
vanvincq@CP2L ~/Bureau $ ./fichiers.pl
/home/vanvincq/. 4096
/home/vanvincq/.. 4096
/home/vanvincq/.adobe 4096
/home/vanvincq/.cache 4096
/home/vanvincq/.codeblocks 4096
/home/vanvincq/.config 4096
/home/vanvincq/.dbus 4096
/home/vanvincq/.emacs.d 4096
/home/vanvincq/.evolution 4096
/home/vanvincq/.filezilla 4096
/home/vanvincq/.fontconfig 4096
/home/vanvincq/.gconf 4096
/home/vanvincq/.gconfd 4096
/home/vanvincq/.gegl-0.0 4096
/home/vanvincq/.gimp-2.6 4096
/home/vanvincq/.gnome2 4096
/home/vanvincq/.gnome2_private 4096
/home/vanvincq/.gnupg 4096
/home/vanvincq/.gstreamer-0.10 4096
/home/vanvincq/.gvfs 4096
/home/vanvincq/.icedove 4096
/home/vanvincq/.icons 4096
/home/vanvincq/.lftp 4096
/home/vanvincq/.libreoffice 4096
/home/vanvincq/.local 4096
/home/vanvincq/.macromedia 4096
/home/vanvincq/.mozilla 4096
/home/vanvincq/.nautilus 4096
/home/vanvincq/.netkit 4096
/home/vanvincq/.nv 4096
/home/vanvincq/.pki 4096
/home/vanvincq/.pulse 4096
/home/vanvincq/.ssh 4096
/home/vanvincq/.texmf-var 4096
/home/vanvincq/.themes 4096
/home/vanvincq/.thumbnails 4096
/home/vanvincq/.update-notifier 4096
/home/vanvincq/.wireshark 4096
/home/vanvincq/.xchat2 4096
/home/vanvincq/.xxe5 4096
/home/vanvincq/Bureau 4096
/home/vanvincq/Documents 4096
/home/vanvincq/Images 4096
/home/vanvincq/Modèles 4096
/home/vanvincq/Musique 4096
/home/vanvincq/pt 4096
/home/vanvincq/Public 4096
/home/vanvincq/Téléchargements 4096
/home/vanvincq/Vidéos 4096
Écrivez un programme qui prend en arguments sur sa ligne de commande des noms de mois (janvier, décembre, ...) et qui affiche leur nombre de jours (28, 30, ...) à l'écran. Utilisez une table de hachage (gérer le cas d'un mois inexistant).
#!/usr/bin/perl -w my %mois = ( "Janvier" => 31, "Février" => 28, "Mars" => 31, "Avril" => 30, "Mai" => 31, "Juin" => 30, "Juillet" => 31, "Août" => 31, "Septembre" => 30, "Octobre" => 31, "Novembre" => 30, "Décembre" => 31 ); foreach(@ARGV) { print "$_\t:\t"; if (exists($mois{$_})) { print "$mois{$_}\n"; } else { print "inconnu\n"; } }
vanvincq@CP2L ~/Bureau $ ./mois.pl Janvier Février Bière Juin Mars
Janvier : 31
Février : 28
Bière : inconnu
Juin : 30
Mars : 31
Dans une seconde variante, comment faire pour accepter tous les mois sans tenir compte de la casse ?
Pour simplifier un peu la tâche, j'ai transformé les clefs intitiales en minuscules.
#!/usr/bin/perl -w my %mois = ( "janvier" => 31, "février" => 28, "mars" => 31, "avril" => 30, "mai" => 31, "juin" => 30, "juillet" => 31, "août" => 31, "septembre" => 30, "octobre" => 31, "novembre" => 30, "décembre" => 31 ); foreach(@ARGV) { my $key = $_; $key =~ tr/A-Z/a-z/; print "$key\t:\t"; if (exists($mois{$key})) { print "$mois{$key}\n"; } else { print "inconnu\n"; } }
vanvincq@CP2L ~/Bureau $ ./mois.pl Janvier JANVIER mArS
janvier : 31
janvier : 31
mars : 31
Les lignes du fichier système passwd sont de format login:passwd:uid:gid:info:home:shell. Écrivez un programme qui créé, à partir du fichier /etc/passwd, une table de hachage associant la séquence mot de passe au login (le login sera la clef et le mot de passe sera la valeur). Utilisez la fonction split.
Dans une seconde étape, vous afficherez les couples (login, passwd) mémorisés dans la table de hachage.
Enfin dans une dernière étape, le programme supprimera de cette table tous les utilisateurs dont le login contient une ou plusieurs voyelles.
#!/usr/bin/perl -w my ($login, $passwd); my %hash = (); # Ouverture du fichier en mode lecture if (!open(FILE, "/etc/passwd")) { exit(1); } # Absorption du contenu my @contentFile = <FILE>; # Pour chaque ligne du fichier, récupérer le deux premiers champs foreach (@contentFile) { ($login, $passwd) = split (/:/, $_); $hash{ $login } = $passwd; } # Affichage du contenu de la liste while (my ($key, $value) = each(%hash)) { print "$key => $value\n"; } # Suppression des utilisateurs ayant une ou plusieurs voyelles foreach $login (keys(%hash)) { if ($login =~ m/[aeiouy]/i) { delete ($hash{ $login }); } } # Affichage du contenu de la liste print "\nContenu de la table après suppression :\n"; while (my ($key, $value) = each(%hash)) { print "$key => $value\n"; } # Fermeture du fichier close(FILE);
vanvincq@CP2L ~/Bureau $ ./password.pl
telnetd => x
bin => x
usbmux => x
nobody => x
lp => x
Debian-gdm => x
irc => x
list => x
messagebus => x
sys => x
Debian-exim => x
gnats => x
saned => x
cl-builder => x
avahi => x
vanvincq => x
proxy => x
avahi-autoipd => x
games => x
libuuid => x
hplip => x
www-data => x
proftpd => x
ftp => x
statd => x
mail => x
root => x
daemon => x
backup => x
uucp => x
sync => x
man => x
news => x
sshd => x
Contenu de la table après suppression :
lp => x
ftp => x
sshd => x
Le but de cet exercice est la manipulation des expressions régulières (ne pas utiliser split ici). Il vous est demandé d'écrire un programme manipulant le même fichier /etc/passwd et d'afficher les informations qui vous seront demandées.
Ce programme comportera uniquement les instructions nécessaires à la lecture du fichier ainsi que l'expression régulière demandée et un simple appel à la fonction print. Une fois que vous avez répondu à une question, vous pouvez mettre en commentaire les lignes de codes la concernant et passer à la suivante.
Il vous est demandé d'afficher :
la ligne correspondante à l'utilisateur root;
#!/usr/bin/perl -w # Ouverture du fichier open (FILE, "/etc/passwd") || die(); print "Ligne correspondante à l'utilisateur root :\t"; while (<FILE>) { print "$_" if ( $_ =~ m/^root\b/); } # Fermeture du fichier close (FILE);
vanvincq@CP2L ~ $ ./expression.pl
Ligne correspondante à l'utilisateur root : root:x:0:0:root:/root:/bin/bash
les lignes correspondantes aux utilisateurs qui n'ont pas /bin/sh comme shell (commencez par chercher ceux qui ont /bin/sh puis nier);
#!/usr/bin/perl -w # Ouverture du fichier open (FILE, "/etc/passwd") || die(); print "Lignes correspondantes aux utilisateurs sans /bin/sh :\n"; while (<FILE>) { print "$_" if ( $_ !~ m:/bin/sh$:); } # Fermeture du fichier close (FILE);
vanvincq@CP2L ~ $ ./expression.pl
Lignes correspondantes aux utilisateurs sans /bin/sh :
root:x:0:0:root:/root:/bin/bash
sync:x:4:65534:sync:/bin:/bin/sync
Debian-exim:x:101:103::/var/spool/exim4:/bin/false
statd:x:102:65534::/var/lib/nfs:/bin/false
messagebus:x:103:106::/var/run/dbus:/bin/false
avahi:x:104:107:Avahi mDNS daemon,,,:/var/run/avahi-daemon:/bin/false
usbmux:x:105:46:usbmux daemon,,,:/home/usbmux:/bin/false
saned:x:106:115::/home/saned:/bin/false
hplip:x:107:7:HPLIP system user,,,:/var/run/hplip:/bin/false
Debian-gdm:x:108:116:Gnome Display Manager:/var/lib/gdm3:/bin/false
avahi-autoipd:x:109:117:Avahi autoip daemon,,,:/var/lib/avahi-autoipd:/bin/false
vanvincq:x:1000:1000:Vanvincq Clément,,,:/home/vanvincq:/bin/bash
cl-builder:x:110:118::/usr/share/common-lisp/:/bin/false
sshd:x:111:65534::/var/run/sshd:/usr/sbin/nologin
proftpd:x:112:65534::/var/run/proftpd:/bin/false
ftp:x:1010:1010:Accès ftp authentifié,,,,:/home/ftp:/bin/true
telnetd:x:114:119::/nonexistent:/bin/false
les lignes en remplaçant /home par /mnt/home;
#!/usr/bin/perl -w # Ouverture du fichier open (FILE, "/etc/passwd") || die(); while (<FILE>) { $_ =~ s@/home@/mount/home@; # on peut utiliser tout autre séparateur au choix comme ':', etc. print "$_"; } # Fermeture du fichier close (FILE);
vanvincq@CP2L ~ $ ./expression.pl
root:x:0:0:root:/root:/bin/bash
daemon:x:1:1:daemon:/usr/sbin:/bin/sh
bin:x:2:2:bin:/bin:/bin/sh
sys:x:3:3:sys:/dev:/bin/sh
sync:x:4:65534:sync:/bin:/bin/sync
games:x:5:60:games:/usr/games:/bin/sh
man:x:6:12:man:/var/cache/man:/bin/sh
lp:x:7:7:lp:/var/spool/lpd:/bin/sh
mail:x:8:8:mail:/var/mail:/bin/sh
news:x:9:9:news:/var/spool/news:/bin/sh
uucp:x:10:10:uucp:/var/spool/uucp:/bin/sh
proxy:x:13:13:proxy:/bin:/bin/sh
www-data:x:33:33:www-data:/var/www:/bin/sh
backup:x:34:34:backup:/var/backups:/bin/sh
list:x:38:38:Mailing List Manager:/var/list:/bin/sh
irc:x:39:39:ircd:/var/run/ircd:/bin/sh
gnats:x:41:41:Gnats Bug-Reporting System (admin):/var/lib/gnats:/bin/sh
nobody:x:65534:65534:nobody:/nonexistent:/bin/sh
libuuid:x:100:101::/var/lib/libuuid:/bin/sh
Debian-exim:x:101:103::/var/spool/exim4:/bin/false
statd:x:102:65534::/var/lib/nfs:/bin/false
messagebus:x:103:106::/var/run/dbus:/bin/false
avahi:x:104:107:Avahi mDNS daemon,,,:/var/run/avahi-daemon:/bin/false
usbmux:x:105:46:usbmux daemon,,,:/mount/home/usbmux:/bin/false
saned:x:106:115::/mount/home/saned:/bin/false
hplip:x:107:7:HPLIP system user,,,:/var/run/hplip:/bin/false
Debian-gdm:x:108:116:Gnome Display Manager:/var/lib/gdm3:/bin/false
avahi-autoipd:x:109:117:Avahi autoip daemon,,,:/var/lib/avahi-autoipd:/bin/false
vanvincq:x:1000:1000:Vanvincq Clément,,,:/mount/home/vanvincq:/bin/bash
cl-builder:x:110:118::/usr/share/common-lisp/:/bin/false
sshd:x:111:65534::/var/run/sshd:/usr/sbin/nologin
proftpd:x:112:65534::/var/run/proftpd:/bin/false
ftp:x:1010:1010:Accès ftp authentifié,,,,:/mount/home/ftp:/bin/true
telnetd:x:114:119::/nonexistent:/bin/false
les lignes en supprimant la séquence de mot de passe;
#!/usr/bin/perl -w # Ouverture du fichier open (FILE, "/etc/passwd") || die(); while (<FILE>) { $_ =~ s/:[^:]+?:/:/; print "$_"; } # Fermeture du fichier close (FILE);
cvanvinc@pinson ~/Bureau $ ./exercice.pl
root:0:0:root:/root:/bin/bash
daemon:1:1:daemon:/usr/sbin:/bin/sh
bin:2:2:bin:/bin:/bin/sh
sys:3:3:sys:/dev:/bin/sh
sync:4:65534:sync:/bin:/bin/sync
games:5:60:games:/usr/games:/bin/sh
man:6:12:man:/var/cache/man:/bin/sh
lp:7:7:lp:/var/spool/lpd:/bin/sh
mail:8:8:mail:/var/mail:/bin/sh
news:9:9:news:/var/spool/news:/bin/sh
uucp:10:10:uucp:/var/spool/uucp:/bin/sh
proxy:13:13:proxy:/bin:/bin/sh
www-data:33:33:www-data:/var/www:/bin/sh
backup:34:34:backup:/var/backups:/bin/sh
list:38:38:Mailing List Manager:/var/list:/bin/sh
irc:39:39:ircd:/var/run/ircd:/bin/sh
gnats:41:41:Gnats Bug-Reporting System (admin):/var/lib/gnats:/bin/sh
nobody:65534:65534:nobody:/nonexistent:/bin/sh
libuuid:100:101::/var/lib/libuuid:/bin/sh
messagebus:101:103::/var/run/dbus:/bin/false
Debian-exim:102:104::/var/spool/exim4:/bin/false
statd:103:65534::/var/lib/nfs:/bin/false
avahi:104:107:Avahi mDNS daemon,,,:/var/run/avahi-daemon:/bin/false
usbmux:105:46:usbmux daemon,,,:/home/usbmux:/bin/false
Debian-gdm:106:114:Gnome Display Manager:/var/lib/gdm3:/bin/false
saned:107:116::/home/saned:/bin/false
hplip:108:7:HPLIP system user,,,:/var/run/hplip:/bin/false
info:1000:1000:info,,,:/home/info:/bin/bash
haldaemon:109:117:Hardware abstraction layer,,,:/var/run/hald:/bin/false
cl-builder:110:119::/usr/share/common-lisp/:/bin/false
mysql:111:120:MySQL Server,,,:/var/lib/mysql:/bin/false
gdm:112:121:Gnome Display Manager:/var/lib/gdm:/bin/false
sshd:113:65534::/var/run/sshd:/usr/sbin/nologin
nath:1001:1001:,,,:/home/nath:/bin/bash
les lignes en échangeant login et passwd.
#!/usr/bin/perl -w # Ouverture du fichier open (FILE, "/etc/passwd") || die(); # Les parenthèses permettent d'inclure le regroupement mémorisant. while (<FILE>) { $_ =~ s/^([^:]+):([^:]+):/$2:$1:/; print "$_"; } # Fermeture du fichier close (FILE);
cvanvinc@pinson ~/Bureau $ ./exercice.pl
x:root:0:0:root:/root:/bin/bash
x:daemon:1:1:daemon:/usr/sbin:/bin/sh
x:bin:2:2:bin:/bin:/bin/sh
x:sys:3:3:sys:/dev:/bin/sh
x:sync:4:65534:sync:/bin:/bin/sync
x:games:5:60:games:/usr/games:/bin/sh
x:man:6:12:man:/var/cache/man:/bin/sh
x:lp:7:7:lp:/var/spool/lpd:/bin/sh
x:mail:8:8:mail:/var/mail:/bin/sh
x:news:9:9:news:/var/spool/news:/bin/sh
x:uucp:10:10:uucp:/var/spool/uucp:/bin/sh
x:proxy:13:13:proxy:/bin:/bin/sh
x:www-data:33:33:www-data:/var/www:/bin/sh
x:backup:34:34:backup:/var/backups:/bin/sh
x:list:38:38:Mailing List Manager:/var/list:/bin/sh
x:irc:39:39:ircd:/var/run/ircd:/bin/sh
x:gnats:41:41:Gnats Bug-Reporting System (admin):/var/lib/gnats:/bin/sh
x:nobody:65534:65534:nobody:/nonexistent:/bin/sh
x:libuuid:100:101::/var/lib/libuuid:/bin/sh
x:Debian-exim:101:103::/var/spool/exim4:/bin/false
x:statd:102:65534::/var/lib/nfs:/bin/false
x:messagebus:103:106::/var/run/dbus:/bin/false
x:avahi:104:107:Avahi mDNS daemon,,,:/var/run/avahi-daemon:/bin/false
x:usbmux:105:46:usbmux daemon,,,:/home/usbmux:/bin/false
x:saned:106:115::/home/saned:/bin/false
x:hplip:107:7:HPLIP system user,,,:/var/run/hplip:/bin/false
x:Debian-gdm:108:116:Gnome Display Manager:/var/lib/gdm3:/bin/false
x:avahi-autoipd:109:117:Avahi autoip daemon,,,:/var/lib/avahi-autoipd:/bin/false
x:vanvincq:1000:1000:Vanvincq Clément,,,:/home/vanvincq:/bin/bash
x:cl-builder:110:118::/usr/share/common-lisp/:/bin/false
x:sshd:111:65534::/var/run/sshd:/usr/sbin/nologin
x:proftpd:112:65534::/var/run/proftpd:/bin/false
x:ftp:1010:1010:Accès ftp authentifié,,,,:/home/ftp:/bin/true
x:telnetd:114:119::/nonexistent:/bin/false
Construisez une référence vers une table de hachage dont les clefs seraient le login d'une personne et la valeur une référence vers une table de hachage comportant les clefs suivantes :
uid: son numéro d'utilisateur,
home: son répertoire personnel,
gid: une référence vers un tableau comportant ses numéros de groupe.
Prennez par exemple :
root, d'uid 0, son répertoire personnel est /root et ses groupes sont 0, 2 et 10.
paul, d'uid 500, son répertoire personnel est /home/paul et ses groupes sont 200, 4 et 10.
Faites un schéma de cette structure en mémoire.
Affichez d'abord cette structure de données à l'aide du module Data::Dumper.
#!/usr/bin/perl -w use strict; use Data::Dumper; my $reference = { "root" => { "uid" => 0, "home" => "/root", "gid" => [ 0, 2, 10]}, "paul" => { "uid" => 500, "home" => "/home/paul", "gid" => [ 200, 4, 10]} }; print Dumper($reference);
cvanvinc@pinson ~/Bureau $ ./reference.pl
$VAR1 = {
'root' => {
'uid' => 0,
'home' => '/root',
'gid' => [
0,
2,
10
]
},
'paul' => {
'uid' => 500,
'home' => '/home/paul',
'gid' => [
200,
4,
10
]
}
};
Écrivez ensuite le code Perl permettant d'afficher toute la structure sans utiliser ce module (le format d'affichage est libre): n'utilisez pas l'opérateur ref, mais utilisez le fait que vous connaissez les trois clefs des tables de hachages (uid, home et gid) ainsi que les types de leurs valeurs respectives.
Dans un premier temps, affichez la liste des numéros de groupe avec foreach.
#!/usr/bin/perl -w use strict; use Data::Dumper; my $reference = { "root" => { "uid" => 0, "home" => "/root", "gid" => [ 0, 2, 10]}, "paul" => { "uid" => 500, "home" => "/home/paul", "gid" => [ 200, 4, 10]} }; print "Affichage libre sans Dumper:\n"; foreach my $login ( keys %{$reference} ) { print "$login\n"; print "\t$reference->{$login}->{'uid'}\n"; print "\t$reference->{$login}->{'home'}\n"; foreach my $value ( @{$reference->{$login}->{'gid'}} ) { print "\t\t$value\n"; } }
vanvincq@CP2L ~/Bureau $ ./reference.pl
Affichage libre sans Dumper:
root
0
/root
0
2
10
paul
500
/home/paul
200
4
10
Dans un second temps avec join.
#!/usr/bin/perl -w use strict; use Data::Dumper; my $reference = { "root" => { "uid" => 0, "home" => "/root", "gid" => [ 0, 2, 10]}, "paul" => { "uid" => 500, "home" => "/home/paul", "gid" => [ 200, 4, 10]} }; print "Affichage libre sans Dumper:\n"; foreach my $login ( keys %{$reference} ) { print "$login\n"; print "\t$reference->{$login}->{'uid'}\n"; print "\t$reference->{$login}->{'home'}\n"; print "\t".join (' ', @{$reference->{$login}->{'gid'}})."\n"; }
vanvincq@CP2L ~/Bureau $ ./reference.pl
Affichage libre sans Dumper:
root
0
/root
0 2 10
paul
500
/home/paul
200 4 10
Affichez finalement chaque liste de numéros de groupe par ordre numérique.
#!/usr/bin/perl -w use strict; use Data::Dumper; my $reference = { "root" => { "uid" => 0, "home" => "/root", "gid" => [ 0, 2, 10]}, "paul" => { "uid" => 500, "home" => "/home/paul", "gid" => [ 200, 4, 10]} }; print "Affichage libre sans Dumper:\n"; foreach my $login ( keys %{$reference} ) { print "$login\n"; print "\t$reference->{$login}->{'uid'}\n"; print "\t$reference->{$login}->{'home'}\n"; print "\t".join(' ', sort( {$a <=> $b} @{$reference->{$login}->{'gid'}} ))."\n"; }
vanvincq@CP2L ~/Bureau $ ./reference.pl
Affichage libre sans Dumper:
root
0
/root
0 2 10
paul
500
/home/paul
4 10 200
Le but de cet exercice est la manipulation du fichier passwd. Ce fichier est composé de sept champs séparés par le caractère ':'. L'ordre des champs et le suivant :
login : le nom du compte de l'utilisateur,
passwd : la séquence chiffrée du mot de passe (ou * dans certains cas),
uid : le numéro de l'utilisateur (0 pour root),
gid : le numéro de groupe de l'utilisateur (attention : il n'y a ici qu'un seul numéro, ne pas confondre avec ce qui vous a été dit à l'exercice précédent),
info : des informations sur l'utilisateur (nom, etc.),
home : le répertoire personnel de l'utilisateur,
shell : le chemin de l'exécutable de son shell préféré.
Voici les étapes du projet :
Quelle structure pourrait-on utiliser pour stocker en mémoire toutes ces données et les manipuler facilement ?
La solution la plus simple serait de créer un tableau contenant les références des différents utilisateurs vers une table de hachage dont les clefs seraient 'login', 'uid', etc.
On se propose de stocker ces informations dans un tableau qui aura pour valeur des référence vers des tables de hachage dont les clefs seront login, uid, gid, info, passwd, home et shell. Faites un schéma de cette structure de données.
Écrivez une fonction parse qui prend en paramètre le nom du fichier à analyser. Elle renvoie une référence vers ce tableau et elle s'utilisera de la sorte : my $ref = parse('/etc/passwd');
#!/usr/bin/perl -w use strict; #** # @function public parse ($filename) # @brief Ouvre un fichier et récupère son contenu (selon la structure /etc/passwd). # @params $filename required le nom du fichier à parser. # @retval \@array la référence vers le tableau. #* sub parse { my ($filename) = @_; my @array = (); my ($login, $passwd, $uid, $gid, $info ,$home, $shell); open (FILE, $filename) or die("open: $!"); while (<FILE>) { ($login, $passwd, $uid, $gid, $info ,$home, $shell) = split (/:/, $_); push (@array, { 'login' => $login, 'passwd' => $passwd, 'uid' => $uid, 'gid' => $gid, 'info' => $info, 'home' => $home, 'shell' => $shell} ); } close (FILE); return \@array; } my $ref = parse('/etc/passwd');
Écrivez une fonction dump qui effectue l'affichage de toutes ces informations. Chaque utilisateur sera affiché sur une seule ligne au même format que les lignes du fichier /etc/passwd et les utilisateurs seront affichés dans l'ordre de leur présence dans le fichier (pas de tri à faire, on respecte l'ordre du tableau).
#!/usr/bin/perl -w use strict; #** # @function public parse ($filename) # @brief Ouvre un fichier et récupère son contenu (selon la structure /etc/passwd). # @params $filename required le nom du fichier à parser. # @retval \@array la référence vers le tableau. #* sub parse { my ($filename) = @_; my @array = (); my ($login, $passwd, $uid, $gid, $info ,$home, $shell); open (FILE, $filename) or die("open: $!"); while (<FILE>) { ($login, $passwd, $uid, $gid, $info ,$home, $shell) = split (/:/, $_); push (@array, { 'login' => $login, 'passwd' => $passwd, 'uid' => $uid, 'gid' => $gid, 'info' => $info, 'home' => $home, 'shell' => $shell} ); } close (FILE); return \@array; } #** # @function public dump ($reference) # @brief Affiche le contenu de la structure # @params $reference required la référence vers la structure #* sub dump { my ($reference) = @_; foreach (@$reference) { foreach my $value (values(%$_)) { # Suppression des caractères de fin de ligne avec chomp # plus simple que $value =~ s/\n//; chomp $value; print "$value:"; } print "\n"; } } # Les '::' évitent l'ambiguité lors de l'appel de la fonction. ::dump(parse('/etc/passwd'));
vanvincq@CP2L ~/Bureau $ ./ultime.pl
root:x:0:/bin/bash:/root:0:root:
daemon:x:1:/bin/sh:/usr/sbin:1:daemon:
bin:x:2:/bin/sh:/bin:2:bin:
sys:x:3:/bin/sh:/dev:3:sys:
sync:x:4:/bin/sync:/bin:65534:sync:
games:x:5:/bin/sh:/usr/games:60:games:
man:x:6:/bin/sh:/var/cache/man:12:man:
lp:x:7:/bin/sh:/var/spool/lpd:7:lp:
mail:x:8:/bin/sh:/var/mail:8:mail:
news:x:9:/bin/sh:/var/spool/news:9:news:
uucp:x:10:/bin/sh:/var/spool/uucp:10:uucp:
proxy:x:13:/bin/sh:/bin:13:proxy:
www-data:x:33:/bin/sh:/var/www:33:www-data:
backup:x:34:/bin/sh:/var/backups:34:backup:
Mailing List Manager:x:38:/bin/sh:/var/list:38:list:
ircd:x:39:/bin/sh:/var/run/ircd:39:irc:
Gnats Bug-Reporting System (admin):x:41:/bin/sh:/var/lib/gnats:41:gnats:
nobody:x:65534:/bin/sh:/nonexistent:65534:nobody:
:x:100:/bin/sh:/var/lib/libuuid:101:libuuid:
:x:101:/bin/false:/var/spool/exim4:103:Debian-exim:
:x:102:/bin/false:/var/lib/nfs:65534:statd:
:x:103:/bin/false:/var/run/dbus:106:messagebus:
Avahi mDNS daemon,,,:x:104:/bin/false:/var/run/avahi-daemon:107:avahi:
usbmux daemon,,,:x:105:/bin/false:/home/usbmux:46:usbmux:
:x:106:/bin/false:/home/saned:115:saned:
HPLIP system user,,,:x:107:/bin/false:/var/run/hplip:7:hplip:
Gnome Display Manager:x:108:/bin/false:/var/lib/gdm3:116:Debian-gdm:
Avahi autoip daemon,,,:x:109:/bin/false:/var/lib/avahi-autoipd:117:avahi-autoipd:
Vanvincq Clément,,,:x:1000:/bin/bash:/home/vanvincq:1000:vanvincq:
:x:110:/bin/false:/usr/share/common-lisp/:118:cl-builder:
:x:111:/usr/sbin/nologin:/var/run/sshd:65534:sshd:
:x:112:/bin/false:/var/run/proftpd:65534:proftpd:
Accès ftp authentifié,,,,:x:1010:/bin/true:/home/ftp:1010:ftp:
:x:114:/bin/false:/nonexistent:119:telnetd:
Dans le programme principal après l'appel à la fonction parse, modifiez vos données des manières suivantes :
ne gardez que les comptes dont les uid sont des nombres pairs (% et grep),
#!/usr/bin/perl -w use strict; #** # @function public parse ($filename) # @brief Ouvre un fichier et récupère son contenu (selon la structure /etc/passwd). # @params $filename required le nom du fichier à parser. # @retval \@array la référence vers le tableau. #* sub parse { my ($filename) = @_; my @array = (); my ($login, $passwd, $uid, $gid, $info ,$home, $shell); open (FILE, $filename) or die("open: $!"); while (<FILE>) { ($login, $passwd, $uid, $gid, $info ,$home, $shell) = split (/:/, $_); push (@array, { 'login' => $login, 'passwd' => $passwd, 'uid' => $uid, 'gid' => $gid, 'info' => $info, 'home' => $home, 'shell' => $shell} ); } close (FILE); return \@array; } #** # @function public dump ($reference) # @brief Affiche le contenu de la structure # @params $reference required la référence vers la structure #* sub dump { my ($reference) = @_; foreach (@$reference) { foreach my $value (values(%$_)) { # Suppression des caractères de fin de ligne avec chomp # plus simple que $value =~ s/\n//; chomp $value; print "$value:"; } print "\n"; } } sub peersOnly { my ($reference) = @_; # On retourne directement une référence anonyme return [ grep { !($_->{'uid'} % 2) } @$reference ]; } my $ref = parse('/etc/passwd'); $ref = peersOnly($ref); # Les '::' évitent l'ambiguité lors de l'appel de la fonction. ::dump($ref);
vanvincq@CP2L ~/Bureau $ ./ultime.pl
root:x:0:/bin/bash:/root:0:root:
bin:x:2:/bin/sh:/bin:2:bin:
sync:x:4:/bin/sync:/bin:65534:sync:
man:x:6:/bin/sh:/var/cache/man:12:man:
mail:x:8:/bin/sh:/var/mail:8:mail:
uucp:x:10:/bin/sh:/var/spool/uucp:10:uucp:
backup:x:34:/bin/sh:/var/backups:34:backup:
Mailing List Manager:x:38:/bin/sh:/var/list:38:list:
nobody:x:65534:/bin/sh:/nonexistent:65534:nobody:
:x:100:/bin/sh:/var/lib/libuuid:101:libuuid:
:x:102:/bin/false:/var/lib/nfs:65534:statd:
Avahi mDNS daemon,,,:x:104:/bin/false:/var/run/avahi-daemon:107:avahi:
:x:106:/bin/false:/home/saned:115:saned:
Gnome Display Manager:x:108:/bin/false:/var/lib/gdm3:116:Debian-gdm:
Vanvincq Clément,,,:x:1000:/bin/bash:/home/vanvincq:1000:vanvincq:
:x:110:/bin/false:/usr/share/common-lisp/:118:cl-builder:
:x:112:/bin/false:/var/run/proftpd:65534:proftpd:
Accès ftp authentifié,,,,:x:1010:/bin/true:/home/ftp:1010:ftp:
:x:114:/bin/false:/nonexistent:119:telnetd:
ajoutez dix à tous les gid (map),
#!/usr/bin/perl -w use strict; #** # @function public parse ($filename) # @brief Ouvre un fichier et récupère son contenu (selon la structure /etc/passwd). # @params $filename required le nom du fichier à parser. # @retval \@array la référence vers le tableau. #* sub parse { my ($filename) = @_; my @array = (); my ($login, $passwd, $uid, $gid, $info ,$home, $shell); open (FILE, $filename) or die("open: $!"); while (<FILE>) { ($login, $passwd, $uid, $gid, $info ,$home, $shell) = split (/:/, $_); push (@array, { 'login' => $login, 'passwd' => $passwd, 'uid' => $uid, 'gid' => $gid, 'info' => $info, 'home' => $home, 'shell' => $shell} ); } close (FILE); return \@array; } #** # @function public dump ($reference) # @brief Affiche le contenu de la structure # @params $reference required la référence vers la structure #* sub dump { my ($reference) = @_; foreach (@$reference) { foreach my $value (values(%$_)) { # Suppression des caractères de fin de ligne avec chomp # plus simple que $value =~ s/\n//; chomp $value; print "$value:"; } print "\n"; } } sub peersOnly { my ($reference) = @_; # On retourne directement une référence anonyme return [ grep { !($_->{'uid'} % 2) } @$reference ]; } sub addTenToGID { my ($reference) = @_; foreach (@$reference) { $_->{'gid'} += 10; } } my $ref = parse('/etc/passwd'); # Récupération de la nouvelle référence $ref = peersOnly($ref); # Modification directe addTenToGID($ref); # Les '::' évitent l'ambiguité lors de l'appel de la fonction. ::dump($ref);
cvanvinc@pinson ~/Bureau $ ./ultime.pl
root:x:0:/bin/bash:/root:10:root:
bin:x:2:/bin/sh:/bin:12:bin:
sync:x:4:/bin/sync:/bin:65544:sync:
man:x:6:/bin/sh:/var/cache/man:22:man:
mail:x:8:/bin/sh:/var/mail:18:mail:
uucp:x:10:/bin/sh:/var/spool/uucp:20:uucp:
backup:x:34:/bin/sh:/var/backups:44:backup:
Mailing List Manager:x:38:/bin/sh:/var/list:48:list:
nobody:x:65534:/bin/sh:/nonexistent:65544:nobody:
:x:100:/bin/sh:/var/lib/libuuid:111:libuuid:
:x:102:/bin/false:/var/spool/exim4:114:Debian-exim:
Avahi mDNS daemon,,,:x:104:/bin/false:/var/run/avahi-daemon:117:avahi:
Gnome Display Manager:x:106:/bin/false:/var/lib/gdm3:124:Debian-gdm:
HPLIP system user,,,:x:108:/bin/false:/var/run/hplip:17:hplip:
info,,,:x:1000:/bin/bash:/home/info:1010:info:
:x:110:/bin/false:/usr/share/common-lisp/:129:cl-builder:
Gnome Display Manager:x:112:/bin/false:/var/lib/gdm:131:gdm:
triez le tableau par ordre alphabétique du login (sort).
#!/usr/bin/perl -w use strict; #** # @function public parse ($filename) # @brief Ouvre un fichier et récupère son contenu (selon la structure /etc/passwd). # @params $filename required le nom du fichier à parser. # @retval \@array la référence vers le tableau. #* sub parse { my ($filename) = @_; my @array = (); my ($login, $passwd, $uid, $gid, $info ,$home, $shell); open (FILE, $filename) or die("open: $!"); while (<FILE>) { ($login, $passwd, $uid, $gid, $info ,$home, $shell) = split (/:/, $_); push (@array, { 'login' => $login, 'passwd' => $passwd, 'uid' => $uid, 'gid' => $gid, 'info' => $info, 'home' => $home, 'shell' => $shell} ); } close (FILE); return \@array; } #** # @function public dump ($reference) # @brief Affiche le contenu de la structure # @params $reference required la référence vers la structure #* sub dump { my ($reference) = @_; foreach (@$reference) { foreach my $value (values(%$_)) { # Suppression des caractères de fin de ligne avec chomp # plus simple que $value =~ s/\n//; chomp $value; print "$value:"; } print "\n"; } } sub peersOnly { my ($reference) = @_; # On retourne directement une référence anonyme return [ grep { !($_->{'uid'} % 2) } @$reference ]; } sub addTenToGID { my ($reference) = @_; foreach (@$reference) { $_->{'gid'} += 10; } } sub sortByLogin { my ($reference) = @_; # Tri lexical explicite return [ sort { $a->{'login'} cmp $b->{'login'} } @$reference ]; } my $ref = parse('/etc/passwd'); # Récupération de la nouvelle référence $ref = peersOnly($ref); # Modification directe addTenToGID($ref); # Récupération de la nouvelle référence $ref = sortByLogin($ref); # Les '::' évitent l'ambiguité lors de l'appel de la fonction. ::dump($ref);
cvanvinc@pinson ~/Bureau $ ./ultime.pl
:x:102:/bin/false:/var/spool/exim4:114:Debian-exim:
Gnome Display Manager:x:106:/bin/false:/var/lib/gdm3:124:Debian-gdm:
Avahi mDNS daemon,,,:x:104:/bin/false:/var/run/avahi-daemon:117:avahi:
backup:x:34:/bin/sh:/var/backups:44:backup:
bin:x:2:/bin/sh:/bin:12:bin:
:x:110:/bin/false:/usr/share/common-lisp/:129:cl-builder:
Gnome Display Manager:x:112:/bin/false:/var/lib/gdm:131:gdm:
HPLIP system user,,,:x:108:/bin/false:/var/run/hplip:17:hplip:
info,,,:x:1000:/bin/bash:/home/info:1010:info:
:x:100:/bin/sh:/var/lib/libuuid:111:libuuid:
Mailing List Manager:x:38:/bin/sh:/var/list:48:list:
mail:x:8:/bin/sh:/var/mail:18:mail:
man:x:6:/bin/sh:/var/cache/man:22:man:
nobody:x:65534:/bin/sh:/nonexistent:65544:nobody:
root:x:0:/bin/bash:/root:10:root:
sync:x:4:/bin/sync:/bin:65544:sync:
uucp:x:10:/bin/sh:/var/spool/uucp:20:uucp:
Utilisez votre fonction dump pour vérifier.
Petit détail : lors de l'appel de la fonction dump, l'ordre des clefs de la table de hachage n'est pas respectée.