Exercices de programmation avec l’interpréteur bash


Préambule : la documentation en ligne de l’interpéteur bash se trouve sous http://www.gnu.org/software/bash/manual/bashref.html

A-  Apéritif

Q.1. Ecrire un fichier shell qui prend en parametre 2 entiers et affiche la somme. S'il n'y a pas deux paramètres, il faut afficher un message d'erreur.

Q.2. Ecrire un script qui prend en paramètre trois entiers et qui affiche le plus grand. On affichera un message d'erreur s'il n'y pas pas trois arguments passés sur la ligne de commande.

Q.3. Ecrire un script shell qui affichera 5,4,3,2,1 en utilisant une boucle while.

Q.4. Ecrire un script qui utilisera une instruction case pour effectuer des opérations arithmétiques :
+ addition
- subtraction
x multiplication
/ division
Le nom du script doit être 'q4' et il s'utilisera comme suit :
$ ./q4 20 / 3

Vérifier également qu'il y a suffisamment de paramètres sur la ligne de commande.

Q.5. Ecrire un script qui listera : current date, time, username, and current directory

Q.6. Ecrire un script qui prend en paramètre un entier et affiche l'entier en ordre inverse (123 -> 321).

Q.7. Ecrire un script qui prend en paramètre un entier et affiche la somme des digits qui le compose (123 -> 1+2+3 = 6).

Q.8. Quelle commande Unix vous permet de réaliser de l'arithmétique sur les réels .

Q.9. Comment calculer  5.12 + 2.5 à partir du prompt Linux ?

Q.10. Comment réaliser dans un shell un calcul sur les réels ?Par exemple, on veut a=5.66, b=8.67, c=a+b.

Q.11. Ecrire un script qui détermine si un fichier donné en paramètre existe.

Q.12. Ecrire un script qui détrmine si l'argument $1 contient le symbole "*". Si $1 ne contient pas le symbole "*" ajoutez le à $1, sinon affichez le message "Symbol is not required". Le script se lance par :
$ Q12 /bin
Ici $1 est /bin, et puisque l'on n'a pas de "*" on affichera

