===== Scripts BASH =====
L'objectif de ce TD est de vous familiariser avec l'écriture de Scripts ''bash''.
==== Quelques Rappels ====
''bash'' est un shell de commandes permettant l'interaction de l'utilisateur avec le système d'exploitation. Ce langage de commandes, outre cette interactivité, permet d'automatiser des tâches. Ainsi, il dispose de certaines caractéristiques des langages de programmation plus << classiques >>, comme la manipulation de variables - cependant rudimentaire - le conditionnement de blocs d'instruction, la répétition, etc. Quelques éléments de rappel :
* Un ''bash''-script est un fichier texte/source contenant une succession de commandes ''bash''
* Toute commande << valide >> dans le terminal l'est également au sein d'un ''bash''-script
* Un passage à la ligne au sein d'un ''bash''-script correspond à la validation dans le terminal
* un ''bash''-script débute toujours par : ''#!/bin/bash'' (c'est le ''shebang'')
==== Q.1 - Hello World ====
Ecrire le ''bash''-script correspondant au classique << ''hello world'' >>
==== Q.2 - Création de fichiers et redirection de STDOUT ====
Ecrire un shell-script, créant dans le dossier courant s'il n'existe pas déjà, un répertoire dont le nom est passé en premier argument. Il créera dans ce dossier 10 fichiers nommés << Un >> à << Dix >> contenant respectivement << file Un >> à << file Dix >>
==== Q.3 - Instruction conditionnelle ====
Ecrire un shell-script admettant 2 nombres en paramètres et affichant le plus grand des deux.
==== Q.4 - Ai-je un mail ? ====
Les mails s'accumulent au sein d'un spooler au nom de l'utilisateur. Ainsi, un nouveau mail arrivant pour ''$USER'' sera habituellement déposé par le système dans le dossier ''/var/spool/mail/$USER''. Ecrire un ''bash''-script qui vérifie s'il y a du courrier pour un utilisateur dont le nom sera passé en argument.
{{ :bash-quick-reference.pdf | Voir la section 'conditional expressions' de la BASH refcard}}
Pour résultat, on affichera sur la sortie standard un des messages suivants :
Pas de courrier pour .
Courrier du jour pour .
Courrier en retard pour .
==== Q.5 - Boucles et table de multiplications ====
Ecrire un script nommé ''table.sh'' permettant l'affichage des ''p'' premières lignes de la table de multiplication d'un nombre ''n''. ''p'' et ''n'' sont passés en paramètre.
==== Q.6 - Boucles et calcul d'une série ====
Ecrire un ''bash''-script qui affiche les valeurs successives de la suite définie par :
{{ :u_n_1_u_n_2_si_.png?250 |}}
La valeur de ''k'' est passée en argument de la commande. L'exécution du script se stoppe lorsque le terme est égal à 1.
==== Q.7 - Trouver le plus petit ====
Ecrire un ''bash''-script admettant un nombre variable de valeurs entières en paramètre. Elle renvoie sur la sortie standard la plus petite.
==== Q.8 - Compréhension du metacaractère '*' ====
On considère la séquence de commandes suivante :
% mkdir rep
% cd rep
% touch echo
% touch hello
% *
hello
%
Que se produit-il quand on saisit les commandes suivantes ? Expliquez-en la raison.
% * *
puis
% * ; *
==== Q.9 - Premiers usages des tubes ====
A l'aide de la commande ''cut'', reprenez le ''bash''-script de la question 5 afin qu'il admette indépendamment le paramétrage suivant :
% ./table.sh p=5 n=6
et
% ./table.sh n=6 p=5
Dans les deux cas, la sortie standard sera identique.
==== Q.10 - Compter des lignes ====
A l'aide de la commande ''wc'', écrire un ''bash''-script nommé ''sup.sh'' tel qu'il admette le paramétrage suivant : ''./sup.sh rep1 rep2''. ''rep1'' et ''rep2'' sont tous deux des dossiers. Ce point, ainsi que le nombre de paramètres doivent être vérifiés par ''sup.sh''. Le traitement réalisé par ''sup.sh'' permet de savoir lequel des deux contient le plus grand nombre de références (i.e. dossiers et fichiers). En cas d'égalité, ''sup.sh'' affichera le message : ''dossiers ayant le même nombre d'entrées''.
==== Q.11 - Lister le contenu d'une branche entière ====
Ecrire un ''bash''-script ''listebranche'' qui affiche le contenu de tous les dossiers qui figurent dans le chemin allant de la racine ''/'' à votre dossier courant, par exemple:
$ pwd
/home/enseign
$ ./listbranche
/home/enseign
joiron lemahec ionica dequen ferment groult ...
/home
adminsys master enseign invite licence ...
/
bin etc home users ...
==== Q.12 - Vérification de chemin ====
Quand une commande (par exemple ''cd'') prend en argument un chemin absolu et que celui-ci n'existe pas, un message comme '' not found'' sera affiché, sans plus de précision. Ecrire un ''bash''-script nommé ''check-path.sh'' qui affiche sur la sortie standard la partie gauche du chemin inexistant, en s'arrêtant sur le répertoire qui n'existe pas. Par exemple :
$ ./check-path.sh /home/lissence/toto
/home/lissence n\'existe pas
==== Q.13 - Qui a le plus grand UID ? ====
Une entrée du fichier des utilisateurs << ''/etc/passwd'' >> a la forme suivante:
root:*:0:0:System Administrator:/var/root:/bin/sh
la valeur de l'''UID'' correspond au nombre situé entre le second et le troisième << '':'' >> pour chacune de ces lignes. Quel utilisateur, représenté par son ''login'' possède le plus élevé ?
==== Q.14 - Tri ====
A l'aide de la commande ''sort'', proposez un ''bash''-script qui affiche ses arguments en les triant par ordre alphabétique.
==== Q.15 - Le dernier argument ====
Proposez une commande nommée ''lastarg.sh'' qui affiche sur la sortie standard son dernier argument.
==== Q.16 - A propos des chemins par défaut ====
On souhaite utiliser la variable d'environnement ''$PATH'' qui est de la forme :
/opt/local/bin:/opt/local/sbin:/opt/local/bin:/usr/local/bin:/usr/bin:/bin:/Users/gilles/bin
''$PATH'' contient l'ensemble des chemins du système dans lesquels les commandes sont directement accessibles par la ligne de commande. La séparation entre chaque chemin est faite par le caractère '':''. Ecrire un ''bash''-script qui admet en argument une liste de fichiers. Notre commande ''is-in-path.sh'' teste pour chacun de ses arguments son appartenance à l'un des dossiers dont le chemin absolu est présent dans la variable ''PATH''.
==== Q.17 - Endormir un processus ====
Proposez un ''bash''-script qui attend et se met en veille jusqu'à la prochaine heure pleine. On n'appellera qu'une seule fois la commande ''date'', qui affiche les informations suivant le format :
Jeu 17 jan 2019 16:40:08 CET
<< Endormir >> le déroulement d'un script se fait à l'aide de la commande ''sleep'' qui admet en paramètre une valeur entière correspondant à un nombre de secondes (e.g ''sleep 10'' attendra 10 secondes). Dans le cas d'exemple ci-dessus, notre commande ''heure-pleine.sh'' devra se terminer vers ''17:00'' heures, soit 1192 secondes après l'appel à ''date'' (on néglige le temps d'exécution de quelques appels à des fonctions comme ''expr'').
==== Q.18 - Récursivité ====
=== Q.18 a) LS ===
Sans utiliser ''ls'', proposez un ''bash''-script qui liste l'ensemble des fichiers contenus dans un dossier sui est passé en paramètre.
=== Q.18 b) LS récursif ===
Enrichissez la réponse précédente et proposez un ''bash''-script nommé '' my-ls.sh'' qui admet en paramètres des noms de dossiers (ce point sera vérifié) et qui liste tous les fichiers contenus dans l'arborescence enracinée à partir de chaque paramètre. Le nom de chaque fichier devra être précédé de son adressage absolu.
==== Q.19 - Nettoyage ====
A partir de la réponse faite à la question précédente, écrivez un ''bash''-script qui prend en argument des noms de dossiers et qui efface tous les fichiers dont le nom se termine par le caractère '''~''' contenus dans l'arborescence enracinée dans chaque dossier. il ne vous est pas autorisé d'utiliser l'option ''-r'' de la commande ''rm''.
==== Q.20 - Comptage ====
Ecrire un filtre, nommé ''cptvide.sh'', qui affiche sur la sortie standard le nombre de lignes vides du flux d'entrée. On considère qu'une ligne vide est une ligne qui commence par un certain nombre éventuellement nul de blancs puis un retour à la ligne. Cet exercice fait appel à des premières notions relatives aux expressions régulières.
==== Q.21 - Double écho ====
Proposez un filtre qui répète deux fois chaque ligne de l'entrée standard.
==== Q.22 - Taille d'un dossier ====
La commande ''ls -l'' fournit la sortie standard suivante :
% ls -l
total 8
drwxr-xr-x 2 gilles staff 64 16 jan 08:49 dir1
drwxr-xr-x 2 gilles staff 64 16 jan 08:56 dir2
drwxr-xr-x 3 gilles staff 96 16 jan 08:57 dir3
-rw-r--r--@ 1 gilles staff 8 16 jan 09:25 lien-p
lrwxr-xr-x 1 gilles staff 5 16 jan 09:21 lien-s -> vide1
-rw-r--r-- 1 gilles staff 0 16 jan 08:48 toto
La taille de chaque entrée est spécifiée sur la cinquième colonne de cette sortie. Proposez un ''bash''-script qui affiche le cumul des tailles des entrées - fichiers et dossiers - pour chaque dossier passé en argument. On ne considère pas les sous--répertoires.
==== Q.23 - Taille d'une branche ====
En partant de la question précédente et en vous inspirant des réponses faites pour les questions 18.b et 19, propsez un ''bash''-script qui affiche le cumul des tailles des branches - uniquement les fichiers - enracinées dans chaque dossier passé en paramètre.
==== Q.24 - Recherche de singletons ====
Ecrire une commande qui affiche le nom des fichiers du répertoire courant qui n'existent pas dans un des sous-répertoires du répertoire courant (on ne considèrera que les sous-répertoires directs du répertoire courant).
==== Q.25 - Qui sont les plus grands ? ====
Proposez un ''bash''-script qui affiche les noms des fichiers du répertoire courant qui ont une taille supérieure ou égale à un nombre passé en argument. S'il n'y a pas d'argument, la taille minimale par défaut est fixée à 1024 octets. Pour mémoire, la commande ''ls -l'' (que vous n'êtes pas obligés d'utiliser) renvoie des informations sous le format suivant :
% ls -l
total 8
drwxr-xr-x 2 gilles staff 64 16 jan 08:49 dir1
drwxr-xr-x 2 gilles staff 64 16 jan 08:56 dir2
drwxr-xr-x 3 gilles staff 96 16 jan 08:57 dir3
-rw-r--r--@ 1 gilles staff 8 16 jan 09:25 lien-p
lrwxr-xr-x 1 gilles staff 5 16 jan 09:21 lien-s -> vide1
-rw-r--r-- 1 gilles staff 0 16 jan 08:48 toto
==== Q.26 - Multi move ====
Proposez une commande nommée ''mmv.sh'' qui permet de renommer une série de fichiers passés en paramètres. Le nombre de paramètres sera toujours pair.
% ls
ex1.c ex2.c ex3.c titi toto
% ./mmv.sh *.c *.c.bak
% ls
ex1.c.bak ex2.c.bak ex3.c.bak titi toto
% mmv titi toto tutu tata
% ls
ex1.c.bak ex2.c.bak ex3.c.bak tutu tata