7 - Les processus

Les processus

Chaque application, chaque commande est un processus.

Certains processus vont s’exécuter jusqu’à ce que vous les arrêtiez, d’autres vont réaliser une tâche et s’arrêter tout seul.

Exemple:

  • La commande ls : elle s’exécute et se termine tout de suite. Vous pouvez taper une autre commande.

  • La commande firefox : elle ouvre Firefox mais reste en exécution jusqu’à ce que vous fermiez Firefox. Notez que vous ne pouvez plus utiliser votre terminal tant que Firefox fonctionne.

Jobs versus processus

Il est possible d’arrêter ou de suspendre temporairement un processus, de même que de le faire passer de l’exécution en arrière-plan à une exécution en avant-plan (et inversement). Dans ce contexte, on nommera les processus des jobs. En fait, on dira qu’un processus devient une job aussitôt qu’on s’est mêlé de son exécution, aussitôt qu’on la contrôlera. Du coup, toute job est un processus mais tout processus n’est pas une job.

On visualisera les jobs à l’aide de la commande jobs. Les jobs seront listées de par leur numéro de job, pas leur PID.

Comment faire pour lancer Firefox et pouvoir continuer à utiliser le terminal?

Quand une commande vous empêche d’utiliser le terminal pendant son exécution, c’est parce qu’elle s’exécute au premier plan.

Comment faire pour qu’une application s’exécute en arrière plan?

Deux possibilités:

  • Lors de l’exécution initiale: lancez la commande suivi de &:
$ firefox &
  • Si la commande s’exécute déjà et que vous souhaitez la passer en arrière plan, vous devez d’abord faire Ctrl-z pour stopper l’application. Notez alors que vous pouvez utiliser votre terminal mais le programme, lui n’est plus utilisable. Tapez ensuite bg (pour background), le programme va alors s’exécuter en arrière plan.

  • Comment faire pour remettre la commande au premier plan? Avec fg (pour foreground).


Exercice 1

Lancez Firefox puis faites le passer en arrière plan et ramenez le au premier plan.

Pour arrêter une commande au premier plan: Ctrl-c


La commande servant à visualiser les processus en cours d’exécution est ps.

$ ps -f

Par exemple, ps affichera la liste de vos processus présentement en exécution dans l’ordinateur où se déroule la session de travail (où s’exécute votre shell).

Si vous entrez cette commande, vous voyez que les processus sont identifiés par deux numéros: pid et ppid:

  • pid: identifiant du processus

  • ppid: identifiant du processus père

Le processus père est le processus qui les a créé.

Exemple: Si vous lancez une commande depuis votre terminal, celui-ci (le terminal) sera le père de la commande que vous venez de lancer.


Si vous faites un man ps, vous vous rendrez compte qu’il y a une très grande quantité d’options possibles, la plupart d’entre elles sont plus ou moins incompréhensibles.

Les plus importantes sont les suivantes:

  • e: affiche tous les processus sur la machine, incluant ceux des autres et incluant ceux qui ne sont pas associés à un port tty (donc démarrés par le système) - finalement, tout.
  • a: n’affiche pas les processus du système, ni les “session leaders” (les processus de login et les init)
  • x: affiche les processus du système (sans tty) et les “session leaders”, et ajoute l’état de chaque processus
  • f: affiche un format plus long, avec plus d’information sur chaque processus
  • u : affiche les processus de l’usager courant.

En gros, ps –ax équivaut à ps –e, en ce sens qu’ils nous affichent la même liste de processus. Ils diffèrent par contre sur un point: ps –ax affiche l’état de chaque processus et ps –e ne le fait pas. ps tout seul affiche uniquement les processus de l’usager en cours, ce qui est souvent suffisant. ps –f ajoutera de l’information sur chaque processus.

Un administrateur du système qui voudra voir tout ce qui roule sur son serveur, peu importe chez quel usager, utilisera ps –ef pour voir tous les processus possibles avec un maximum d’information. Voici quelques exemples d’utilisations courantes, avec explication sur la sortie.

Exécution typique de ps (tout court, sans switches):

$ ps

PID TTY TIME CMD
2321 pts/0 00:00:00 bash
2332 pts/0 00:00:00 ps

À noter: on voit ici la liste de vos processus les plus clairement actifs au moment du lancement de la commande: votre shell (bash), et la commande ps en cours d’exécution.

  • Le TTY est le port qui est attribué par le système à votre session de travail (c’est le même dans chaque cas, puisqu’on parle d’une seule et même session de travail).
  • Le PID est le numéro d’identification du processus.
  • Le TIME est le temps de traitement total utilisé par chaque processus, arrondi à la seconde (ce qui donne souvent des 0).

