I. Opérations matricielles en bash
Transcription
I. Opérations matricielles en bash
Année universitaire 2014/2015 Site : ⊠ Luminy St-Charles St-Jérôme Cht-Gombert Sujet de : ⊠ 1er semestre 2 ème semestre Session 2 ⊠ Aix-Montperrin Aubagne-SATIS Durée de l’épreuve : 2h Examen de : L2 Code du module : SIN3U7 Nom du diplôme : Licence d’Informatique Libellé du module : Programmation Unix 1 Calculatrices autorisées : NON Documents autorisés : OUI, notes de Cours/TD/TP Lisez l’énoncé en entier avant de commencer à rédiger. Ne répondez pas à plusieurs questions en même temps ; respectez le découpage de l’énoncé, sous peine de nullité. I. Opérations matricielles en bash On se propose de réaliser un script bash qui effectue des calculs matriciels simples, à partir de matrices de réels stockées dans des fichiers texte. 1) Écrire la fonction max_entiers qui reçoit en argument deux entiers, puis affiche le maximum des deux entiers sur la sortie standard. 2) Écrire la fonction est_reel qui reçoit un argument x. La fonction ne fait aucun affichage ; elle vérifie à l’aide d’une instruction case si x représente un réel (écrit avec les caractères 0-9, un signe "-" éventuel et un "." éventuel pour séparer la partie décimale), puis réussit ou échoue. La fonction devra accepter par exemple "0", "-0", ".41", "4.", "24.3", mais rejeter ⊲ les quatre chaı̂nes dégénérées "", "-", ".", "-." , ⊲ toutes les chaı̂nes contenant un caractère illégal, c’est-à-dire n’étant ni un chiffre, ni un signe "-" , ni un point (par exemple : "3c7"), ⊲ toutes les chaı̂nes contenant un signe "-" en position non préfixe (par exemple "89-54"), ⊲ toutes les chaı̂nes contenant plus d’un point (par exemple : "1.23.45"). 3) Écrire la fonction valider_reel qui reçoit un argument x. La fonction appelle la fonction est_reel pour vérifier si x représente un réel ; si c’est le cas elle affiche la valeur de x, sinon elle affiche 0 sur la sortie standard. 4) Écrire la fonction calculer_reel a b op qui reçoit en arguments deux réels a et b et un opérateur op valant "+" ou "-". La fonction remplace a et b par leur valeur validée par valider_reel, puis affiche sur la sortie standard le résultat de l’opération a op b, en se servant de la commande bc (avec une précision indicative de 6 décimales — bc n’en tient pas forcément compte pour ces opérations). Exemples : calculer_reel 2.3 1.1 + calculer_reel 2.3 1.1 calculer_reel 2.3 toto + # affiche 3.4 # 1.2 # 2.3 5) Écrire la fonction calculer_ligne lres la lb op qui reçoit par référence trois tableaux lres, la, lb, et un opérateur op valant "+" ou "-". Les tableaux la et lb contiennent chacun des réels. La fonction calcule le tableau lres où chaque case contient le résultat de calculer_reel pour les cases de la et lb de même indice et l’opérateur op. La taille de lres est le maximum des tailles de la et lb. T.S.V.P Programmation Unix 1, UE SIN3U7, Edouard Thiel — CC BY-NC — http://pageperso.lif.univ-mrs.fr/~edouard.thiel/ens/unix/ 1 6) Écrire la fonction calculer_matrice fic1 fic2 op qui reçoit en argument deux noms de fichiers fic1 et fic2, et un opérateur op valant "+" ou "-". La fonction lit en parallèle une ligne de réels dans fic1 et une ligne de réels dans fic2, et les stocke dans deux tableaux ligne1 et ligne2 à l’aide de la construction suivante : while read -a ligne1 <&3 && read -a ligne2 <&4 ; do # Corps de la boucle à remplir done 3< "$fic1" 4< "$fic2" Cette construction permet à la fonction de s’arrêter dès que la fin de l’un des deux fichiers est atteinte. Placer cette boucle dans la fonction et rajouter dans le corps de la boucle un test qui arrête la boucle dès que l’un des tableaux lus est vide. Pour chaque couple lu, appeler calculer_ligne dans le corps de la boucle puis afficher en une seule ligne les valeurs du tableau résultant sur la sortie standard. 7) On suppose disposer d’une fonction afficher_usage qui affiche sur la sortie standard l’usage du script, qui est calmatri.sh -add|-sub src1 src2 [res] Écrire le corps principal du script. Le script commence par vérifier la présence des arguments, sinon affiche l’usage sur la sortie d’erreur puis échoue. Le script convertit ensuite l’action -add ou -sub en un opérateur op valant "+" ou "-", sinon affiche l’usage sur la sortie d’erreur puis échoue. Le script vérifie ensuite l’accès en lecture aux fichiers texte src1 et src2, sinon affiche un message d’erreur et échoue. Enfin le script appelle calculer_matrice pour les fichiers et l’opérateur ; le résultat est soit affiché sur la sortie standard, soit enregistré dans le fichier res s’il a été donné en argument. Exemples : $ ./calmatri.sh USAGE: calmatri.sh -add|-sub src1 src2 [res] $ cat matrice1.txt 1.0 2.0 3.0 4.0 5.0 6.0 7.0 8.0 $ cat matrice2.txt 1.1 0.2 0.5 -0.6 0.7 0.8 $ ./calmatri.sh -add matrice1.txt matrice2.txt 2.1 2.2 3.0 4.0 5.5 5.4 7.0 8.0 $ ./calmatri.sh -sub matrice1.txt matrice2.txt difference.txt $ cat difference.txt -.1 1.8 3.0 4.0 4.5 6.6 7.0 8.0 Programmation Unix 1, UE SIN3U7, Edouard Thiel — CC BY-NC — http://pageperso.lif.univ-mrs.fr/~edouard.thiel/ens/unix/ 2 Correction I. Opérations matricielles en bash On se propose de réaliser un script bash qui effectue des calculs matriciels simples, à partir de matrices de réels stockées dans des fichiers texte. 1) Écrire la fonction max_entiers qui reçoit en argument deux entiers, puis affiche le maximum des deux entiers sur la sortie standard. max_entiers () # a b { local a="$1" b="$2" if ((a>b)) ; then echo "$a" ; else echo "$b" ; fi } 2) Écrire la fonction est_reel qui reçoit un argument x. La fonction ne fait aucun affichage ; elle vérifie à l’aide d’une instruction case si x représente un réel (écrit avec les caractères 0-9, un signe "-" éventuel et un "." éventuel pour séparer la partie décimale), puis réussit ou échoue. La fonction devra accepter par exemple "0", "-0", ".41", "4.", "24.3", mais rejeter ⊲ les quatre chaı̂nes dégénérées "", "-", ".", "-." , ⊲ toutes les chaı̂nes contenant un caractère illégal, c’est-à-dire n’étant ni un chiffre, ni un signe "-" , ni un point (par exemple : "3c7"), ⊲ toutes les chaı̂nes contenant un signe "-" en position non préfixe (par exemple "89-54"), ⊲ toutes les chaı̂nes contenant plus d’un point (par exemple : "1.23.45"). est_reel () # x { local x="$1" case "$x" in "" | . | - | -. | *[^0-9.-]* | ?*-* | *.*.* ) false ;; *) true ;; esac } 3) Écrire la fonction valider_reel qui reçoit un argument x. La fonction appelle la fonction est_reel pour vérifier si x représente un réel ; si c’est le cas elle affiche la valeur de x, sinon elle affiche 0 sur la sortie standard. valider_reel () # x { local x="$1" if est_reel "$x" ; then echo "$x" ; else echo "0" ; fi } 4) Écrire la fonction calculer_reel a b op qui reçoit en arguments deux réels a et b et un opérateur op valant "+" ou "-". La fonction remplace a et b par leur valeur validée par valider_reel, puis affiche sur la sortie standard le résultat de l’opération a op b, en se servant de la commande bc (avec une précision indicative de 6 décimales — bc n’en tient pas forcément compte pour ces opérations). Exemples : calculer_reel 2.3 1.1 + # affiche 3.4 calculer_reel 2.3 1.1 # 1.2 calculer_reel 2.3 toto + # 2.3 Programmation Unix 1, UE SIN3U7, Edouard Thiel — CC BY-NC — http://pageperso.lif.univ-mrs.fr/~edouard.thiel/ens/unix/ 3 calculer_reel () # a b op { local a="$1" b="$2" op="$3" a=$(valider_reel "$a") b=$(valider_reel "$b") echo "scale=6; $a $op $b" | bc } 5) Écrire la fonction calculer_ligne lres la lb op qui reçoit par référence trois tableaux lres, la, lb, et un opérateur op valant "+" ou "-". Les tableaux la et lb contiennent chacun des réels. La fonction calcule le tableau lres où chaque case contient le résultat de calculer_reel pour les cases de la et lb de même indice et l’opérateur op. La taille de lres est le maximum des tailles de la et lb. calculer_ligne () # lres la lb op { declare -n lres="$1" la="$2" lb="$3" local op="$4" i n n=$(max_entiers ${#la[*]} ${#lb[*]}) lres=() for ((i=0; i<n; i++)); do lres[i]=$(calculer_reel "${la[i]}" "${lb[i]}" "$op") done } 6) Écrire la fonction calculer_matrice fic1 fic2 op qui reçoit en argument deux noms de fichiers fic1 et fic2, et un opérateur op valant "+" ou "-". La fonction lit en parallèle une ligne de réels dans fic1 et une ligne de réels dans fic2, et les stocke dans deux tableaux ligne1 et ligne2 à l’aide de la construction suivante : while read -a ligne1 <&3 && read -a ligne2 <&4 ; do # Corps de la boucle à remplir done 3< "$fic1" 4< "$fic2" Cette construction permet à la fonction de s’arrêter dès que la fin de l’un des deux fichiers est atteinte. Placer cette boucle dans la fonction et rajouter dans le corps de la boucle un test qui arrête la boucle dès que l’un des tableaux lus est vide. Pour chaque couple lu, appeler calculer_ligne dans le corps de la boucle puis afficher en une seule ligne les valeurs du tableau résultant sur la sortie standard. calculer_matrice () # fic1 fic2 op { local fic1="$1" fic2="$2" op="$3" while read -a ligne1 <&3 && read -a ligne2 <&4 ; do if ((${#ligne1[*]} == 0 || ${#ligne2[*]} == 0)); then break; fi calculer_ligne ligneres ligne1 ligne2 "$op" echo "${ligneres[*]}" done 3< "$fic1" 4< "$fic2" } 7) On suppose disposer d’une fonction afficher_usage qui affiche sur la sortie standard l’usage du script, qui est calmatri.sh -add|-sub src1 src2 [res] Programmation Unix 1, UE SIN3U7, Edouard Thiel — CC BY-NC — http://pageperso.lif.univ-mrs.fr/~edouard.thiel/ens/unix/ 4 Écrire le corps principal du script. Le script commence par vérifier la présence des arguments, sinon affiche l’usage sur la sortie d’erreur puis échoue. Le script convertit ensuite l’action -add ou -sub en un opérateur op valant "+" ou "-", sinon affiche l’usage sur la sortie d’erreur puis échoue. Le script vérifie ensuite l’accès en lecture aux fichiers texte src1 et src2, sinon affiche un message d’erreur et échoue. Enfin le script appelle calculer_matrice pour les fichiers et l’opérateur ; le résultat est soit affiché sur la sortie standard, soit enregistré dans le fichier res s’il a été donné en argument. Exemples : $ ./calmatri.sh USAGE: calmatri.sh -add|-sub src1 src2 [res] $ cat matrice1.txt 1.0 2.0 3.0 4.0 5.0 6.0 7.0 8.0 $ cat matrice2.txt 1.1 0.2 0.5 -0.6 0.7 0.8 $ ./calmatri.sh -add matrice1.txt matrice2.txt 2.1 2.2 3.0 4.0 5.5 5.4 7.0 8.0 $ ./calmatri.sh -sub matrice1.txt matrice2.txt difference.txt $ cat difference.txt -.1 1.8 3.0 4.0 4.5 6.6 7.0 8.0 #! /bin/bash # Emplacement pour les fonctions afficher_usage () { cat << EOT USAGE: ${0##*/} -add|-sub src1 src2 [res] EOT } if (($# < 3)) ; then afficher_usage >&2 ; exit 1 ; fi action="$1" src1="$2" src2="$3" res="${4-/dev/stdout}" case "$action" in -add) op="+" ;; -sub) op="-" ;; *) afficher_usage >&2 ; exit 1 ;; esac test -r "$src1" || { echo "Erreur de lecture src1" >&2 ; exit 1 ;} test -r "$src2" || { echo "Erreur de lecture src2" >&2 ; exit 1 ;} calculer_matrice "$src1" "$src2" "$op" >| "$res" Programmation Unix 1, UE SIN3U7, Edouard Thiel — CC BY-NC — http://pageperso.lif.univ-mrs.fr/~edouard.thiel/ens/unix/ 5