<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>