Vous êtes sur la page 1sur 38

Labo Environnement Unix/Linux

Exercices corrigés en shell

© Dr. Mohamed Saïd OUERGHI 2020

1/38
Exercices SHELL

Exercice 1 :
Après avoir visualisé le résultat de la commande env (diverses valeurs de
variables prédéfinies), écrire un script shell qui en affiche certains ainsi que celles
relatives au script et ses arguments.

#sh1: script affichant la valeur de plusieurs


#variables prédéfinies de l'environnement et du shell
echo directory home : $HOME
echo user logname : $LOGNAME
echo my mailbox : $MAIL
echo path value : $PATH
echo shell commands : $SHELL
echo terminal type : $TERM
echo script name : $0
echo script pid : $$
echo arguments number : $#
echo list of arguments : $*

Exercice 2 :
Ecrire un script shell manipulant les quotes (simple, double et anti).

#sh2 : script manipulant les quotes

var=exemple
echo contenu de var : $var
echo "contenu de var : $var"
echo 'contenu de var : $var'
echo `echo contenu de var : $var`

echo ceci est l\'exemple type de l\'apostrophe


echo "ceci est l'exemple type de l'apostrophe"

2/38
Exercice 3 :
Ecrire un script shell permettant l’affichage de plusieurs façons de la liste des
ses paramètres effectifs.

#sh3 : sript obtention des paramètres d'un script

echo nom du script : $0


echo nombre d\'arguments d\'appel : $#

if test $# -eq 0
then
echo liste de paramètres vide
else
echo liste des paramètres obtenus par \$* : $*
echo liste des paramètres obtenus par \$@ : $@
echo –e "liste des paramètres affichés par une boucle for : \n"
for i
do echo –e "$i \c"
done
echo –e "\nliste des paramètres obtenus par une boule while :"
while test $# -ne 0
do echo –e "$1 \c";
shift
done
fi

Exercice 4 :
Ecrire un script shell affichant la liste des caractères spéciaux en indiquant
chaque fois sa classe

#sh 4 : liste des caractères spéciaux du shell

echo les caractères spéciaux sont :


echo -e "\t les différentes quottes : \( \" \' \` \)"
echo -e "\t les parenthèses et assimilés \( \[ \] \) \( \{ \} \)"
echo -e "\t les symboles de ponctuations : \( \. \: \; \)"
echo -e "\t les opérateurs arithmétiques: \( \+ \- \* \/ \% \)"
echo -e "\t les opérateurs de comparaison : \( \> \< \= \! \| \& \)"
echo -e "\t les symboles spéciaux : \( \\ \? \@ \$ \~ \)"

3/38
Exercice 5 :
Ecrire un script utilisant diverses possibilités pour afficher le contenu d’une
variable et affecter son contenu.

#sh5 : l'affectation

var0=""
echo var0 : $var0

var1=chaine
echo var1 : $var1

var2="une chaine"
echo var 2 : $var2

var3=$var1
echo var3 : $var3

echo "variable non affectée"


echo var : $var

echo "var est une chaine vide"


var=""

var4=${var:valeur1}
echo var4 : $var4
echo var : $var

var5=${var :+valeur2}
echo var5 : $var5
echo var : $var

var6=${var :-valeur3}
echo var6 : $var6
echo var : $var

var7=${var :="valeur4"}
echo var7 : $var7
echo var : $var

echo "var est une chaine non vide"


var="valeur"
var4=${var:valeur1}
echo var4 : $var4
echo var : $var

var5=${var :+valeur2}
echo var5 : $var5
echo var : $var

4/38
var6=${var :-valeur3}
echo var6 : $var6
echo var : $var

var7=${var :="valeur4"}
echo var7 : $var7
echo var : $var

Exercice 6 :
Ecrire un script qui admet un unique paramètre optionnel devant
correspondre à un répertoire. Si ce paramètre est absent, on considérera le
répertoire courant. Ce script affichera la liste des fichiers qui sont inclus dans
le répertoire indiqué, si celui-ci est valide.

#sh6 : script affichant la liste des fichiers


# inclus dans le répertoire donné en paramètre
# il s'agira du répertoire courant si pas de paramètres
# il s'agira d'une erreur si plusieurs paramètres

if test $# -gt 1
then
echo erreur : trop de paramètres
echo "usage : $PWD/$0 [directory]"
elif test $# -eq 0
then
echo contenu du répertoire courant :
ls $1
elif test -d $1
then
echo contenu du répertoire $1
ls -l $1
else
echo erreur : $1 n\'est pas un répertoire
echo "usage : $PWD/$0 [directory]"
fi

5/38
Exercice 7 :
Ecrire un script qui admet la spécification d’un répertoire comme paramètre et
qui affichera pour chaque fichier qu’il renferme son type. Un total par type de
fichiers sera également affiché.

#sh7 : script affichant le type de chaque fichier


# appartenant au répertoire passé en paramètre
# ainsi que le total par catégorie trouvé

if test $# -ne 1
then
echo erreur : un paramètre est attendu
echo "usage : $PWD/$0 directory"
elif test -d $1
then
nbficOrd=0
nbficRep=0
nbficSpc=0
cd $1
for i in *
do
if test -d $i
then
echo $i est un fichier répertoire
nbficRep=`expr $nbficRep + 1`
elif test -f $i
then
echo $i est un fichier ordinaire
nbficOrd=`expr $nbficOrd + 1`
elif (ls $i) 1> /dev/null
then
echo $i est un fichier spécial
nbficSpc=`expr $nbficSpc + 1`
else
echo $i inconnu
fi
done
echo nombre total de fichier répertoire : $nbficRep
echo nombre total de fichier ordinaire : $nbficOrd
echo nombre total de fichier spéciaux : $nbficSpc
else
echo $1 n\'est pas un répertoire
fi