Exécution typique de ps -f (voir les processus lancés par l’usager, de façon plus détaillée et en ordre croissant de PID):

$ ps -f

UID   PID  PPID C STIME TTY   TIME     CMD
alain 2321 2320 0 06:04 pts/0 00:00:00 bash
alain 2366 2321 0 06:17 pts/0 00:00:00 ps –f

  • Le UID identifie l’utilisateur propriétaire de chaque processus.
  • Le PID est le numéro d’identification du processus.
  • Le PPID identifie le processus parent de chaque processus. Tout processus a un parent (par exemple, ici, le parent de la commande ps -f est le shell d’où elle a été lancée).
  • Le C est le pourcentage de temps d’utilisation du CPU sur le temps réel écoulé depuis le lancement du programme, arrondi à l’entier près.
  • STIME est l’heure (ou la date, si ce n’est pas aujourd’hui) où le processus a été lancé.
  • Il est possible, avec d’autres options, de modifier grandement l’affichage des données de ps. Par exemple, la colonne STAT à l’affichage identifie l’état d’exécution de chaque processus. On verra S pour dormant (sleeping), R pour en cours d’exécution (running or runnable), T pour suspendu (traced), W pour bloqué (wait) et Z pour zombie; pour les définitions plus détaillées et pour les autres états moins courants, référez-vous aux pages de manuel man ps.

À noter: un processus enfant hérite de la plupart des propriétés de son parent (si un processus root lance une commande, elle aura elle aussi par défaut des droits root).


Exercice 2

Avec ps, notez le pid de votre shell. Lancez Firefox depuis votre console. Quel est le pid de Firefox? Quel est le pid du père de Firefox?


Que se passe-t-il si on tue le père d’un processus?

Il sera adopté par le processus 1.

Comment se nomme le processus 1?

Il est donc possible de créer un arbre généalogique avec tous les processus.

L’arborescence des processus s’obtient avec:

$ pstree

Exercice 3

Lancez Firefox en tâche de fond à l’aide de la ligne de commande, notez son pid et son ppid (le ppid devrait être votre SHELL).

Fermez le terminal puis ouvrez-en un nouveau.

Quel est le ppid de Firefox maintenant?


Un processus peut être dans plusieurs états:

  • Élu: c’est lui qui est sur le processeur, en cours d’exécution.

  • Prêt: il est dans la file d’attente du processeur, il n’est en attente d’aucune ressource.

  • Bloqué: il est en attente d’une ressource autre que le processeur (disque par exemple).

  • Zombie: le processus est mort mais son père n’a pas encore pris en compte sa mort. Il y a toujours une entrée le concernant dans la table des processus.

Ces différents états sont gérés par l’ordonnanceur.

Pour afficher les processus en ordre décroissant d’utilisation de l’unité centrale de traitement et leur utilisation des ressources. L’affichage est également rafraîchi régulièrement :

$ top

À quelle fréquence se rafraîchit top? Comment obtenir un rafraîchissement toutes les secondes?

Il existe plusieurs commandes qui peuvent être tapées directement dans top, pour modifier l’affichage ou gérer les processus à partir de là. La plus importante à connaître: q pour quitter! Pour le reste, faites un man top pour plus de détails!


Pour arrêter des processus:

$ kill pid

kill peut avoir différents paramètres. Pour tuer un processus immédiatement:

$ kill -9 pid

killall peut détruire tous les processus ayant le même nom:

$ killall httpd

On tue un processus pour en interrompre de force l’exécution et l’éliminer de la mémoire. La commande servant à tuer un processus est kill pid

Notez que:

  • Seul l’usager root peut tuer les processus des autres usagers.
  • Parfois, un processus refusera le signal émis par un kill. Il sera quand même possible de le tuer avec kill -SIGKILL pid
  • Vous verrez aussi, dans le registre des meurtres brutaux, la commande kill -9 pid qui est équivalente à kill -SIGKILL pid
  • En réalité, kill n’est pas une commande qui sert uniquement à tuer des processus. C’est plutôt une commande qui sert à envoyer des signaux aux processus. Certains signaux tuent, d’autres demandent au processus de se terminer, d’autres encore peuvent avoir tout un tas de fonctionnalité.
  • Chaque signal porte un nom qui commence par SIG ou bien un numéro. On peut déterminer quel signal envoyer au processus en utilisant l’un ou l’autre, comme une option. C’est pourquoi on peut faire kill -9 ou kill -SIGKILL pour obtenir exactement le même effet.
  • Si on omet de spécifier un signal, kill envoie par défaut SIGTERM (ou 15), qui demande au processus de se terminer “gracieusement”.
  • Il est possible d’énumérer plusieurs pid dans une même commande (en les séparants par un espace): kill 123 145 1203 2345

