Corrigé du TP - Shell - UNIX

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.

Recherche d'information sur un utilisateur

  1. É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).
    Le nom recherché sera passé comme paramètre au shell.
    La recherche portera dans le fichier /etc/passwd.

    Retour
    # Fichier "infouser1.sh"
    #!/bin/sh
    grep $1 /etc/passwd

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

    Retour
    # Fichier "infouser2.sh"
    #!/bin/sh
    
    if test $# -ne 1
    then
    	echo Mauvais nombre de parametres.
    	echo
    	echo Usage: $0 uid
    	exit 1
    fi
    
    grep $1 /etc/passwd

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

    Retour
    # Fichier "infouser3.sh"
    #!/bin/sh
    
    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

    Par défaut, le shell s'arrête avec un statut à zéro, c'est pourquoi une ligne exit 0 à la fin du programme est superflue.

    Le test effectué est -lt 1 (plus petit que 1), mais on aurait tout aussi bien pu faire -eq 0.

    Le texte de sortie contient des \', 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).

    On aurait pu aussi utiliser un test plus simple sur le résultat de grep $1 /etc/passwd, et le transformer en if test ! $?.

Édition de statistiques sur un corpus XML

Pour cette partie du TP, il vous faut d'abord récupérer les deux corpus suivants :
corpus1.xml.gz
corpus2.xml.gz
Ces deux fichiers contiennent 25 notices en XML Dilib, leur exploration préparatoire est conseillée.

  1. É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.
    Les fichiers ne devront jamais être décompressés sur disque.
    L'élément résumé se nomme fC01.

    Retour
    # Fichier "resume1.sh"
    #!/bin/sh
    
    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}%

    N'oubliez pas de banaliser l'opérateur de multiplication, sinon expr ne comprendra pas ce que vous demandez (man expr pour plus de détails).

    gzcat est utilisé, mais on pourrait aussi utiliser gunzip -c.


  2. 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é resultatsfC01.txt.

    Retour
    # Fichier "resume2.sh"
    #!/bin/sh
    
    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

    Cette fois, on a mis la chaîne contenant les apostrophes (caractère spécial) entre guillemets pour les banaliser.


  3. É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.
    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 while.
    Les statistiques obtenues seront récupérées dans le fichier resultatsMulti.txt.
    Les éléments à utiliser sont fA60 pour le type de document (P pour périodique) et fA23 pour la langue (FRE pour la langue française).

    Retour
    # Fichier "resume3.sh"
    #!/bin/sh
    
    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

    shift est utilisé pour parcourir tous les paramètres et considérer chacun d'entre eux comme le paramètre numéro 1.

    Le rm -f resultatsMulti.txt est là pour éviter la concaténation des résultats avec ceux des exécutions précédentes du même script.

    Pour plus de précision, on pourrait utiliser la commande DILIB SgmlSelect plutôt que grep, pour sélectionner les notices françaises (en effet, si l'attribut i1 changeait, la commande de comptage deviendrait plus compliquée avec grep).

    Le caractère \ en fin de ligne permet de passer à la ligne sans interrompre la commande. C'est une facilité de présentation.

    Retour


  4. Modifiez le shell précédent pour que le fichier résultat soit compressé au choix (Oui/Non).

    Retour
    # Fichier "resume4.sh"
    #!/bin/sh
    
    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

    L'utilisation du case à l'intérieur du while autorise l'apparition de l'option -z n'importe où sur la ligne de commande.

    L'instruction touch resultatsMulti.txt permet, lorsqu'aucun fichier n'a été passé en paramètre, et que l'option -z a été sélectionnée, de ne pas avoir de message d'erreur: resultatsMulti.txt: No such file or directory. On ne peut pas compresser un fichier qui n'existe pas. touch modifie la date de dernière modification d'un fichier, mais aussi elle crée un fichier lorsqu'il n'existe pas.

    Retour


  5. 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 date d'Unix (notion de mise à jour). ATTENTION ! On considèrera le fichier corpus2.xml.gz comme une mise à jour de corpus1.xml.gz. Leur différence de nommage pourra par exemple être liée plutôt à l'heure qu'à la date.-->

    Retour
    # Fichier "resume5.sh"
    #!/bin/sh
    
    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

    Retour


  6. Écrivez un shell qui, reprenant les exercices précédents, calcule les statistiques sur le fichier corpus1.xml.gz, puis stocke les résultats en compressé. Ensuite, le même traitement sera porté sur corpus2.xml.gz 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).

    Retour
    # Fichier "resume6.sh"
    #!/bin/sh
    
    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

    On teste le nombre de lignes cumulées, car dans le cas où aucun fichier n'aurait été traité, la variable CUMUL_NB_LIGNES vaudrait zéro, et occasionnerait une erreur lors de la division!

    Retour



Philippe.Houdry@inist.fr