6/38
Exercice 8 :
Ecrire un script qui affiche la liste des sous répertoires d’un ou plusieurs
répertoires passés en paramètres, ainsi que leur total. On testera à chaque fois
la validité du répertoire passé en paramètre.

#sh8: script listant les sous répertoires


# du(des) répertoire(s) passés en paramètres
# ainsi que leur total

DIR=`pwd`
if test $# -eq 0
then
echo erreur : paramètres manquants
echo "usage : $PWD/$0 directory..."
else
for i in $*
do
echo --------------------------------------
if ! test -d $i
then
echo erreur : $i n\'est pas un répertoire
else
cd $i
Total=0
echo liste des sous-répertoires de $i :
for j in *
do
if test -d $j
then
echo $j
Total=`expr $Total + 1`
fi
done
echo "Total = $Total"
fi
done
cd $DIR : restitution du chemin initial
echo --------------------------------------
fi

7/38
Exercice 8bis :
En recourant à la commande find écrire un script répondant aux besoins
d’affichage de la liste des sous répertoires soit du répertoire courant si aucun
paramètre n’est précisé ou du répertoire donné en paramètre.

#sh8bis : pareil que sh8


# liste des sous répertoires du répertoire passé en paramètre

if test $# -gt 1
then
echo erreur : nombre de paramètres importants
echo usage : $0 [directory]
else
if test $# -eq 0
then
dossier=. #répertoire courant
else
dossier=$1 #répertoire passé en paramètre
fi
find $dossier -type d -print
fi

Exercice 9 :
Ecrire un script récursif qui affiche le contenu d’un répertoire passé en
paramètre dont la spécification de chemin doit au préalable être validée.

#sh9 : script affichant récursivement le contenu


# d'un répertoire passé en paramètre

if test $# -ne 1
then
echo erreur : un seul argument est nécessaire
echo "usage : $0 directory"
exit
fi

if ! test -d $1
then
echo erreur : $1 n\'est pas un répertoire
echo "usage : $0 directory"
else
echo ""
echo "--------------- répertoire : $1 ---------------"