/bin/*

Q.13. Ecrire un script qui affiche le contenu d'un fichier d'une ligne donnée à une autre. Si le script s'appelle Q13 :

$ Q13 5 9 myf
affiche le contenu du fichier myf de la ligne 5 a la ligne 9.

Q.14. Ecrire un script qui, au moyen de la commande getopts, affiche les options (de la forme -c, -d, -e) passées sur la ligne de commande. Si le script s'appelle Q14 alors on pourra lancer :
Q14 -c -d -e xemacs
et le programme affichera :
-c clear the screen
-d show list of files in current working directory
-e { editor } start this { editor } if installed

et il lancera une session xemacs.

Q.15. Ecrire un script que vous insérerez dans votre fichier .bash_profile. Il affichera :

Good Morning
Good Afternoon
Good Evening , selon l'heureQ.16. Ecrire un script qui affichera le message "Hello World", en gras et clignotant et dans différentes couleurs en utilisant la commande echo.
Q.17. Ecrire un script qui implémente un processus en arrière plan qui affichera continuellement l'heure courante

Q.18. Ecrire un script qui simule un menu permettant de réaliser les actions suivantes :


Menu-Item

Purpose

Action for Menu-Item

Date/time 

To see current date time

Date and time must be shown using infobox of dialog utility

Calendar

To see current calendar

Calendar must be shown using infobox of dialog utility

Delete

To delete selected file

First ask user name of directory where all files are present, if no name of directory given assumes current directory, then show all files only of that directory, Files must be shown on screen using menus of dialog utility, let the user select the file, then ask the confirmation to user whether he/she wants to delete selected file, if answer is yes then delete the file , report  errors if any while deleting file to user.

Exit

To Exit this shell script

Exit/Stops the menu driven program i.e. this script



Q.19. Ecrire un script qui vous permet d'afficher différentes informations sur le système :
1) Currently logged user and his logname
2) Your current shell
3) Your home directory
4) Your operating system type
5) Your current path setting
6) Your current working directory
7) Show Currently logged number of users
8) About your os and version ,release number , kernel version
9) Show all available shells
10) Show mouse settings
11) Show computer cpu information like processor type, speed etc
12) Show memory information
13) Show hard disk information like size of hard-disk, cache memory, model etc
14) File system (Mounted)
 

Q.20.Ecrire un script vous permettant de réaliser à l'écran le dessin suivant :

Ordinateur-de-Christophe-Cerin:~ cerin$ /bin/bash Q20.sh
Enter Number between (5 to 9) : 9
 
          .
         . .
        . . .
       . . . .
      . . . . .
     . . . . . .
    . . . . . . .
   . . . . . . . .
  . . . . . . . . .
  . . . . . . . . .
   . . . . . . . .
    . . . . . . .
     . . . . . .
      . . . . .
       . . . .
        . . .
         . .
          .
Ordinateur-de-Christophe-Cerin:~ cerin$ 

Q.21. Ecrire un script qui converti un fichier de majuscule à minuscule et vice et versa selon ce que l'on passe sur la ligne de commande.

Q.22 Editer un fichier pour qu’il contienne le texte suivant :

case $# in
    0) variable=`pwd`;;
    1) variable=$1 ;;
    *) echo "Erreur de syntaxe" ; exit;;
esac


a) Exécuter le code pour faire apparaître le message d’erreur

b) Modifier le code en ajoutant du texte après le esac pour que le programme affiche la valeur de variable si elle a été positionnée par `pwd`uniquement.

Q-23 La commande set sert a affecter les variables $0, $1 alors que la commande shift permet de décaler sur la gauche les valeurs des paramètres positionnels. Voir l’exemple suivant :

$ set ab cd
$ echo $1
ab
$ shift
$ echo $1
cd
$ shift
$ echo $1
 
$


Écrire un script permettant d'afficher à l'écran le contenu d'une série de fichiers dont les noms sont passés en paramètres, et n'utilisant pas de boucle for. Le message <nom fichier> inaccessible sera affiché si le fichier <nom fichier> est inexistant ou ne peut être lu.

Q-24 Écrire un script (en utilisant set, par exemple) permettant de convertir une date, renvoyée par la commande date, sous le format suivant (en français) :

Lundi 16 Decembre 1996 15:31:37

Note : on peut se servir de set et shift mais on ne peut pas faire quelque chose du genre :

$ date "+DATE: %m/%d/%y%nTIME: %H:%M:%S"
DATE: 10/03/05
TIME: 09:53:14

 

Q-25 Tapez sous le prompt de l’interpréteur bash les commandes suivantes et observez les résultats (certains peuvent être différents sur votre système, en particulier pour la commande pwd). En fait, les () permettent d’ouvrir et de fermer un nouveau shell. Expliquer ce qui s’est passé.

$ pwd
/users/linfg/linfg0
$ a=1
$ ( echo $a ; a=2 ; echo $a ; cd /usr/include ; pwd )
1
2
/usr/include
$ echo $a
1
$ pwd
/users/linfg/linfg0
$


Q-26 Taper le code suivant et observer les valeurs de a. Si vous n’obtenez pas 1 pour le premier affichage, que faut-il faire ? (voir la commande export)

$ a=1
$ bash
$ echo $a ; a=2 ; echo $a ; cd /usr/include ; pwd
$ exit


Q-27 Modifier le moins possible le code suivant pour faire apparaitre à l'écran que le chien et le chat sont des « animaux dosmestiques qui vivent à la maison » :

echo -n Enter the name of an animal:
read ANIMAL
echo -n The $ANIMAL has

Q-28 La commande shell select permet d’élaborer facilement des menus. Tapez le code suivant puis entrer un entier :

select fname in *;
do
        echo you picked $fname \($REPLY\)
        break;
done


Inspirez vous de ce texte pour ne lister que les fichiers d’extension txt ou doc. Vous pouvez utiliser l’expansion avec {}.

Q-29 Vous lancer la commande ps et vous la redirigez dans un fichier. Ecrire un script permettant d'afficher uniquement les processus triés par ordre alphabétique. Vous pouvez utiliser sort, uniq, cut... Modifiez votre script pour afficher le nom des processus ainsi que le nombre d'occurrences de ce processus.

Q-30 Créer un script test-fichier, qui précisera le type du fichier passé en paramètre, ses permissions d'accès pour l'utilisateur

Exemple de résultats :

Le fichier /etc est un répertoire
"/etc" est accessible par root en lecture écriture exécution
Le fichier /etc/smb.conf est un fichier ordinaire qui n'est pas vide
"/etc/smb.conf" est accessible par jean en lecture.


Q-31 Afficher le contenu d'un répertoire

Écrire un script bash listedir.sh permettant d'afficher le contenu d'un répertoire en séparant les fichiers et les (sous)répertoires.

Exemple d'utilisation :

$ ./listdir.sh 

affichera :

--------------   Fichiers dans /etc/rc.d --------------------
rc
rc.local
rc.sysinit
--------------   Repertoires dans /etc/rc.d --------------------
init.d
rc0.d
rc1.d
rc2.d
rc3.d
rc4.d
rc5.d
rc6.d


Q-32 Lister les utilisateurs

Écrire un script bash affichant la liste des noms de login des utilisateurs définis dans /etc/passwd ayant un UID supérieur à 500.

Indication : for in $(cat /etc/passwd) permet de parcourir les lignes du dit fichier.


Q
-33 lecture au clavier

La commande bash read permet de lire une chaîne au clavier et de l'affecter à une variable. exemple :

echo -n "Entrer votre nom: "
read nom
echo "Votre nom est $nom"

La commande file affiche des informations sur le contenu d'un fichier (elle applique des règles basées sur l'examen rapide du contenu du fichier).

Les fichiers de texte peuvent être affichés page par page avec la commande more.


1-  Tester ces trois commandes;


2-  Écrire un script qui propose à l'utilisateur de visualiser page par page chaque fichier texte du répertoire spécifié en argument. Le script affichera pour chaque fichier texte (et seulement ceux là) la question "voulez vous visualiser le fichier machintruc ?". En cas de réponse positive, il lancera more, avant de passer à l'examen du fichier suivant.

Q34  Gestion des notes

N1)  Écrire un script qui demande à l'utilisateur de saisir une note et qui affiche un message en fonction de cette note :
"très bien" si la note est entre 16 et 20
"bien" lorsqu'elle est entre 14 et 16
"assez bien" si la note est entre 12 et 14
"moyen" si la note est entre 10 et 12
"insuffisant" si la note est inférieur à 10

N2)  Reprenez l'exercice 1 et faites en sorte que le programme se répète tant que l'utilisateur n'ai pas saisi une note négative ou q (pour quitter). Le script doit calculer le nombre de notes saisies et en faire la moyenne tout à la fin.

N3)  Reprenez uniquement le code de l'exercice 1. La note peut cette fois être donnée en paramètre ou bien être saisie si elle n'a pas été trouvée en paramètre. La comparaison de la note devra être faite dans une fonction "appreciation".


B-   Plat principal

0- Un fichier contient des entiers au format binaire, un par ligne. Donner une commande sed qui permet d'afficher les entiers qui commencent et se terminent par 1 avec au milieu 2 à 4 zéro:

1- Ecrire un programme shell qui prend en paramètre un exécutable, qui va retrouver tous les numéros de processus et les détruire. Il s’agit de simuler la commande killall. Vous pouvez vous inspirer du code suivant :

#!/bin/bash
TITI="`echo $1`"
for i in `ps -hu | cut -c 8-14 `
do
  TOTO=`ps -h $i | cut -c 22- | grep -G $TITI | cut -f 1 -d " "`
  NUM=`echo $TOTO | wc -c `
  if test $NUM -ne 1; then
          ps -h $i
          echo "Detruction du PID $NUM"
          # kill –9 $NUM
  fi
done

2- Le texte qui suit permet de générer un fichier au format HTML. Expliquer le fonctionnement général en isolant les différentes parties. Expliquer les parties les plus techniques. Exécuter le code à partir d’un fichier de données que vous avez à créer. Rajouter l’envoi d’un mail à vous même (voir commande mail) dont le corps sera le fichier produit. Rajouter également le contrôle du nombre de paramêtres dans le fichier d’entrée. Vérifiez que les objets qui doivent être de type entier dans le fichier d’entrée le sont bien.

#!/bin/sh
 
# pour digerer le formulaire de registration
 
echo Content-type: text/HTML
echo
cat > /tmp/BIDON
 
NUMERO=`expr 0 + 1`
for i in `echo 1 2 3 4 5 6 7 8 9 10 11 12 13 14`
do
#eval TI$NUMERO="`cut -f $i -d \= /tmp/BIDON | cut -f 2 -d \& `"
#    NUMERO=`expr $NUMERO + 1`
    j=`expr $i + 1`
    eval TI$i="\"`cut -f $j -d \= /tmp/BIDON | cut -f 1 -d \& | tr \+ \ | sed -e '1,$s/\%0D\%0A/ /g' | sed -e '1,$s/\%09/ /g' | sed -e '1,$s/\%E9/\&eacute;/g' | sed -e '1,$s/\%7E/\~/g' | sed -e '1,$s/\%23/\#/g'  | sed -e '1,$s/\%7B/\{/g' | sed -e '1,$s/\%7D/\}/g' | sed -e '1,$s/\%28/\(/g' | sed -e '1,$s/\%29/\)/g' | sed -e '1,$s/\%5B/\[/g' | sed -e '1,$s/\%5D/\]/g' | sed -e '1,$s/\%E8/\&egrave;/g' | sed -e '1,$s/\%E0/\&agrave;/g' | sed -e '1,$s/\%26/\&amp;/g' | sed -e '1,$s/\%22/\&quot;/g' | sed -e '1,$s/\%7C/\|/g' | sed -e '1,$s/\%3C/\&lt;/g' | sed -e '1,$s/\%3E/\&gt;/g' | sed -e '1,$s/\%E7/\&ccedil;/g' | sed -e '1,$s/\%5E/\^/g' | sed -e '1,$s/\%F9/\&ugrave;/g' | sed -e '1,$s/\%25/\%/g' | sed -e '1,$s/\%2B/\+/g' | sed -e '1,$s/\%24/\$/g' | sed -e '1,$s/\%21/\!/g' | sed -e '1,$s/\%2F/\//g' | sed -e '1,$s/\%3A/\:/g' | sed -e '1,$s/\%3B/\;/g' | sed -e '1,$s/\%2C/\,/g' | sed -e '1,$s/\%3F/\?/g' | sed -e '1,$s/\%5C/\&backslash;/g'`\""
#    TI=$TI:"`cut -f $j -d \= /tmp/BIDON | cut -f 1 -d \& #| tr \+ \ | sed -e '1,$s/\%0D\%0A/ /g' | sed -e #'1,$s/\%09/ /g' `"
#    NUMERO=`expr $NUMERO + 1`
done
 
case $TI13 in
        "80")
               NUM=80
               ;;
        "284")
               NUM=284
               ;;
        "334")
               NUM=334
               ;;
        "317")
               NUM=317
               ;;
        "384")
               NUM=384
               ;;
esac
DEST="/tmp/registration-iscee98.html"
#rm /tmp/BIDON
EXEL="./exel.txt"
echo "$TI1   $TI2   $TI3   $TI4   $TI5   $TI6   $TI7   $TI8   $TI9   $TI10  $TI11        $TI12  $TI13  $TI14" >> $EXEL
#-----------------------------------------------------
cat << FIN1 > $DEST
<HTML>
<HEAD>
<TITLE>
ISCEE'98 Registration Form
</TITLE>
</HEAD>
<BODY BGCOLOR="#FFFFFF">
<CENTER>
<H3>
ISCEE'98 Registration Form
</H3>
Oct 8-9, 1998, Universit&eacute; de Melbourne</CENTER>
<HR>
<UL><P>
 
 
<B>Last name:</B> $TI1 &nbsp;&nbsp;
<B>First name:</B> $TI2<br>
<b>Name on Badge:</b> $TI3<br>
<B>Affiliation: </B>$TI4<br>
<b>Address:</b> $TI5<br>
<B>City: </B>$TI6<br>
<B>Phone Number: </B>$TI7 &nbsp;&nbsp;
<B>Fax Number: </B>$TI8<br>
<b>E-Mail: </b>$TI9<br>
<B>IEEE Number:</B>$TI10<br>
<b>HTTP: </b>$TI11<br>
<b>Special Diary:</b>$TI12<br>
<b>Registration Fees: </b>$TI13 US$ or `expr 6 \* $NUM` FF<br>
<b>Comment: </b> $TI14<br>
<P>
<br>
<br>
<P>Signature ____________________________<P>
</UL><P>
</UL><HR>
<pre>
Way of Payment (**): 
(**) Change fees will be paid by the participant. 
 
1- By check payable to VERNE-ADER 
 
2- By administration order form to VERNE-ADER: 
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;UPJV-Chemin du Thil-80025 Amiens Cedex 1-France 
 
3- By direct BankTransfer on the account: 
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Credit Lyonnais Melbourne 30002/05024/0000079046K20 
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(Please, indicate your identity and the name ISCEE'98.)
</pre>
Registration form along with payment must be MAILED to:<P>
<B>ISCEE'98</B><BR>
Melbourne - Australia<br>
Email: iscee98@melbourne.au
<p>
Please, FAX to 33-322827502 this form AND a copie of your
bank transfert form which contains the symposium name and your name in order to identify the payment. Thanks.
</p>
</UL>
</BODY>
</HTML>
FIN1
cat /tmp/registration-iscee98.html
 

3) On veut un script permettant de formater un fichier qui contient des lignes organisées en colonnes mais le séparateur de colonne et un ou plusieurs blancs ou encore \t. Par exemple, vous pouvez utiliser la commande column comme suit :

 

Ordinateur-de-Christophe-Cerin:~ cerin$ column -t titi
abc
efg  asdf
ijk  ert   fgv
qqq
Ordinateur-de-Christophe-Cerin:~ cerin$ more titi
        abc
efg asdf
        ijk ert    fgv
qqq

 

 Il vous faut donc simuler la commande column. Utilisez sed par exemple.

4) Le script suivant prend en paramètre un fichier texte et génère un fichier HTML :

 

Ordinateur-de-Christophe-Cerin:~ cerin$ more script.sed
2i\
<html>\
<head><title>sed generated html</title></head>\
<body bgcolor="#ffffff">\
<pre>
$a\
</pre>\
</body>\
</html>
 
Ordinateur-de-Christophe-Cerin:~ cerin$ more titi
        abc
efg asdf
        ijk ert         fgv
qqq
 
 
 
Ordinateur-de-Christophe-Cerin:~ cerin$
 
Ordinateur-de-Christophe-Cerin:~ cerin$ sed -f script.sed titi
        abc
<html>
<head><title>sed generated html</title></head>
<body bgcolor="#ffffff">
<pre>
efg asdf
        ijk ert         fgv
qqq
 
 
 
</pre>
</body>
</html>Ordinateur-de-Christophe-Cerin:~ cerin$
 

Le script repose sur les commandes d'insertion et de concaténation de sed. Veuillez le modifier pour insérer dès la première ligne et ajouter un \n en fin de fichier.  On vous demande ensuite de modifier script.sed pour que l'on puisse procéder au traitement suivant sur le fichier inséré : suppression des <tab> et blancs en tête de chaque ligne et mettre un seul blanc entre les mots. Supprimer également les lignes blanches de fin.

5- Utilisez sed pour réaliser les actions suivantes :

1. Print a list of files in your scripts directory, ending in ".sh". Mind that you might have to unalias ls. Put the result in a temporary file.

2. Fabriquer une liste des fichiers dans /usr/bin qui ont un a en deuxième position. Ranger le résultat dans un fichier temporaire.

3. Détruire les 3 premières lignes du fichier temporaire.

4. Afficher sur la sortie standard les fichier ayant comme motif "an".

5. Create a file holding sed commands to perform the previous two tasks. Add an extra command to this file that adds a string like "*** This might have something to do with man and man pages ***" in the line preceding every occurence of the string "man". Check the results.

6. A long listing of the root directory, /, is used for input. Create a file holding sed commands that check for symbolic links and plain files. If a file is a symbolic link, precede it with a line like "--This is a symlink--". If the file is a plain file, add a string on the same line, adding a comment like "<--- this is a plain file".


C-   Dessert

1- Etude d’un code

  1. Après avoir mis des commentaires dans le code qui suit, dites en une phrase ce que fait le code.

  2. Ajouter les codes permettant de créer les répertoires s’ils ne sont pas présents et qui va créer quelques fichiers « bidons » en entrée si le répertoire d’entrée n’existait pas.

  3. Exécutez le code et lister le résultat.

#!/bin/bash
#
 
#
# File    : addlog.sh
# Date    : avril 2nd, 2002
#
# Purpose: 
# Args   : -h for help
#          $1, dir1
#
 
 
# ------------------- Local Function
 
Help()
{ 
        echo
        echo `basename $0` [-h] dir1
        echo " -h : get this help msg";
        echo
 }
 
# ------------------- Main Function
 
# -------------------
 
if [ $# -lt 1 ]; then
        echo
        echo `basename $0` : too few args
        Help
        exit 1
fi
 
if [ $1 = "-h" ]; then
        Help
        exit 0
fi
 
inDir=$1
shift
 
if [ -d $inDir ]; then
    dirExist=1
else
    dirExist=0
fi
 
if [ $dirExist -ne 1 ]; then
    echo "$dirIn is not a valid directory"
    exit 2
fi
 
 
# ------------------- Main loop
 
scriptLogFile="ADDLOG.txt"
if [ -f $scriptLogFile ]; then
    echo $inDir >> $scriptLogFile
else
    echo $inDir > $scriptLogFile
fi
 
localDir=`pwd`
outDir=$localDir/total
inDir=$localDir/$inDir
 
cd $outDir
 
for fileIn in `ls $inDir/*.log`; do
 
  fileOut=`basename $fileIn`
 
  if [ -f $fileOut ]; then
 
    tempFile=`date | sed 's/ /_/g' | sed 's/:/_/g'`
    cp $fileIn $tempFile
    $localDir/rmline1.sh $tempFile
 
    cat $tempFile >> $fileOut
    rm -f $tempFile
 
  else
 
    cp $fileIn $fileOut
 
  fi
 
done
 
cd $localDir