TP #3 : Processus
Responsables : Jean-Patrick Gelas, Nicolas Louvet
Version : 0.1a (04/2021)
Objectif : La première partie de ce TP portera sur la gestion des processus. La seconde partie traitera d'opérateurs supplémentaire.
Exécution en tâche de fond
Vous avez peut être remarqué que lorsque vous lancez une commande dans votre console vous perdez la main sur celle-ci (vous ne pouvez plus saisir de nouvelles commandes).
Une solution simple, est de lancer la commande en tâche de fond (en
background) en la post fixant d'un caractère &
.
$ gedit &
Astuce : Très souvent j'oublie de saisir le &
en fin de commande. La
solution rapide pour reprendre la main sur ma console sans arrêter
l'application que je viens de lancer est la suivante. J'envoie un signal de
pause sur le dernier processus lancer (c'est à dire mon applicationt) avec la
séquence de touche Ctrl
+Z
. Puis je tape la commande bg
. L'application
reprend alors son cours d'exécution et moi j'ai à nouveau la main sur ma console.
$ gedit # Oups! J'ai oublié le `&`
Ctrl+Z
$ bg
$
Remarque: La commande qui permet de remettre le processus en premier plan (foreground) est fg
.
Important: La séquence de touche qui permet de stopper un processus
violemment est Ctrl
+C
. A utiliser quand vous n'arrivez pas à stopper un
processus autrement. Cette séquence de touche ne fonctionne que sur le
processus en premier plan de votre console.
Exercice 1 : Soit le script shell suivant nommé chatty.sh,
constitué d'une boucle infinie. Saisissez-le, rendez-le exécutable (chmod) et exécutez-le (sans le &
).
#!/bin/bash
while true
do
echo "Blah blah blah..."
sleep 1
done
Pour le stopper vous devrez utiliser la séquence de touche Ctrl
+C
.
Exercice 2 : Exécutez le à présent avec le &
.
$ ./chatty.sh &
Tapez la séquence Ctrl
+C
. Rien ne se passe !
Comment allez-vous reprendre la main pour le
stopper ?
Contrôle des processus
La commande ps
permet d'afficher la liste des processus en cours d'exécution
sur la machine. Vous l'utiliserez réguliérement avec les options suivantes.
$ ps aux
A chaque processus est associé un identifiant appelé le PID. Nous utiliseront cet identifiant pour cibler un processus particulier.
Exercice 3 : Exécutez le script chatty.sh
dans une console. Ouvrez une
autre console et dans celle-ci déterminez quel est le PID de chatty.sh en
cours d'exécution sur votre machine.
Le PID de chatty.sh est ....
La commande kill
(qui porte plus ou moins bien son nom) va nous permettre
d'envoyer un signal (une sorte de message) a un processus dont le PID est passé en paramètre.
Chaque signal à un rôle particulier. Un processus doit normalement réagir en fonction du signal reçu.
Il existe de nombreux signaux différents mais dans la pratique vous en utiliserez probalement peu.
Ces signaux vous permettrons par exemple de mettre en pause un processus (-STOP
équivalent de Ctrl
+Z
), de reprendre son exécution (-CONT
équivalent de fg
ou bg
), de stopper définitivement et proprement le processus (-INT
équivalent de
Ctrl
+C
), ou de le tuer avec violence et sant pitié (-KILL
ou -9
) !
Voici quelques exemples ci-dessous où je fais l'hypothèse que le PID de mon processus est 1234.
$ kill -STOP 1234 # met en pause l'exécution du processus 1234
$ kill -CONT 1234 # le processus 1234 reprend le cours de son éxécution
$ kill -9 1234 # Assassine sauvagement le processus 1234 ! :-(
Exercice 3 : Essayez de contrôler le cours d'exécution du processus ./chatty.sh avec les différentes séquences de touches et commandes vu dans cette section.
Remarque : Un scritp shell peut connaitre son propre PID. Celui-ci est stocké dans la variable $$
.
Soit le script depressif suivant... :-)
#!/bin/bash
echo "Mon PID est $$"
echo "Adieu triste monde !"
kill $$
echo "Cette ligne ne s'affichera jamais..."
Remarque : Le développeur d'une application à la possibilité de détourner un
signal reçu pour que son application réagisse differement du comportement
standard. C'est pour cela que parfois Ctrl
+C
ne suffit pas pour stopper un processus.
Valeur de retour
Une application, lorsque elle se termine, renvoie une valeur dite de retour
sous la forme d'un entier compris entre 0 et 255. Par convention une application
renvoie 0
quand tout c'est bien passé. En script shell, cette valeur est émise
avec l'instruction exit
qui prend en paramètre un entier. Le plus souvent 0.
#!/bin/bash
...
exit 0
A l'issue de l'exécution d'une commande, il est possible de récupérer sa valeur de retour dans la variable $?
.
$ echo "Hello" # une commande
Hello
$ echo $? # si cela affiche '0' c'est que tout c'est probablement bien passé
0
IMPORTANT : La variable $?
contient la valeur de retour de la dernière commande exécutée.
Question 4 : Soit le script shell suivant nommée theAnswer.sh
#!/bin/bash
echo "La réponse se cache dans ma valeur de retour (exit value)..."
exit 42
Qu'est ce que va afficher la commande echo $?
exécutée immédiatement après ./theAnswer.sh
?
Introduction a grep
La commande grep
est un outil de recherche de chaînes de caractéres.
Imaginons un fichier liste.txt
contenant sur chaque ligne un Prénom suivit d'une Année de naissance.
$ cat liste.txt
Alice 2012
Bob 2011
Charles 1999
Leon 2011
Octave 2012
La commande grep 2012 liste.txt
me permet d'extraire toutes les lignes du
fichier liste.txt contenant la chaine de caractères 2012.
$ grep 2012 liste.txt
Alice 2012
Octave 2012
$
Ici, deux lignes match notre recherche sur la chaîne de caractères 2012. La commande grep agit donc comme un filtre. Intéressons nous à présent aux valeurs de retour que grep est susceptible de renvoyer.
Exercice 5 : Consulter la documentation de la commande grep (man grep
). Quelles sont
les trois valeurs susceptibles d'être retournées ? (cf. section EXIT STATUS).
.
.
.
Remarque : Les valeurs de retour d'une commande quelle quel soit sont généralement documentées car vous ne pouvez pas les inventer.
Exercice 6: Quelle est la valeur de retour des commandes suivantes
$ grep 2012 liste.txt # ...
$ grep 1999 liste.txt # ...
$ grep Octave liste.txt # ...
$ grep Marionnette liste.txt # ...
$ grep 2011 LISTE.TXT # ...
Rappel : On peut afficher la valeur de retour de la derniére commande exécutée avec un echo $?
.
Nous allons à présent vous proposer un script shell avec des instructions conditionnelles pour réagir a la valeur de retour de la commande grep.
Soit le script shell suivant nommé bilan-v1.0.sh
qui prendra en paramètre une année (ex: 2011) et un nom de
fichier, par exemple liste.txt
qui respectera le format décrit ci-avant
(i.e. un prénom et une année de naissance par ligne).
$ ./bilan-v1.0.sh 2011 liste.txt
Voici le source de la version 1.0 du script shell bilan-v1.0.sh
.
#!/bin/bash
year=$1 # parametre 1
list_file=$2 # parametre 2
echo "Le fichier a utilisé est $list_file"
echo "L'année cherchée est $year"
grep "$year" $list_file
return_value=$? # on sauvegarde la valeur de retour du 'grep'.
if [ $return_value -eq 0 ]; then
echo "A COMPLETER 0"
exit 0
fi
if [ $return_value -eq 1 ]; then
echo "A COMPLETER 1"
exit 1
fi
if [ $return_value -eq 2 ]; then
echo "A COMPLETER 2"
exit 2
fi
exit 4
Remarque : L'instruction if [ $return_value -eq 0 ]; then ...
peut se lire de la
façon suivante : Si le contenu de la variable $return_value
est égal à 0
alors ....
ATTENTION : Veillez a toujours bien laisser un caractére d'espacement autour des crochets !!!
# CORRECT
if [ $numberOfcatsLives -le 9 ]; then echo "The cat comes back to life!"; fi
# INCORRECT !!!
if [$age -ge 18]; echo "You can get drunk"; fi
Exercice 7 : Dans le script précédent remplacer les instructions d'affichage echo "A COMPLETER _"
avec
des messages qui ont du sens. Par exemple :
echo "Aucun élève est né en $year"
echo "Le fichier $list_file est introuvable"
...
Puis tester les différents cas.
Voici à présent une nouvelle version du script que l'on nommera bilan-v2.0.sh
.
Attention : Ne considérez pas ce script comme une meilleur version de bilan-v1.0.sh
.
#!/bin/bash
year=$1 # parametre 1
list_file=$2 # parametre 2
echo "Le fichier a utilisé est $list_file"
echo "L'année cherchée est $year"
grep "$year" $list_file
return_value=$?
if test $return_value -eq 0
then
echo "$? : Des élèves de l'année $year sont présents dans la liste."
else
echo "$? : Aucun élève de l'année $year n'est présent dans la liste."
fi
exit 0
Question 8: Testez différents scénarios, notamment avec une année qui n'existe pas, puis un fichier liste qui n'existe pas. Pourquoi peut-on considérer que bilan-v2.0.sh est moins complet que la précédente version ?
Question 9: A votre avis les $?
dans bilan-v2.0.sh contiennent la valeur de retour de quelle instruction ?
Activités
Activité 1 : Variable d'environnement $#
Reprenons le scripte bilan-v1.0.sh
. Son bon fonctionnement
implique que l'utilisateur lui passe deux paramètres (un motif a rechercher
et un nom de fichier). La variable $#
contient le nombre de
paramètres qui a été passé au script. Au tout début du script, ajoutez une
instruction conditionnelle. Si le nombre de paramètres est égale à deux
exécutez le script normalement, si non affichez un message expliquant comment
utiliser ce script et interrompez son exécution avec une valeur de retour à 3.
#!/bin/bash
echo "Nombre de paramétres : $#"
if ...
Activité 2 : Compte à rebours paramétrable
Ecrivez un script shell permettant d'obtenir un comportement équivalent à la démonstration ci-dessous.
$ ./comptearebours.sh # appel au script sans paramètre
Usage : ./comptearebours.sh [integer]
$ echo $?
1
$ ./comptearebours.sh 5 # on passe au script en entier comme paramètre
5
4
3
2
1
BOOM
_ ._ _ , _ ._
(_ ' ( ` )_ .__)
( ( ( ) `) ) _)
(__ (_ (_ . _) _) ,__)
`~~`\ ' . /`~~`
; ;
/ \
_____________/_ __ \_____________
$ echo $?
0
Astuce : Pour soustraire 1
à une variable voici une façon de faire.
a=10
a=$((a - 1))
echo $a # affiche 9
Astuce : Pour mettre en pause temporairement l'enchainement d'instruction utilisez sleep
for i in 1 2 3; do
echo $i
sleep 1 # pause de 1 seconde
done
Astuce : Pour créer facilement une séquence de nombre entier utilisez seq
(man seq
)
$ seq 3
1
2
3
Activité 3 : Jeu du plus ou du moins (read
)
Le principe de ce jeu est le suivant : le programme va tirer au sort un nombre entre 1 et 100. Il invitera ensuite le joueur à saisir un nombre qu'il pense deviner. Après la saisie, le programme indiquera si le nombre saisi par le joueur est trop grand ou trop petit. Si le nombre saisi est le bon, le jeu affichera un message de félicitations et se fermera.
Pour vous aider voici comment tirer un nombre au hasard entre 1 et 100 en code shell
$ r=$(( ( RANDOM % 100 ) + 1 ))
$ echo $r
42 <---- un nombre compris entre 1 et 100
Pour rendre votre script interactif vous utiliserez la commande read
à
laquelle on passe en paramètre un nom de variable. Cette variable contiendra
la chaine de caractères saisie par l'utilisateur.
$ read a
Hello world
$ echo "L'utilisateur a saisi la chaine de caractères : $a"
Hello world
A vous de jouer !
Simplification : Dans le cadre de cet exercice on fait confiance à l'utilisateur pour qu'il saisisse une valeur numérique (et pas une chaine de caractères que bash ne sera pas capable de convertir en un entier).
Annexe
options | Traduction | Symbol |
---|---|---|
-eq |
equal | = |
-ne |
not equal | != |
-gt |
greater than | > |
-lt |
lower than | < |
-ge |
greater or equal | >= |
-le |
lower or equal | <= |
Astuce: Si vous craignez d'oublier les espaces autour des crochets vous pouvez utiliser la commande test
.
Les instructions suivantes sont équivalentes.
if [ 1 -eq 1 ]; then echo "Always true"; fi
if test 1 -eq 1; then echo "Always true"; fi
Félicitation ! Vous avez terminé le TP #3. Vous pouvez passer au TP #4