Devoir Hors Présentiel – Numération en Script shell
L'exercice consiste à appliquer différentes opérations à une liste d'entiers. Vous allez écrire plusieurs scripts shell pour effectuer ces opérations, ainsi qu'un script principal. Celui-ci permet de sélectionner l'opération, et d'envoyer la liste d'entiers, donnés en paramètres, au script implémentant l'opération. Pour cela, nous procédons pas à pas.
Le devoir doit être rendu via la section dédiée sur la page Moodle du cours. La forme de rendu attendue est l'ensemble des fichiers de script shell que vous allez écrire. Une archive Zip, GZip, Tar, etc. est aussi acceptée.
La charge de travail personnel prévisionnelle pour ce DM est estimée à 3h. Vous êtes incités à le réaliser en autonomie afin de vous familiariser avec les scripts shell. Vous êtes néanmoins autorisés à le réaliser en binôme : dans ce cas, l'un doit rendre le devoir tandis que l'autre doit rendre sous Moodle un fichier indiquant uniquement le nom du binôme avec qui il a travaillé.
Bon travail !
Readme
Avant d'entamer la partie calculatoire de l'exercice, voici un scénario d'exécution attendu du script num.sh que vous allez implémenter dans les parties suivantes :
$ ./num.sh len 123 4 3 1 $ ./num.sh mir 123 4 56 321 4 65 $ ./num.sh s 123 6 $ ./num.sh Erreur : Argument manquant num.sh applique une opération à chaque nombre d'une liste de nombres entiers positifs donnés en argument. ./num.sh [OP] [ARGS]... OP est l'opération à appliquer, à choisir parmi : * l ou len (pour longueur) : afficher le nombre de chiffres de chaque nombre * m ou mir (pour miroir) : écrire chaque nombre à l'envers (en miroir) * s ou sum (pour somme) : afficher la somme des chiffres de chaque nombre * b ou bin (pour binaire) : écrire chaque nombre, donné sous forme décimale, en binaire * d ou dec (pour décimal) : écrire chaque nombre, donné sous forme binaire, en décimal * i ou int (pour interactif) : commencer la saisie interactive de l'opération à appliquer aux nombres ARGS est la liste des nombres entiers positifs à traiter. $Remarquez que le dernier lancement du script num.sh ci-dessus aboutit à un message d'erreur, suivi de l'affichage du mode d'emploi de la commande.
Écrivez un script readme.sh qui affiche ce mode d'emploi.
Récupération des arguments et mise en place du squelette calculatoire
L'objet de cette partie consiste à écrire le script num.sh, qui est en charge de récupérer les arguments qui lui sont passés, puis de lancer l'opération demandée sur ceux-ci s'ils sont conformes.
Dans un premier temps, le script vérifie la conformité des arguments :
- le premier argument doit correspondre à une opération prévue par le mode d'emploi de la commande num.sh (cf. le script readme.sh réalisé à la partie précédente) ;
- tous les arguments suivants doivent être des entiers positifs.
Dans un second temps, le script exécute l'opération voulue sur ces entiers positifs.
num.sh applique une opération à une liste d'entiers positifs. Ainsi, un appel correct doit obligatoirement comporter au moins deux arguments : une opération et une opérande.
Testez que le nombre d'arguments passés est correct. En cas d'erreur, affichez un message de sortie d'erreur adéquat, lancez le script readme.sh et terminez num.sh.
Dans une variable op, récupérez la valeur du premier argument.
S'il est indiqué dans sa version longue, utilisez un schéma alternatif pour le normaliser sous la forme de sa lettre unique.
Par exemple, l'opération convertissant un entier binaire en décimal peut être invoquée soit en utilisant le mot dec, soit la lettre d.
Si dec est utilisé, modifiez la valeur de la variable op pour qu'elle soit égale à d.
Après avoir décalé d'un cran la liste des paramètres, stockez dans la variable args l'ensemble des arguments restants.
Vérifiez que les nombres dans args sont des entiers.
Pour ce faire, testez sur chacun d'eux l'évaluation d'une opération arithmétique quelconque. En cas d'erreur, affichez un message de sortie d'erreur adéquat, lancez le script readme.sh et terminez num.sh.
Pour lancer l'évaluation d'une opération arithmétique, utilisez la commande expr comme suit : isnum="$(expr 0 + "$arg" 2>/dev/null)", avec arg la variable contenant le nombre à tester. Ensuite, testez si la variable isnum est vide. Si c'est le cas, alors expr a échoué : arg n'est pas un nombre entier.
Si la commande expr échoue, elle ne produit rien sur la sortie standard, mais seulement un message d'erreur sur la sortie d'erreur standard. La commande proposée consiste donc à éliminer la sortie d'erreur standard (en la redirigeant vers /dev/null) pour ne récupérer que la sortie standard. Ensuite, en vérifiant qu'elle n'est pas vide, on s'assure que les opérandes sont des nombres entiers.Dans le cas contraire, affichez un message de sortie d'erreur adéquat, lancez le script readme.sh et terminez num.sh.
Maintenant que les différents arguments sont corrects et stockés dans des variables indépendantes, il reste à lancer l'opération voulue sur chaque nombre dans args.
Lancer une opération consiste à appeler un script avec un nombre en argument : ce script applique l'opération sur ce nombre.
Implémentez l'aiguillage vers l'appel du script effectuant l'opération, à l'aide d'une structure de contrôle permettant un choix alternatif multiple.
Les scripts seront implémentés dans la partie suivante, et seront nommés comme suit :
- len.sh : afficher le nombre de chiffres (la longueur) de l'entier passé en argument ;
- mirror.sh : écrire à l'envers (en miroir) l'entier passé en argument ;
- sum_digit.sh : afficher la somme des chiffres de l'entier passé en argument ;
- decimal_to_binary.sh : écrire en binaire l'entier positif décimal passé en argument ;
- binary_to_decimal.sh : écrire en décimal l'entier positif binaire passé en argument.
Si la variable op ne correspond à aucune des opérations décrites dans le script readme.sh, affichez un message de sortie d'erreur adéquat, lancez le script readme.sh et terminez num.sh.
Implémentation des différentes opérations
Dans cette partie, vous devez implémenter chaque opération dans un script séparé. Un script ne traite qu'un seul nombre entier positif.
Comme ces sous-scripts seront principalement invoqués depuis le script principal, ne vous souciez pas de vérifier la conformité de l'argument (sauf pour le script binary_to_decimal.sh de la question 3.e). Pour toutes ces opérations, on ignore d'éventuels 0 inutiles au début des nombres en entrée. Par exemple, ./num.sh len 042 affiche 2 ; et ./num.sh mir 04200 affiche 0024.
- extraire sa conversion vers la base numérique de destination avec une opération modulo ;
- avancer en enlevant sa conversion (diviser par la base numérique de destination) ;
- concaténer dans le bon ordre le chiffre converti dans une variable d'accumulation.
Implémentez le script binary_to_decimal.sh, qui écrit en décimal le nombre binaire en argument.
Ici, il est possible que l'argument soit invalide : ce peut être un nombre entier positif qui contient des chiffres invalides en binaire, c'est-à-dire différents de 0 et de 1. Prenez ce cas d'erreur en considération : affichez un message de sortie d'erreur adéquat, lancez le script readme.sh et terminez binary_to_decimal.sh.
Dans un nombre d'une base numérique donnée, chaque chiffre indique le multiplicateur à appliquer à la puissance de cette base pour la position du chiffre, et le résultat est la somme de toutes ces puissances.
Par exemple pour le nombre 110 en binaire :
- le 0 signifie qu'il y a 0 fois la puissance 0 de la base 2 dans le nombre converti ;
- le 1 du centre signifie qu'il y a 1 fois la puissance 1 de la base 2 dans le nombre converti ;
- le 1 de gauche signifie qu'il y a 1 fois la puissance 2 de la base 2 dans le nombre converti.
- extraire le chiffre avec une opération modulo ;
- avancer en enlevant le chiffre (division) ;
- ajouter dans une variable d'accumulation, la puissance de 2 correspondant à la position du chiffre multipliée par ce dernier.
Une version interactive
Dans cette dernière partie, il s'agit de permettre le choix interactif de l'opération de manière à pouvoir en appliquer plusieurs d'affilée sur le même ensemble d'entiers positifs donnés en arguments du script. Pour ce faire, l'opération saisie au lancement du script num.sh sera i ou int.
Voici un exemple d'utilisation du mode interactif :
$ ./num_interactif.sh i 123 4 56 Saisissez une opération parmi l, m, s, b, d ; ou c pour mettre fin au mode interactif. > m 321 4 65 Saisissez une nouvelle opération parmi l, m, s, b, d ; ou c pour mettre fin au mode interactif. > b 1111011 100 111000 Saisissez une nouvelle opération parmi l, m, s, b, d ; ou c pour mettre fin au mode interactif. > l 3 1 2 Saisissez une nouvelle opération parmi l, m, s, b, d ; ou c pour mettre fin au mode interactif. > cDans num_interactif.sh, si le mode interactif est demandé, positionnez une variable interactive à "true" (ou toute autre valeur pour signifier l'activation du mode interactif). Demandez ensuite la saisie au clavier de l'opération à appliquer (parmi l, m, s, b ou d).
Encapsulez l'aiguillage de l'opération à appliquer (cf. question 2.g) dans une boucle infinie. La dernière étape de cette boucle consiste à demander la saisie d'une nouvelle opération dans le cas où le mode interactif est activé ; sinon il faut mettre fin à la boucle infinie.