CSC 3102 – Introduction aux systèmes d’exploitation

Portail informatique

Devoir Hors Présentiel – Numération en Script shell

Cet exercice a pour but de vous familiariser à la manipulation des structures de base du script shell afin que leur utilisation ne soit pas un frein à la réalisation des séances de TP suivantes.

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.


Testez régulièrement vos avancées en lançant vos scripts avec différentes configurations d'arguments. Vous pouvez même scripter ces différents appels au sein d'un script shell indépendant afin d'automatiser vos tests.

Dans tous les cas, n'oubliez pas d'indiquer l'utilisation de l'interpréteur de commandes bash en écrivant à la première ligne de chaque script : #! /bin/bash et de les rendre exécutables grâce à la commande chmod u+x <mon_script.sh>.

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

ce scénario est un bon démarrage de banc de tests, à utiliser systématiquement pour évaluer le bon comportement de votre implémentation. Veillez à le compléter avec vos propres tests !

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.

Rendez ce script exécutable, et exécutez-le.

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.

Ouvrez un nouveau fichier nommé num.sh dans votre éditeur de code.

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.

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.

l'existence de l'opération sera traitée un peu plus tard.

L'ensemble des arguments suivants sont des entiers positifs auxquels il faudra plus tard appliquer l'opération venant d'être récupérée dans la variable op.
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 (seulement un message d'erreur sur la sortie standard d'erreur). Ainsi, en récupérant la sortie standard et en vérifiant qu'elle n'est pas vide, on s'assure que les opérandes sont des nombres entiers.

Vérifiez que les nombres dans args sont positifs.
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.
on ne traite pas la saisie interactive pour l'instant.
chaque script ne traite qu'un seul entier positif. Vous devez donc itérer ici sur chaque nombre de la liste.

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 lorsque demandé autrement (question 3.e). Pour toutes ces opérations, on ignore d'éventuels 0 inutiles au début des nombres. Par exemple, ./num.sh len 042 affiche 2.

pensez à bien tester vos scripts individuellement, au fut et à mesure. N'oubliez pas de les rendre exécutables avec commande chmod. Puis testez-les en les appelant au travers du script num.sh
pour être efficace, nous vous conseillons de scripter les tests individuels dans un script appelé test.sh par exemple.
Vous pouvez utiliser la commande expr pour faire des calculs sur des nombres.
Attention à protéger les caractères spéciaux représentant les opérations mathématiques pour expr.

Implémentez le script len.sh, qui affiche le nombre de chiffres du nombre en argument.

Implémentez le script mirror.sh, qui écrit à l'envers le nombre en argument.

Implémentez le script sum-digit.sh, qui affiche la somme des chiffres du nombre en argument.

Implémentez le script decimal_to_binary.sh, qui écrit en binaire le nombre décimal en argument.

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.

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 sur un même ensemble d'entiers positifs. Pour ce faire, l'opération saisie au lancement du script num.sh sera i ou int.

Travaillez dans une copie de num.sh, nommée num_interactif.sh.

Dans 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).

pour simplier la saisie, supposez que seule la lettre de l'opération voulue peut être saisie.

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.

ici aussi, et pour simplier la saisie, supposez que seule la lettre de l'opération voulue peut être saisie.

Faites en sorte de terminer num_interactif.sh si le caractère c (pour close) est saisi interactivement par l'utilisateur à la dernière étape de la boucle infinie écrite ci-dessus.