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

Documents pareils