Il est aussi possible d’attendre la fin d’une commande avant d’en exécuter une autre même si celle-ci a été lancée en arrière plan.

Exemple:

$ firefox &
wait $!

Ou encore, dans un script:

firefox &
wait $!
echo "Fin du script"

Si vous exécutez un processus à partir du terminal, la fermeture du terminal entraine la fin du processus.

Pour éviter ce comportement, deux possibilités existent:

Une fois le processus démarré:

$ disown <pid>

Au lancement de la commande:

$ nohup <commande>

Exercice 4

  1. Lancez la commande
$ gedit
  • Notez que cette commande s’exécute tant que vous ne fermez pas le fenêtre.

  • Ouvrez un autre terminal, trouvez le pid de la commande gedit et tuez la commande.

  1. Ouvrez un terminal, exécutez Firefox en tâche de fond. Fermez le terminal. Que se passe-t-il avec Firefox?
  • Essayez maintenant la même opération mais après avoir exécuté
$ disown  
  • Et après avoir lancé Firefox de cette façon:
$ nohup firefox

Codes de retour

Une commande peut s’exécuter correctement mais peut aussi se terminer avec une erreur.

Chaque commande va donc avoir une valeur de retour qui permet de savoir s’il y a eu une erreur ou non.

Par convention, si la valeur de retour de la commande est 0, la commande s’est exécutée correctement sans erreur.

S’il y a des erreurs, la valeur de retour sera différente de 0.

Variables prépositionnées

Certaines variables sont réservées par le système pour des significations particulières.

Il sera ainsi possible de connaitre la valeur de retour de la dernière commande:

$ echo $?

Ou de connaitre le PID de la dernière commande lancée en tâche de fond:

$ echo $!

Exercice 5

  1. Lancez la commande ls. Quel est son code de retour? Est-ce un succès ou un échec?

  2. Sans être root, lancez la commande $ find / -name “*.conf”. Quel est son code de retour? Pourquoi?


Combinaison de commandes

Il est possible de combiner des commandes. Nous avons déjà vu le | mais il y a d’autres possibilités.

$ Commande 1 ; Commande 2 ; …

Permet d’enchainer les commandes les unes après les autres.

$ Commande 1 && Commande 2

Exécutera Commande 2 seulement si Commande 1 s’est exécutée avec succès et n’a pas renvoyé d’erreur.

$ Commande 1 || Commande 2

Exécutera Commande 2 seulement si Commande 1 a eu un problème et a renvoyé une erreur.

Exemples:

Tester l’existence d’un fichier et exécuter la commande s’il existe:

$ test -e fichier && commande

Notez que la commande ne s’exécutera pas si le fichier n’existe pas

Afficher un message OK si la commande a réussi:

$ commande && echo OK

Ou bien afficher un message d’erreur si la commande échoue:

$ commande || echo ERREUR

Et enfin, afficher OK si le code de retour est 0 ou ERREUR si le code de retour est différent de 0 :

$ Commande && echo OK || echo ERREUR

Exemple :

$ test $var -eq 0 && echo "$var = 0" || echo "$var != 0"

Exercice 6

  1. Exécutez:
$ find / -name "*.conf" && ls
  • Est-ce que les deux commandes s’exécutent? Et si vous les inversez?
  1. Exécutez
$ find / -name "*.conf" || ls
  • Est-ce que les deux commandes s’exécutent? Et si vous les inversez?
  1. Exécutez
$ find / -name "*.conf" & ls
  • Est-ce que les deux commandes s’exécutent? Et si vous les inversez?

Il est possible d’utiliser des () pour déterminer la priorité des opérateurs &, &&, |, || et ;

Exemple:

ls est exécutée s’il y a une erreur avec find et le résultat de la ou des commande(s) exécutée(s) sera filtré par grep:

$ (find / -name "*.conf" 2>/dev/null || ls) | grep a

ls sera exécuté s’il y a une erreur avec find et le résultat de ls seulement sera filtré par grep:

$ find / -name "*.conf" 2>/dev/null || (ls | grep a)

Rappel:

$ $(commande) 

permet de stocker le résultat d’une commande dans une variable.

Exemple:

La commande suivante permet de stocker le résultat de la commande find dans la variable var.

$ var=$(find / -name "*.conf")
$ echo $var

Cette enchainement donne le même affichage que:

$ find / -name "*.conf"

mais le résultat est réutilisable.

Commandes utiles

Pour chercher dans le contenu de plusieurs fichiers :

$ egrep <chaine> <fichiers>
$ egrep ssh *

Pour connaître l’espace disque:

$ df [-h]

Pour connaître la taille d’un fichier ou d’un répertoire:

$ du [-sh] répertoire

Pour connaître l’état de la mémoire:

$ free