8/38
for j in $1/*
do
if test -d $j
then
# traitement du sous répertoire par un appel récursif
$0 $j
else
echo $j
fi
done
fi

Exercice 9bis :
Ecrire un script qui utilise les définitions d’environnements que l’on peut
empiler et dépiler moyennant le parenthèsage pour afficher récursivement le
contenu d’un répertoire passé en paramètre.

#sh9bis: script affichant récursivement le contenu


# d'un répertoire passé en paramètres
#nota : agit comme ls -R
# on utilise pour chaque sous répertoire un
# environnement d'exécution qui lui est propre
# et obtenu par les fameuses parenthèses !

echo -e "\n\n====début============ $1 ============"


if test -d $1
then
(
#empilement d'un nouvel environnement
for i in $1/*
do
if test -d $i
then
$0 $i #appel récursif car $i est un répertoire
else
ls $i 2>/dev/null
if test $? -eq 1
then
echo "répertoire vide"
fi
fi
done
)
#dépilement d'environnement
else
:
fi
echo -e "=====fin============== $1 ==============\n"

9/38
Exercice 10 :
Ecrire un script qui admet en entrée un paramètre de type fichier ordinaire ou
répertoire (sinon il s’agit d’une erreur) et affiche comme résultat ses 10
premières lignes.

#sh10 : script visualisant les 10 premières lignes du


# contenu d'un fichier ou d'un répertoire passé en paramètre

if test $# -gt 1
then
echo erreur : trop de paramètres
echo usage : $0 fichier \| répertoire
exit
fi

if test $# -eq 0
then
echo erreur : paramètre obligatoire
echo usage : $0 fichier \| répertoire
exit
fi

if test -d $1 -a -r $1
then
echo "-------- contenu partiel du répertoire $1 ---------"
ls -l $1 | head -10
elif test -f $1 -a -r $1
then
echo "+++++++++ contenu partiel du fichier $1 +++++++++++"
head -10 $1
else
echo ":::::: répertoire ou fichier non accessible :::::"
fi

Exercice 10 bis :
Ecrire un script qui affiche les n premières lignes (par défaut n=5) d’une liste
de noms de fichiers admis en paramètres d’entrée. Le script devra vérifier que
la donnée n est correcte et il en est de même avec les fichiers.

#sh10bis : script visualisant les n premières lignes


# (par défaut = 5) d'une liste de fichiers
# les paramètres de ce script sont n et les fichiers

10/38
if test $# -lt 1
then
echo erreur : paramètres attendus
echo usage : $0 [nbrelignes] fichier...
exit 1
fi

if (((expr $1 + 1) 1>/dev/null) 2>/dev/null)


then
if test $1 -gt 0
then #un nbre de lignes est précisé
n=$1
shift
else
echo "erreur : l'option nbrelignes est un entier positif"
echo usage : $0 [nbrelignes] fichier...
exit 2
fi
else
n=5 #valeur prédéfinie
fi

if test -z $1
then
echo "erreur : une liste de fichier est attendue"
echo usage : $0 [nbrelignes] fichier...
exit 3
fi

for p in $*
do echo -e "\n\n --------------------- $p --------------------\n"
if test -f $p
then
head -$n $p 2>/dev/null
if test $? -eq 1
then
echo -e "\t Aucun fichier de ce nom !!!"
fi
else
echo -e "\t $p n'est pas un fichier !!!"
fi
done

11/38
Exercice 11 :
Ecrire un script qui indique si une donnée lue à partir du clavier est de type
entier ou chaîne de caractères

#sh11 : script pour commencer du calcul


# vérifie si la donnée lu est un décimal

echo "ce script reconnaît si une donnée est un entier ou pas"


echo "======================================================"
echo -e "introduire une donnée : \c"
read val

echo -e "............ analyse de la donnée : \c"


if ((expr $val + 1) 1> /dev/null ) 2> /dev/null
then
echo c\'est un entier
else
echo c\'est une chaine de caractères
fi

Exercice 11 bis :
Utilisez la commande case pour écrire un script qui admet en entrée plusieurs
entiers et qui déterminera leur somme, produit et moyenne. La liste des entiers
est de taille quelconque.

#sh11bis : calculons la somme, le produit, la moyenne


# d'une liste de nombre donnée en paramètres

#hypothèse : on ne vérifiera pas qu'il s'agit de nombres

liste=$@
nbr=$#

som=0
prod=1
while ! test -z $1
do som=`expr $som + $1`
prod=`expr $prod \* $1`
shift
done

moy=`expr $som / $nbr`

12/38
echo "liste à traiter : $liste"
echo "taille de cette liste = $nbr"
echo "somme de ces nombres = $som"
echo "produit de ces nombres = $prod"
echo "moyenne de ces nombres = $moy"

Exercice 12 :
Utilisez les commandes for et seq pour écrire un script shell qui calcule
itérativement la factorielle d’un nombre admis comme paramètre d’entrée et
qui doit être un entier positif.

#sh12 : calcul de la factorielle itérativement


# le paramètre doit être un entier positif

if test $# -ne 1
then echo "erreur : factorielle de quoi ??"
elif ! (((expr $1 + 1) 1> /dev/null) 2> /dev/null)
then echo "erreur : paramètre non nombre"
elif test $1 -lt 0
then echo "erreur : factorielle d'un nombre négatif"
else
fact=1
for i in `seq 1 $1`
do
fact=`expr $fact \* $i`
done
echo factorielle\($1\) = $fact
fi

Exercice 12bis :
Ecrire un script de calcul itératif de la factorielle en utilisant la commande
while ou until. On ne traitera les problèmes de dépassement de capacité.

#sh12bis : calcul de la factorielle itérativement


# le paramètre doit être un entier positif

if test $# -ne 1
then echo "erreur : factorielle de quoi ??"
elif ! (((expr $1 + 1) 1> /dev/null) 2> /dev/null)
then echo "erreur : paramètre non nombre"
elif test $1 -lt 0
then echo "erreur : factorielle d'un nombre négatif"
else

13/38
fact=1
n=$1
until test $n -lt 1
do
fact=`expr $fact \* $n`
n=`expr $n - 1`
done
echo factorielle\($1\) = $fact
fi

Exercice 13 :
Ecrire un script shell utilisant le concept de fonction récursive pour calculer la
factorielle d’un nombre.

#sh13 : factorielle récursivement


# et de plus avec un sous programme (une fonction locale)

function factorielle()
{
if test $1 -eq 0
then return 1
else fact=`expr $2 \* $1`
n=`expr $1 - 1`
factorielle $n $fact
#appel récursif avec n-1 et la factorielle précédente
fi
}

#programme principal
echo -e "\t\t CALCUL DE LA FACTORIELLE"
echo -e "\t\t ========================"
echo -e "\n \t introduire un entier : \c" ; read Nbr
# on suppose que l'entier est positif ou nul

fact=1
factorielle $Nbr $fact
echo -e "\t résultat de factorielle($Nbr) = $fact \n"

14/38
Exercice 13bis :
Ecrire un script récursif pour le calcul de la factorielle d’un nombre.

#sh 13bis : la factorielle récursive

#attention : ici on ne vérifie pas les erreurs sur les données

if test $1 -eq 0
then

echo 1
else #on décrément n
n=`expr $1 - 1`
#on calcule n x factorielle(n -1)
echo `expr $1 \* $($0 $n)`
fi

Exercice 14 :
L’envoi d’un quelconque signal par la commande kill nécessite la connaissance
du numéro du processus signalé. On désire écrire un script qui tue un
processus connu par son nom (paramètre d’entrée à vérifier au préalable).

#sh14 : script qui étant donné le nom du processus


# lui envoie le signal SIGKILL pour le tuer

if test $# -eq 1
then
#obtenir avec ps de la ligne contenant le nom
nu=`ps | grep $1`
#découper cette ligne en plusieurs champs
set $nu
#premier champ = numéro de processus
kill -9 $1
else
echo erreur : paramètre attendu
echo usage : $0 NomProcessus
fi

15/38
Exercice 15 :
Ecrire un script permettant de détruire un ensemble de processus dont les
noms sont passés comme paramètres d’entrée au script.

#sh15 : script détruisant une liste de processus


# dont les noms sont donnés en paramètres

if test $# -eq 0
then
echo erreur : paramètres manquants
echo usage : "$0 process..."
else
for i in $*
do #on suppose que les sorties de ps sont de
#la forme :
# PID TTY TIME CMD
# 500 pts/0 00:00:01 bash
# 615 pts/0 00:00:00 cat
#on utilise cut avec comme délimiteur "p"
#ce n’est pas fameux mais ?!!
pid=`ps | grep -e $i | cut -f1 -d "p"`
if test $pid
then
kill -9 $pid
else
echo $i : processus inexistant
fi
done
fi

Exercice 16 :
Ecrire un script qui, étant donnée le nom d’un utilisateur, renseignera sur
l’appartenance de cet utilisateur au système et s’il est actuellement connecté.

#sh16 : script vérifiant si un nom d'utilisateur


# fait partie des utilisateurs du système
# et s'il est connecté au système

echo -e "\n\t\t SCRIPT RENSEIGNEMENT UTILISATEUR "


echo -e " \t\t ================================ \n"
echo -e " \t donnez un nom d'uilisateur : \c"
read nom

16/38
cat /etc/passwd | cut -f 1 -d ":" | grep $nom >/dev/null
case $? in
0) echo -e "\t $nom : fait partie des utilisateurs de ce système"
if who | cut -f 1 | grep $nom >/dev/null
then echo -e "\t\t et il est en ce moment connecté \n"
else echo -e "\t\t mais il est absent en ce moment \n"
fi
;;
1) echo -e "\t $nom : n'est pas connu de ce système !!! \n"
;;
esac

Exercice 17 :
Le script à écrire admet deux paramètres : le nom d’un utilisateur et le nom
d’un fichier contenant un texte imprimable. Il doit :
 vérifier la validité de ses paramètres,
 décider d’envoyer le fichier à la boite aux lettres de l’utilisateur ou le lui
afficher directement sur son écran selon que l’utilisateur est actuellement
connecté ou pas et en fonction de son état d’acceptation de messages en
ligne ou pas.

#sh17 : script qui étant donné un nom d'utilisateur et un message


# dont le contenu est défini dans un fichier se propose de faire
# parvenir le contenu du fichier à l'utilisateur soit par
# envoi direct sur sa boite au lettres soit directement
# sur son écran

echo -e "\n\t\t ENVOI POSTAL "


echo -e " \t\t ============ \n"
echo -e "\t introduire le nom du destinataire : \c"
read dest
echo -e "\t introduire l'emplacement du paquet à envoyer : \c"
read paq

cat /etc/passwd | cut -f 1 -d ":" | grep $dest >/dev/null


case $? in
0) if ! test -f $paq
then echo -e "\t ERREUR : $paq est un nom de fichier incorrect \n"
elif write $dest < $paq 2>/dev/null
then echo -e "\t ... message affiché sur l'écran de $nom \n"
else mail $dest < $paq 2>/dev/null
case $? in
0) echo -e "\t ... message envoyé à la boite aux lettres \n"
;;
1) echo -e "\t ... pas de boites aux lettres trouvé !!\n"
;;
esac
fi

17/38
;;
1) echo -e "\t ERREUR : $dest utilisateur inconnu sur ce système \n"
;;
esac

Exercice 17bis :
Ecrire le script de l’exercice précédent autrement.

#sh17bis : commande équivalente au sh17


# deux paramètres : le premier le nom d'un utilisateur
# le second un nom de fichier à envoyer
# envoi par write ou par mail

#test du nombre de paramètres


if test $# -ne 2
then echo erreur : nombre de paramètres incorrect >&2
exit 1
fi

#test d'existence d'un utilisateur de ce nom connu du système


if grep "^$1:" /etc/passwd 1>/dev/null
then
#test d'existence du fichier à envoyer ou à afficher
if test -f $2
then
#l'utilisateur est-il logé
if who | grep "^$1" 1>/dev/null
then
echo "utilisateur connecté"
echo "...essai d'afficher le message sur son écran"
#test d'acceptation du message par write
if (write $1 <$2) 2>/dev/null
then
echo -e "\n\t xxxxxxxxxxxxxx fichier affiché xxxxxxxxxxxxxx \n"
exit 0
fi
fi
#utilisateur non connecté ou pas mis mesg n
echo "utilisateur non connecté ou refusant les messages en ligne"
echo ".... tentative d'envoi sur sa boite aux lettres"
if (mail $1 < $2) 2>/dev/null
then
echo -e "\n\t+++++++++++ fichier envoyé +++++++++++\n"
exit 0
else
echo -e "\n\t impossible de contacter l'utilisateur"
fi

18/38
else
echo fichier $2 inexistant >&2
exit 2
fi
else
echo "$1 utilisateur inconnu du sytème" >&2
exit 3
fi

Exercice 18 :
Ecrire un script qui réalise les divers calculs arithmétiques simples
nécessitant la connaissance d’un première opérande, d’un opérateur et d’un
second opérande. On vérifiera que les opérandes sont bel et bien des nombres
et que les opérateurs sont parmi :+,- (opérateurs additifs) ,x,/ (la multiplication
et la division) et %(modulo).

#sh18 : calcul arithmétique simple du style 5 + 7


# trois paramètres sont attendus : op1 oper op2

#d'abord un test sur les paramètres


if test $# -ne 3
then echo erreur dans l\'expression
echo usage : $0 opérande1 opérateur opérande2
echo attention : la multiplication est représenté par x
exit 0
fi

#ensuite un calcul équivalent à expr $1 $2 $3


#avec vérification préalable des opérandes
#puis des opérateurs parmi : +, -, *, / et %
if (((expr $1 + 1) 1>/dev/null) 2>/dev/null)
then
if (((expr $3 + 1) 1>/dev/null) 2>/dev/null)
then
case $2 in
'+') expr $1 + $3;;
'-') expr $1 - $3;;
'x') expr $1 \* $3;;
'/') if test $3 -eq 0
then echo erreur : divison par zéro
else expr $1 / $3
fi;;
'%') expr $1 % $3;;
* ) echo erreur : opérateur inconnu ;;
esac
else
echo erreur : 2d opérande non numérique
fi

19/38
else
echo erreur : 1er opérande non numérique
fi

Exercice 19 :
Ecrire un script qui affiche ses paramètres données dans l’ordre inverse de
leur apparition. On utilisera pour cela la commande eval et on construira au
préalable la liste inversée. On suppose que le nombre de paramètres effectifs
ne dépasse pas la valeur 9.

#sh19 : affichage des arguments dans l'ordre inverse


# de leur apparition lors de l'appel
# on utilisera la commande eval en construisant
# une commande echo avec les paramètres inversés

#attention :
# ne fonctionne que partiellement à cause
# du nombre de paramètres formels réduits à 9

if test $# -eq 0
then echo pas d\'arguments
else
echo -e "liste des arguments :"
echo -e "====================="
echo -e "\t $@"

#construction de la commande echo


compt=$#
cmde="echo -e \"\t "
while test $compt -gt 0
do
cmde="$cmde\$$compt "
compt=`expr $compt - 1`
done
cmde="$cmde \""
#fin de la construction

echo -e "liste des arguments dans l'ordre inverse :"


echo -e "=========================================="
eval $cmde
fi

20/38
Exercice 19 bis :
En recourant à la commande cut et un fichier temporaire contenant
initialement la liste des paramètres, écrire un script shell qui construit une
liste inversée de ces paramètres avant de les afficher dans cet ordre. On
suppose que la liste des paramètres effectifs est de taille quelconque (et donc
au delà de 9).

#sh19bis : script pareil au sh19


# avec plusieurs variables

if test $# -eq 0
then
echo nombre de paramètres égal à zéro
else
echo liste des paramètres :
echo -e "\t $*"

#construction de la liste
echo $@ > tmp.tmp
n=$#
until test $n -eq 0
do
liste="$liste `cut -f$n -d" " tmp.tmp`"
n=`expr $n - 1`
done
rm -f tmp.tmp
#fin construction

echo liste inversée :


echo -e "\t $liste"
fi

Exercice 20 :
Ecrire un script shell qui peut interpréter les commandes internes de MS/DOS
et en particulier : copy, cls, date, del, dir, exit, more, ren, time, type. Les
commandes peuvent être indifféremment introduites en minuscule ou en
majuscule. On devra respecter également la syntaxe de ces commandes et leurs
options, par exemple : DIR [/P | /W] [chemin].

#sh20 : script des commandes internes de MS/DOS

interpreter ()
{

21/38
case $1 in
[Dd][Aa][Tt][Ee]) date +"%a %D";;
[Dd][Ee][Ll] ) rm -f $2;;
[Dd][Ii][Rr] ) if test x$2 = x
then ls
else case $2 in
"/p" | "/P") if test x$3 = x
then ls | more
else ls $3 | more
fi;;
"/w" | "/W") if test x$3 = x
then ls
else ls $3
fi;;
* ) if test x$3 = x
then ls $2
else echo option $2 inconnue
fi;;
esac
fi;;
[Cc][Oo][Pp][Yy]) if test x$3 = x
then cp $2 $HOME/.
else cp $2 $3
fi;;
[Cc][Ll][Ss] ) clear;;
[Mm][Oo][Rr][Ee]) cat $2 | more;;
[Rr][Ee][Nn] ) mv $2 $3;;
[Tt][Ii][Mm][Ee]) date +"%T";;
[Tt][Yy][Pp][Ee]) cat $2;;
*) echo commande incorrect;;
esac
}

function menu()
{
while true
do
echo -e "\tDOS>\c"
read commande
set $commande
if test zzz$1 != zzz
then
case $1 in
[Ee][Xx][Ii][Tt] ) clear; break;;
* ) interpreter $*;;
esac
fi
done
}

22/38
######################### PG PRINCIPAL ######################

clear
echo -e "\t\t DOS COMMANDS "
echo -e "\t\t==============\n"
menu

Exercice 21 :
Ecrire un script qui affiche le nom de chaque sous répertoire appartenant au
répertoire donné en paramètre (par défaut le répertoire courant) puis lit au
terminal une commande qu’on exécutera sous le sous-répertoire affiché.
L’exécution de la commande, lorsqu’elle est valide, ne doit pas être
interrompue (par un CTRL-C).

#sh21 :
# script qui affiche le nom de chaque sous répertoire
# appartenant au répertoire donné en paramètre (par défaut
# il s'agira du répertoire courant) puis exécute
# dans ces sous-répertoires une commande qui sera
# introduite au terminal

if test $# -gt 1
then echo "erreur : trop de paramètres"
elif test $# -eq 0
then courant=`pwd`
elif test -d $1
then if test "$1" = "."
then courant=`pwd`
else courant=$1
fi
else echo "erreur : Auncun répertoire de ce nom"
exit 1
fi

echo -e "\t ====== liste des répertoires de $courant ====="


nbrep=`find $courant -type d -maxdepth 1|wc -l`
if test $nbrep -eq 1
then
echo "pas de sous répertoires dans $courant"
exit 2
else
ls -l $courant | grep "^d"
fi

echo -e "\n\n\tCommande à exécuter, Q)uitter, ?)help:\n"


cd $courant
for dir in *

23/38
do
if test -d $dir
then
echo -n "$dir => "
trap 'clear;exit' 2
read cmde
case $cmde in
"")
echo " "
;;
[Qq])
clear
exit 0
;;
? | [Hh][Ee][Ll][Pp])
echo "ce script vous facilite la réalisation d'une commande"
echo "que vous saisissez sur un répertoire qui vous sera précisé"
echo "parmi ceux du répertoire courant ou celui que vous allez"
echo "donné en paramètre"
exit 3
;;
*)
if trap : 2 ; eval $cmde $dir 2>/dev/null
then echo -e "\n"
else echo -e "erreur : commande inconnue ou erronée \n"
fi
;;
esac
fi
done

24/38
Exercices avec FIND

Exercice 1 :
Ecrire un script shell permettant de faciliter l’utilisation de la commande find.
L’objectif est de présenter un menu à l’utilisateur pour choisir quel type de
recherche il voudra réaliser à partir d’un répertoire donnée. Exemple :
affichage de la liste des fichiers ordinaires, affichage de la liste des fichiers
appartenant à un utilisateur donné, etc.

#script find1
# qui affiche une liste de fichiers
# selon les besoins de l'utilisateur exprimés
# par un choix dans un menu

menu()
{
echo -e "\t\t 0) quitter"
echo -e "\t\t 1) sous répertoires de $dir"
echo -e "\t\t 2) liste des fichiers ordinaires de $dir"
echo -e "\t\t 3) liste des fichiers spéciaux de $dir"
echo -e "\t\t 4) fichiers de $dir ayant une taille donnée"
echo -e "\t\t 5) fichiers appartenant à un utilisateur donné"
echo -e "\t\t 6) fichiers récemment mis à jour"
echo -e "\t\t 7) fichiers récemment accédés"
echo -e "\t\t 8) fichiers récemment créés"
echo -e "\t\t 9) fichiers ayant des droits d'accès particuliers"
}

while true
do
echo -e "\n======================================================="

trap 'clear; exit' 2 3


echo -e "Répertoire à traiter : \c"; read dir
if test "$dir" = "."; then dir=`pwd`
elif test -d $dir ; then :
else echo -e ">>>>>>>>>>>REPERTOIRE INCONNU <<<<<<<<<\n"; exit 1
fi

menu
echo -e "\n\t\tChoisir parmi : \c"; read choix
case $choix in
0) exit;;

25/38
1) find $dir -type d -print;;
2) find $dir \( -type f -o -type l \) -print;;
3) find $dir \( -type c -o -type b -o type p -o -type s\) -print;;
4) echo -e "\ttaille min en octets : \c"; read min
min=`expr $min / 512`
echo -e "\ttaille max en octets : \c"; read max
max=`expr $max / 512` ; max=`expr $max + 1`
find $dir \( -size +$min -a -size -$max \) -print
;;
5) echo -e "\tnom de l'utilisateur : \c"; read nom
find $dir -user $nom -print
;;
6) echo -e "\tnombre de jours : \c"; read nbjour
find $dir -mtime -$nbjour -print
;;
7) echo -e "\tnombre de jours : \c"; read nbjour
find $dir -atime -$nbjour -print
;;
8) echo -e "\tnombre de jours : \c"; read nbjour
find $dtime -$nbjour -print
;;
9) echo -e "\tpermission d'accès : \c"; read droit
find $dir -perm -$droit -print
;;
*) echo -e "\n>>>>>>>>>>> ERREUR dans la saisie ! <<<<<<<<<<<<\n"
;;
esac
done

Exercice 2 :
Ecrire un script shell qui va traquer la liste des fichiers de taille nulle et ceux
dont le bit SUID est mis en place. Le script attend un paramètre en entrée qui
doit correspondre à la spécification du chemin d’un répertoire à partir duquel
la recherche va être opérée. Si ce paramètre est absent, il s’agit du répertoire
courant.

#script find2
# traquant les fichiers de taille nulle
# et de SUID-Bit mis en place

if test $# -gt 1
then echo erreur : trop de paramètres
echo usage : $0 [path]
exit 1
fi

echo ${1:-`pwd`} 1>/dev/null 2>/dev/null


echo $1

26/38
echo "liste des fichiers de taille nulle"
echo "=================================="
nbre=`find $1 -size 0 |wc -l`
find $1 -size 0
echo -e "\n>>>>>>>> TOTAL = $nbre \n"

echo "liste des fichiers avec SUID-Bit=1"


echo "=================================="
nbre=`find $1 -perm +4100 | wc -l`
find $1 -perm +4100
echo -e "\n>>>>>>>>> TOTAL = $nbre \n"

Exercice 3 :
Ecrire un script qui cherche tous les fichiers se trouvant dans une sous
arborescence de racine le nom d’un répertoire et appartenant à un groupe
d’utilisateurs donné, et qui vous propose au travers d’un menu soit de les
afficher, de les détruire ou de les archiver.

#script find3
# qui cherche tous les fichiers appartenant à un
# groupe donné et qui exécute une commande parmi une
# liste donnée dans un menu

function menuordre ()
{
echo "=========================================="
echo " A)rchiver "
echo " D)étruire "
echo " L)ister "
echo " Q)uitter "
echo "=========================================="
echo -n " votre choix : "
}

clear
echo -n "nom du groupe : "; read groupe
if ! grep "^$groupe:" /etc/group 1>/dev/null 2>/dev/null
then echo "erreur : nom du groupe erroné !!!"
exit 1
fi

echo -n "répertoire de recherche : "; read dossier


if ! test -d $dossier
then echo "erreur : répertoire inexisant ou inaccesible"
exit 2
fi

menuordre; read choix

27/38
case $choix in
[Aa]) echo -n "nom de l'archive : "; read archive
find $dossier -group $groupe | cpio -ocvB > $archive
;;
[Dd]) find $dossier -group $groupe -exec rm -f {} \;
;;
[Ll]) find $dossier -group $groupe -print
;;
*) echo "erreur commande inconnu"
exit 3
;;
esac

28/38
Exercices avec GREP

Exercice 1 :
Ecrire un script utilisant la commande grep qui affiche les données complètes
connues à propos d’un utilisateur. Ce script signalera de plus si l’utilisateur en
question posséde ou pas un mot de passe et si son UID et GID sont valides.

#script gp1
# cherchant si un utilisateur est connu du système
# et si oui affiche ses données caractéristiques présentes
# dans le fichier /etc/passwd à savoir son UID, GID, ...
#attention : doit également indiquer si l'utilisateur a ou non
# un mot de passe et renseigne sur la validité de UID et GID

clear
if test $# -ne 1
then echo erreur : un paramètres est attendu
echo usage : $0 nom_utilisateur
exit 1
fi

user=$1
res=`grep "^$user:" /etc/passwd`
if ! test -z $res
then IFS=:
set $res
echo "infos de $user : UID=$3, GID=$4, HOME=$6, SHELL=$7"
if test -z $2
then echo " !!!! ATTENTION : pas de mot de passe"
fi
case $3 in
*[!0-9]*) echo " !!!!! ATTENTION : UID non valide" ;;
esac
case $4 in
*[!0-9]*) echo " !!!!! ATTENTION : GID non valide" ;;
esac
else echo "utilisateur $nom : inconnu"
fi

29/38
Exercice 2 :
Ecrire un script utilisant la commande grep qui affiche les informations
relatives à tous les utilisateurs connus d’un groupe identifié par leur numéro.

#script grep2
# affiche les informations concernant tous les
# utilisateurs d'un même groupe

if test $# -eq 0
then echo erreur : paramètres attendus
echo usage : $0 goupeId...
exit 1
fi

for grp
do echo "=================== traitement de $grp ===================="
case $grp in
*[!0-9]*) echo $grp n\'est pas un nombre ;;
*) ligne=`grep "^[^:]*:[^:]*:[^:]*:$grp:" /etc/passwd`
if test -n "$ligne"
then echo infos utilisateur du groupe $grp :
echo $ligne | tr " " "\n"
else echo pas d\'entrée pour le groupe $grp
fi;;
esac
done

Exercice 3 :
Ecrire un script utilisant la commande grep qui prend comme paramètres une
liste de noms de groupes et qui affiche la liste de ses membres et les
informations qui les concernent.

#script grep3
# qui pend la liste des utilisateurs d'un groupe
# dont le nom est un paramètre donnée et
# qui affiche leurs informations respectives

if test $# -eq 0
then echo erreur : paramètres attendus
echo usage : $0 nom_groupe...
exit 1
fi

for grp

30/38
do echo ============= traitement de $grp ==================
membre=`grep "^$grp:" /etc/group |cut -f4 -d:`
if test -z "$membre"
then
echo liste des membres réduite à priori à $grp
if grep "^$grp:" /etc/passwd
then :
else echo $grp non utilisateur de ce système
fi
else
echo liste des membres du groupe $grp : $membre
IFS=,
set $membre
while test -n "$1"
do
grep "^$1" /etc/passwd
shift
done
fi
done

31/38
Exercices avec AWK

Exercice 1 :
Ecrire un script awk qui affiche le contenu d’un fichier (supposé être valide).
Chaque ligne de ce fichier sera précédé par son numéro.

#script f1.awk
# qui affiche le contenu d'un fichier
# chaque ligne est précédé de son numéro

BEGIN {
system("clear")
print " contenu du fichier : ", ARGV[1]
print "=N°= =============contenu de la ligne====================="
}

#rien
{
print NR, ": ",$0
}

END {
print "===================================================fin===="
}

Exercice 2 :
Ecrire un script awk qui utilise les variables prédéfinies pour afficher des
champs particuliers du fichier /etc/passwd.

#script f2.awk
# qui renseigne à propos
# des champs UID et GID du fichier /etc/passwd

BEGIN {
FS=":" #field separator"
print "\t le : ", strftime("%D")
print "=====début============================================="
}

32/38
#rien
{
print "username = " , $1," \t UID = ",$3, " \t GID = ", $4
}

END {
print "================================================fin===="
}

Exercice 3 :
Ecrire un script awk qui renseigne sur la validité des champs UID et GID du
fichier /etc/passwd et qui affiche le total des erreurs trouvées.

#script f3.awk
# qui renseigne à propos de la validité
# des champs UID et GID du fichier /etc/passwd

BEGIN {
FS=":" #field separator"
compteur=0
print "===== validité de UID et GID dans le fichier /etc/passwd"
}

$3 !~ /^[0-9]+$/ || $4 !~ /^[0-9]+$/ {
compteur=compteur+1
print $1," avec un user ou groupe identifié non valide ???"
}

END {
print "\n\t\t\t $$$$ TOTAL = ", compteur
}

Exercice 4 :
Ecrire un script awk qui calcule itérativement les factorielles de 16 premiers
entiers et qui affichera leur résultat.

#script f4.awk
# affichant les 16 premières valeurs de la factorielle
# (je ne sais si on peut aller plus loin !!)

BEGIN {
FactN_1=1

33/38
print "n \t factorielle(n)"
print "0", "\t\t", FactN_1
for (i=1; i<=15; i++) {
FactN= i * FactN_1
print i, "\t\t", FactN
FactN_1= FactN
}
}

Exercice 5 :
Ecrire un script awk utilisant la structure de données tableau pour afficher le
contenu d’un fichier ligne par ligne dans l’ordre inverse de leur apparition
initiale.

#script f5.awk
# utilisant des tableaux
# affiche le contenu du fichier dans l'ordre inverse

BEGIN { print "\t\taffichage inverse du contenu de : ",ARGV[1]


print "\t\t===============AVANT========================="
}

#rien
{ print "> ",$0
lignes[NR]=$0
}

END { print "\t\t===============APRES=========================="


for(i=NR;i>0; i--) { print "< ",lignes[i] }
print "\t\t=============================================="
}

Exercice 6 :
Ecrire un script shell qui affiche certains champs du résultat de la commande
date et ceux en recourant à la commande awk.

#script f6.awk
# qui affiche certains champs du résultat
# de la commande date en particulier l'heure actuelle
# l'équivalent en shell serait de procéder comme suit :

# set `date`
# echo $4 > xxx

34/38
# echo `cut -f1 -d: xxx` heures `cut -f2 -d: xxx` minutes
# rm -f xxx

date | awk '{ n=split($4, champ, ":")


print champ[1] " heures " champ[2] " minutes"
}'

Exercice 7 :
Ecrire un script awk qui réalise les même calculs que la commande wc
(comptage du nombre de caractères, mots et lignes d’un fichier) en utilisant les
fonctions length, split, et en évitant de recourir aux variables prédéfinies NF et
NR.

#script f7.awk
# qui compte le nombre de caractères, mots et ligne d'un
# d'un fichier donné en paramètre

#attention : on n'utilisera pas les variables prédéfinies NF et NR


# NF = nb de mots par ligne du fichier (Number of Fields)
# NR = nb de lignes du fichier (Number of Row)

BEGIN {
print "le script awk équivalent à la commande $wc " ARGV[1] " donne :"
nblig=0
nbmot=0
nbcar=0
}

#rien
{
nblig=nblig + 1
nbmot=nbmot + split($0, t, " ")
nbcar=nbcar + length($0) + 1
}

END {
print "\tNombre de lignes : \t", nblig
print "\tNombre de mots : \t", nbmot
print "\tNombre de caractères : \t", nbcar
}

35/38
Exercice 8 :
Ecrire un script awk qui affiche pour chaque ligne du fichier à traiter la
somme de ses champs numériques et en fin du parcours le total de ces totaux.

#script f8.awk
# qui calcule la somme des lignes d'un fichier
# dont les données sont des entiers

#NR: number of Row et NF : number of fields

BEGIN {
print "<Total> contenu du fichier "
print "=============================================="
}

NR>0 && NF>0 {


somParLigne=0
split($0, ligne, " ")
i=1
do { somParLigne+=ligne[i]
totalgeneral+= $i
i++
} while (i<=NF)
print "<"somParLigne">\t", $0
}

END {
print "==============================================="
print " Total Général = ", totalgeneral
}

Exercice 9 :
Ecrire un script awk qui affiche la moyenne des nombres contenus dans un
fichier paramètre d’entrée du script et présentés en colonnes.

#script f9.awk
# qui affiche la moyenne des nombres

BEGIN {
if (ARGC-1==0)
{print "Aucun fichier de ce nom !!!" ; exit}
else
print "contenu de fichier : ", ARGV[1]
}

36/38
{
split($0, champ, FS)
for(i=1; i<=NF; i++) {
printf("\t %s", champ[i])
T[i]+=champ[i]
}
printf("\n")
}

END {
if (FILENAME) {
printf "valeurs moyennes de chaque colonne \n"
for (i=1; i<=NF; i++) printf("\t %5.2f ", T[i]/NR)
}
printf("\n")
}

Exercice 10 :
Ecrire un script awk qui étant donné un nom de fichier et un motif donné,
scrute le fichier ligne par ligne pour indiquer si le motif en question y est
présent ou pas.

#script f10.awk
# de recherche d'un motif dans un fichier

BEGIN {
printf("motif à rechercher : "); getline motif
printf("fichier concerné : "); getline fichier
}

{
getline < fichier
if ($0=="")
exit
else {
print $0
idx=index($0, motif)
if (idx==0)
printf("\t\t>>non trouvé")
else
printf("\t\>>trouvé à l'indice : %d", idx)
}
}

END {
print "=======================fin========================"
}

37/38
Exercice 11 :
Ecrire un script awk qui affiche toutes les occurrences d’un motif donné à
rechercher dans un fichier donné.

#script f11.awk
# de recherche de toutes les occurrences d'un motif dans un fichier.
# On suppose que le fichier ne contient pas de lignes vides

BEGIN {
printf("motif à rechercher : ");getline motif
printf("nom du fichier : ");getline fichier
printf("\n==================début==================\n")
}

{
getline < fichier
if ($0=="")
exit
else
{ print $0
for(i=1;i<=length($0);i++) printf("-"); printf("\n")

ligne=$0
idx[0]=0; i=1
for(;;){
idnx=index(ligne,motif)
idx[i]=idx[i-1]+idnx; i++
if (idnx==0)
break
else
ligne=substr(ligne,idnx+1,length(ligne)-length(motif))
}

if (idx[1]!=0) { print "trouvé >>"


for(j=1;j<i-1;j++) printf("\t\>%d",idx[j])
}
else print "non trouvé !!"

}
}

END {
print "=======================fin========================"
}

38/38

Vous aimerez peut-être aussi