<html> <head> <meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1"> <link REL="STYLESHEET" TYPE="text/css" TITLE="Style DILIB" HREF="../../dilib.css"> <style type="text/css"> </style> <title>Corrigé du TP - Shell - UNIX</title> </head> <body> <h1>Corrigé du TP - Shell - UNIX</h1> <p class="remarque"> Tous les shells qui seront créés par la suite devront avoir le droit d'exécution correctement positionné, au moins pour leur propriétaire. </p> <h2> Recherche d'information sur un utilisateur </h2> <ol> <li><a name="fichier"></a> <p> Écrivez un shell qui permette de chercher si un utilisateur d'un nom donné existe sur votre machine, en affichant sa référence complète (c'est-à-dire sans aucun filtrage).<br> Le nom recherché sera passé comme paramètre au shell.<br> La recherche portera dans le fichier <code>/etc/passwd</code>. </p> <a href="tpShell.fre.html#name_fichier">Retour</a> <pre class="script"><span class="comment"># Fichier "infouser1.sh" #!/bin/sh</span> grep $1 /etc/passwd</pre> <hr> </li> <li> <a name="param1"></a> <p> Modifiez ce script shell pour qu'il teste si un paramètre est bien passé en ligne. En cas d'erreur (aucun paramètre ou plus d'un), un message sera affiché expliquant la bonne syntaxe à suivre. </p> <a href="tpShell.fre.html#name_param1">Retour</a> <pre class="script"><span class="comment"># Fichier "infouser2.sh" #!/bin/sh</span> if test $# -ne 1 then echo Mauvais nombre de parametres. echo echo Usage: $0 uid exit 1 fi grep $1 /etc/passwd</pre> <hr> </li> <li><a name="utilisateur"></a> <p> Modifiez encore ce shell pour qu'il teste si l'utilisateur demandé existe sur votre machine. En cas d'absence, affichez un message d'avertissement. </p> <a href="tpShell.fre.html#name_utilisateur">Retour</a> <pre class="script"><span class="comment"># Fichier "infouser3.sh" #!/bin/sh</span> if test $# -ne 1 then echo Mauvais nombre de parametres. echo echo Usage: $0 [uid] exit 1 fi if test `grep $1 /etc/passwd | wc -l` -lt 1 then echo L\'utilisateur $1 n\'est pas créé sur cette machine. exit 2 fi grep $1 /etc/passwd</pre> <p class="remarque"> Par défaut, le shell s'arrête avec un statut à zéro, c'est pourquoi une ligne <code>exit 0</code> à la fin du programme est superflue. </p> <p class="remarque"> Le test effectué est <code>-lt 1</code> (plus petit que 1), mais on aurait tout aussi bien pu faire <code>-eq 0</code>. </p> <p class="remarque"> Le texte de sortie contient des <code>\'</code>, pour que le shell n'interprète pas ce caractère spécial comme une quote, mais comme une apostrophe (texte normal, et pas caractère spécial). </p> <p class="remarque"> On aurait pu aussi utiliser un test plus simple sur le résultat de <code>grep $1 /etc/passwd</code>, et le transformer en <code>if test ! $?</code>. </p> </li> </ol> <h2> Édition de statistiques sur un corpus XML </h2> <p> Pour cette partie du TP, il vous faut d'abord récupérer les deux corpus suivants :<br> <a href="corpus1.xml.gz"><code>corpus1.xml.gz</code></a><br> <a href="corpus2.xml.gz"><code>corpus2.xml.gz</code></a><br> Ces deux fichiers contiennent 25 notices en XML Dilib, leur exploration préparatoire est conseillée. </p> <ol> <li><a name="resume1"></a> <p> Écrivez un script shell qui édite le pourcentage de résumés, pour chacun des deux corpus, en passant le nom de fichier en paramètre.<br> <span class="attention"> Les fichiers ne devront jamais être décompressés sur disque.</span><br> L'élément résumé se nomme <code>fC01</code>. </p> <a href="tpShell.fre.html#name_resume1">Retour</a> <pre class="script"><span class="comment"># Fichier "resume1.sh" #!/bin/sh</span> if test $# -ne 1 then echo Mauvais nombre de parametres. echo echo Usage: $0 fichier exit 1 fi NB_LIGNES=`gzcat $1|wc -l` NB_RESUMES=`gzcat $1|grep fC01|wc -l` NB_RES_100=`expr 100 \* $NB_RESUMES` POURCENTAGE=`expr $NB_RES_100 / $NB_LIGNES` echo Pourcentage de notices avec résumé dans $1: ${POURCENTAGE}%</pre> <p class="remarque"> N'oubliez pas de banaliser l'opérateur de multiplication, sinon <code>expr</code> ne comprendra pas ce que vous demandez (<code>man expr</code> pour plus de détails). </p> <p class="remarque"> <code>gzcat</code> est utilisé, mais on pourrait aussi utiliser <code>gunzip -c</code>. </p> <hr> </li> <li><a name="resume2"></a> <p> Modifiez le shell précédent pour qu'il teste l'existence du fichier demandé avant traitement, puis pour qu'il sorte les résultats dans un fichier nommé <code>resultatsfC01.txt</code>. </p> <a href="tpShell.fre.html#name_resume2">Retour</a> <pre class="script"><span class="comment"># Fichier "resume2.sh" #!/bin/sh</span> if test $# -ne 1 then echo Mauvais nombre de parametres. echo echo Usage: $0 fichier exit 1 fi if test ! -f $1 then echo $1 "n'existe pas (ou n'est pas un fichier)." exit 2 fi NB_LIGNES=`gzcat $1|wc -l` NB_RESUMES=`gzcat $1|grep fC01|wc -l` NB_RES_100=`expr 100 \* $NB_RESUMES` POURCENTAGE=`expr $NB_RES_100 / $NB_LIGNES` echo Pourcentage de notices avec résumé dans $1: ${POURCENTAGE}% > resultatsfC01.txt</pre> <p class="remarque"> Cette fois, on a mis la chaîne contenant les apostrophes (caractère spécial) entre guillemets pour les banaliser. </p> <hr> </li> <li><a name="resume3"></a> <p> Écrivez un script shell qui, pour les deux corpus et en testant l'existence du fichier demandé, calcule le pourcentage de notices sans résumé, le pourcentage de notices de type périodique et le pourcentage de notices de langue française.<br> La liste des éléments à prendre en compte sera passée en paramètres en ligne au shell et ceux-ci seront traités en boucle avec un <code>while</code>.<br> Les statistiques obtenues seront récupérées dans le fichier <code>resultatsMulti.txt</code>.<br> Les éléments à utiliser sont <code>fA60</code> pour le type de document (<code>P</code> pour périodique) et <code>fA23</code> pour la langue (<code>FRE</code> pour la langue française). </p> <a href="tpShell.fre.html#name_resume3">Retour</a> <pre class="script"><span class="comment"># Fichier "resume3.sh" #!/bin/sh</span> if test $# -lt 1 then echo Mauvais nombre de parametres. echo echo Usage: $0 fichier... exit 1 fi rm -f resultatsMulti.txt while test $# -ne 0 do if test ! -f $1 then echo $1 "n'existe pas (ou n'est pas un fichier)." exit 2 fi echo ----------- >> resultatsMulti.txt echo $1 >> resultatsMulti.txt echo ----------- >> resultatsMulti.txt NB_LIGNES=`gzcat $1|wc -l` NB_SANS_RESUME=`gzcat $1|grep -v fC01|wc -l` NB_PERIODIQUES=`gzcat $1|grep "fA60><s1>P</"|wc -l` NB_FRANCAIS=`gzcat $1|grep "fA23 i1=\"01\"><s0>FRE</"|wc -l` NB_SANS_RES_100=`expr 100 \* $NB_SANS_RESUME` POURCENTAGE_SANS_RES=`expr $NB_SANS_RES_100 / $NB_LIGNES` echo "Pourcentage de notices sans résumé : ${POURCENTAGE_SANS_RES}%" \ >> resultatsMulti.txt NB_PERIO_100=`expr 100 \* $NB_PERIODIQUES` POURCENTAGE_PERIODIQUES=`expr $NB_PERIO_100 / $NB_LIGNES` echo "Pourcentage de notices de type périodique : ${POURCENTAGE_PERIODIQUES}%" \ >> resultatsMulti.txt NB_FRANCAIS_100=`expr 100 \* $NB_FRANCAIS` POURCENTAGE_FRANCAIS=`expr $NB_FRANCAIS_100 / $NB_LIGNES` echo "Pourcentage de notices françaises : ${POURCENTAGE_FRANCAIS}%" \ >> resultatsMulti.txt shift done</pre> <p class="remarque"> <code>shift</code> est utilisé pour parcourir tous les paramètres et considérer chacun d'entre eux comme le paramètre numéro 1. </p> <p class="remarque"> Le <code>rm -f resultatsMulti.txt</code> est là pour éviter la concaténation des résultats avec ceux des exécutions précédentes du même script. </p> <p class="remarque"> Pour plus de précision, on pourrait utiliser la commande DILIB <code>SgmlSelect</code> plutôt que <code>grep</code>, pour sélectionner les notices françaises (en effet, si l'attribut i1 changeait, la commande de comptage deviendrait plus compliquée avec <code>grep</code>). </p> <p class="remarque"> Le caractère <code>\</code> en fin de ligne permet de passer à la ligne sans interrompre la commande. C'est une facilité de présentation. </p> <p> <a href="tpShell.fre.html#name_resume3">Retour</a> </p> <hr> </li> <li><a name="resume4"></a> <p> Modifiez le shell précédent pour que le fichier résultat soit compressé au choix (Oui/Non). </p> <a href="tpShell.fre.html#name_resume4">Retour</a> <pre class="script"><span class="comment"># Fichier "resume4.sh" #!/bin/sh</span> if test $# -lt 1 then echo Mauvais nombre de parametres. echo echo Usage: $0 [-z] fichier... exit 1 fi rm -f resultatsMulti.txt* COMPRESSION=0 while test $# -ne 0 do case $1 in -z ) COMPRESSION=1 ;; * ) if test ! -f $1 then echo $1 "n'existe pas (ou n'est pas un fichier)." exit 2 fi echo ----------- >> resultatsMulti.txt echo $1 >> resultatsMulti.txt echo ----------- >> resultatsMulti.txt NB_LIGNES=`gzcat $1|wc -l` NB_SANS_RESUME=`gzcat $1|grep -v fC01|wc -l` NB_PERIODIQUES=`gzcat $1|grep "fA60><s1>P</"|wc -l` NB_FRANCAIS=`gzcat $1|grep "fA23 i1=\"01\"><s0>FRE</"|wc -l` NB_SANS_RES_100=`expr 100 \* $NB_SANS_RESUME` POURCENTAGE_SANS_RES=`expr $NB_SANS_RES_100 / $NB_LIGNES` echo "Pourcentage de notices sans résumé : ${POURCENTAGE_SANS_RES}%" \ >> resultatsMulti.txt NB_PERIO_100=`expr 100 \* $NB_PERIODIQUES` POURCENTAGE_PERIODIQUES=`expr $NB_PERIO_100 / $NB_LIGNES` echo "Pourcentage de notices de type périodique : ${POURCENTAGE_PERIODIQUES}%" \ >> resultatsMulti.txt NB_FRANCAIS_100=`expr 100 \* $NB_FRANCAIS` POURCENTAGE_FRANCAIS=`expr $NB_FRANCAIS_100 / $NB_LIGNES` echo "Pourcentage de notices françaises : ${POURCENTAGE_FRANCAIS}%" \ >> resultatsMulti.txt ;; esac shift done if test $COMPRESSION -eq 1 then touch resultatsMulti.txt gzip resultatsMulti.txt fi</pre> <p class="remarque"> L'utilisation du <code>case</code> à l'intérieur du <code>while</code> autorise l'apparition de l'option <code>-z</code> n'importe où sur la ligne de commande. </p> <p class="remarque"> L'instruction <code>touch resultatsMulti.txt</code> permet, lorsqu'aucun fichier n'a été passé en paramètre, et que l'option <code>-z</code> a été sélectionnée, de ne pas avoir de message d'erreur: <code>resultatsMulti.txt: No such file or directory</code>. On ne peut pas compresser un fichier qui n'existe pas. <code>touch</code> modifie la date de dernière modification d'un fichier, <em>mais aussi</em> elle crée un fichier lorsqu'il n'existe pas. </p> <p> <a href="tpShell.fre.html#name_resume4">Retour</a> </p> <hr> </li> <li><a name="resume5"></a> <p> Reprenez le shell précédent pour que le fichier résultat soit nommé avec une indication de date/heure à l'aide de la commande <code>date</code> d'Unix (notion de mise à jour). ATTENTION ! On considèrera le fichier <code>corpus2.xml.gz</code> comme une mise à jour de <code>corpus1.xml.gz</code>. Leur différence de nommage pourra par exemple être liée plutôt à l'heure qu'à la date.--> </p> <a href="tpShell.fre.html#name_resume5">Retour</a> <pre class="script"><span class="comment"># Fichier "resume5.sh" #!/bin/sh</span> if test $# -lt 1 then echo Mauvais nombre de parametres. echo echo Usage: $0 [-z] fichier... exit 1 fi NOM_FICHIER=resultatsMulti`date '+%H%M%S'`.txt COMPRESSION=0 while test $# -ne 0 do case $1 in -z ) COMPRESSION=1 ;; * ) if test ! -f $1 then echo $1 "n'existe pas (ou n'est pas un fichier)." exit 2 fi echo ----------- >> $NOM_FICHIER echo $1 >> $NOM_FICHIER echo ----------- >> $NOM_FICHIER NB_LIGNES=`gzcat $1|wc -l` NB_SANS_RESUME=`gzcat $1|grep -v fC01|wc -l` NB_PERIODIQUES=`gzcat $1|grep "fA60><s1>P</"|wc -l` NB_FRANCAIS=`gzcat $1|grep "fA23 i1=\"01\"><s0>FRE</"|wc -l` NB_SANS_RES_100=`expr 100 \* $NB_SANS_RESUME` POURCENTAGE_SANS_RES=`expr $NB_SANS_RES_100 / $NB_LIGNES` echo "Pourcentage de notices sans résumé : ${POURCENTAGE_SANS_RES}%" \ >> $NOM_FICHIER NB_PERIO_100=`expr 100 \* $NB_PERIODIQUES` POURCENTAGE_PERIODIQUES=`expr $NB_PERIO_100 / $NB_LIGNES` echo "Pourcentage de notices de type périodique : ${POURCENTAGE_PERIODIQUES}%" \ >> $NOM_FICHIER NB_FRANCAIS_100=`expr 100 \* $NB_FRANCAIS` POURCENTAGE_FRANCAIS=`expr $NB_FRANCAIS_100 / $NB_LIGNES` echo "Pourcentage de notices françaises : ${POURCENTAGE_FRANCAIS}%" \ >> $NOM_FICHIER ;; esac shift done if test $COMPRESSION -eq 1 then touch $NOM_FICHIER gzip $NOM_FICHIER fi</pre> <p> <a href="tpShell.fre.html#name_resume5">Retour</a> </p> <hr> </li> <li><a name="cumul"></a> <p> Écrivez un shell qui, reprenant les exercices précédents, calcule les statistiques sur le fichier <code>corpus1.xml.gz</code>, puis stocke les résultats en compressé. Ensuite, le même traitement sera porté sur <code>corpus2.xml.gz</code> considéré comme une mise à jour cumulative des statistiques (c'est-à-dire qu'il n'y aura qu'un seul fichier résultat repris puis écrasé au second traitement). </p> <a href="tpShell.fre.html#name_cumul">Retour</a> <pre class="script"><span class="comment"># Fichier "resume6.sh" #!/bin/sh</span> if test $# -lt 1 then echo Mauvais nombre de parametres. echo echo Usage: $0 [-z] fichier... exit 1 fi NOM_FICHIER=resultatsMulti`date '+%H%M%S'`.txt COMPRESSION=0 CUMUL_NB_LIGNES=0 CUMUL_NB_SANS_RESUME=0 CUMUL_NB_PERIODIQUES=0 CUMUL_NB_FRANCAIS=0 while test $# -ne 0 do case $1 in -z ) COMPRESSION=1 ;; * ) if test ! -f $1 then echo $1 "n'existe pas (ou n'est pas un fichier)." exit 2 fi echo ----------- >> $NOM_FICHIER echo $1 >> $NOM_FICHIER echo ----------- >> $NOM_FICHIER NB_LIGNES=`gzcat $1|wc -l` NB_SANS_RESUME=`gzcat $1|grep -v fC01|wc -l` NB_PERIODIQUES=`gzcat $1|grep "fA60><s1>P</"|wc -l` NB_FRANCAIS=`gzcat $1|grep "fA23 i1=\"01\"><s0>FRE</"|wc -l` CUMUL_NB_LIGNES=`expr $CUMUL_NB_LIGNES + $NB_LIGNES` CUMUL_NB_SANS_RESUME=`expr $CUMUL_NB_SANS_RESUME + $NB_SANS_RESUME` CUMUL_NB_PERIODIQUES=`expr $CUMUL_NB_PERIODIQUES + $NB_PERIODIQUES` CUMUL_NB_FRANCAIS=`expr $CUMUL_NB_FRANCAIS + $NB_FRANCAIS` NB_SANS_RES_100=`expr 100 \* $NB_SANS_RESUME` POURCENTAGE_SANS_RES=`expr $NB_SANS_RES_100 / $NB_LIGNES` echo "Pourcentage de notices sans résumé : ${POURCENTAGE_SANS_RES}%" \ >> $NOM_FICHIER NB_PERIO_100=`expr 100 \* $NB_PERIODIQUES` POURCENTAGE_PERIODIQUES=`expr $NB_PERIO_100 / $NB_LIGNES` echo "Pourcentage de notices de type périodique : ${POURCENTAGE_PERIODIQUES}%" \ >> $NOM_FICHIER NB_FRANCAIS_100=`expr 100 \* $NB_FRANCAIS` POURCENTAGE_FRANCAIS=`expr $NB_FRANCAIS_100 / $NB_LIGNES` echo "Pourcentage de notices françaises : ${POURCENTAGE_FRANCAIS}%" \ >> $NOM_FICHIER ;; esac shift done if test $CUMUL_NB_LIGNES -gt 0 then NB_SANS_RES_100=`expr 100 \* $CUMUL_NB_SANS_RESUME` POURCENTAGE_SANS_RES=`expr $NB_SANS_RES_100 / $CUMUL_NB_LIGNES` NB_PERIO_100=`expr 100 \* $CUMUL_NB_PERIODIQUES` POURCENTAGE_PERIODIQUES=`expr $NB_PERIO_100 / $CUMUL_NB_LIGNES` NB_FRANCAIS_100=`expr 100 \* $CUMUL_NB_FRANCAIS` POURCENTAGE_FRANCAIS=`expr $NB_FRANCAIS_100 / $CUMUL_NB_LIGNES` echo --------------- CUMUL >> $NOM_FICHIER echo "Pourcentage de notices sans résumé : ${POURCENTAGE_SANS_RES}%" \ >> $NOM_FICHIER echo "Pourcentage de notices de type périodique : ${POURCENTAGE_PERIODIQUES}%" \ >> $NOM_FICHIER echo "Pourcentage de notices françaises : ${POURCENTAGE_FRANCAIS}%" \ >> $NOM_FICHIER fi if test $COMPRESSION -eq 1 then touch $NOM_FICHIER gzip $NOM_FICHIER fi</pre> <p class="remarque"> On teste le nombre de lignes cumulées, car dans le cas où aucun fichier n'aurait été traité, la variable <code>CUMUL_NB_LIGNES</code> vaudrait zéro, et occasionnerait une erreur lors de la division! </p> <p> <a href="tpShell.fre.html#name_cumul">Retour</a> </p> <hr> </li> </ol> <hr> <address><a href="mailto:philippe.houdry@inist.fr">Philippe.Houdry@inist.fr</a></address> </body> </html>