====================== Séance 4 : Processus ====================== .. include:: commondefs.rst.inc .. ifslides:: .. include:: credits.rst.inc .. index:: processus, pid Processus ========= On appelle **processus** l'exécution d'un programme. Sous Linux, chaque processus est identifié par un numéro appelé PID (`Processus IDentifier`:eng:). À chaque processus est également associé : * l'identifiant de l'utilisateur pour le compte duquel il s'exécute (UID), qui détermine les *droits* du processus ; * l'identifiant de son processus parent (PPID). ps [options] — *processes* -------------------------- .. program:: ps Affiche la liste des processus en cours (par défaut : uniquement ceux de l'utilisateur et du terminal courant). .. option:: -u Affiche tous les processus de l'utilisateur (tous terminaux confondus). .. option:: -A Affiche tous les processus du système. .. option:: -f Donne plus d'information sur les processus affichés. .. option:: -H Ordonne et indente les processus selon leur généalogie (PPID). top --- .. program:: top Affiche les processus consommant le plus de ressource CPU, en rafraichissant l'affichage régulièrement. Pour quitter ``top``, tapez ``q`` ou CTRL+C. kill [...] ---------------- Arrête (« tue ») le(s) processus identifié(s) par ``pid``. .. note:: On verra plus tard une utilisation plus générale de la commande ``kill``. .. index:: processus;suspendu, suspendu;processus Processus suspendus =================== * Un processus peut être suspendu en tapant CTRL+Z pendant son exécution. * Le shell reprend immédiatement la main. * Le processus est « endormi », mais toujours « vivant » : son exécution peut être reprise. jobs ---- .. program:: jobs Affiche la liste des processus suspendus ou en tâche de fond pour le shell courant. Chaque process est identifié par un numéro de job (*différent* de son PID). .. option:: -l Affiche également le PID de chaque processus. .. option:: -p Affiche *uniquement* le PID des processus. .. note:: Les numéros de job sont propres au shell, alors que les PIDs sont valables pour tout le |SE|. fg [jobid] — *foreground* ------------------------- .. program:: fg Relance au premier plan le job spécifié. .. describe:: jobid Le numéro de job du processus à relancer. Par défaut : le processus exécuté le plus récemment. kill % ------------- Au lieu d'un PID, la commande ``kill`` accepte aussi comme argument un numéro de job, précédé du caractère pourcent ``%``. .. index:: tâche de fond, processus;tâche de fond Tâches de fond ============== * À chaque ligne de commande, le shell lance un processus (ou plusieurs, dans le cas des `pipelines `:ref:), et attend qu'il(s) se termine(nt) pour reprendre la main. * Il est également possible lancer un processus en **tâche de fond** ; dans ce cas, le shell n'attend *pas* la fin du processus et reprends la main immédiatement. * Ceci peut être intéressant pour des tâches longues (compilation, téléchargement de fichier, décompression d'archive...) .. warning:: Lorsqu'une tâche de fond affiche du texte, ceci peut avoir des effets inattendus. Lancer directement un processus en tâche de fond ------------------------------------------------ On ajoute à la fin de la ligne de commande le caractère esperluette (``&``). Exemple :: curl http://example.org/ubuntu-19-10.iso >ubuntu & NB: le ``&`` peut également être utilisé comme un séparateur pour lancer plusieurs processus sur la même ligne de commande :: prog1 & prog2 & prog3 # lance prog1 et prog2 et tâche de fond, et prog3 au premier plan bg [jobid] — *background* ------------------------- .. program:: fg Relance en tâche de fond un processus suspendu. .. describe:: jobid Le numéro de job du processus à relancer. Par défaut : le processus exécuté le plus récemment. Signaux ======= * Un signal est un message envoyé par le |SE| à un processus. * La plupart des signaux ont pour effet de tuer le processus, mais + certains ont un autre effet (voir ci-après), et + un programme peut personnaliser sa répose à certains signaux. kill [options] [...] -------------------------- .. program:: kill Envoie un signal à un ou plusieurs processus. .. describe:: pid [...] Le(s) PID(s) du/des processus à qui envoyer le signal. .. option:: -s [signal] Le signal à envoter (par défaut ``SIGTERM``). Quelques signaux utiles ----------------------- * SIGTERM : demande « poliment » au processus de s'arrêter * SIGKILL : tue le processus (utile lorsque SIGTERM échoue, ce signal n'est pas « personnalisable ») * SIGTSTP : suspend le processus * SIGCONT : relance un processus suspendu Remarques --------- * CTRL+C a pour effet d'envoyer un signal (SIGINT) au(x) processus courant(s). * CTRL+Z a pour effet d'envoyer le signal SIGTSTP au processus courant. * ``bg`` sert en fait à envoyer SIGCONT à un processus. * ``fg`` envoie également SIGCONT au processus, et fait en sorte d'attendre la fin. * On peut voir que ``man`` a personnalisé sa réponse à SIGINT (le procecuss n'est pas tué lorsqu'on tape CTRL+C). Enchaînement ============ On a déjà vu plusieurs moyens de lancer plusieurs processus depuis une seule ligne de commande :: # en parallèle prog1 & prog2 & prog3 # en parallèle avec redirections via des tubes prog1 | prog2 | prog3 .. index:: enchaînement;séquentiel Enchaînement séquentiel ----------------------- On peut également lancer plusieurs processus l'un à la suite des autres, en les séparant par un point-virgule (``;``) :: # en séquence prog1 ; prog2 ; prog3 .. hint:: Le point-virgule joue exactement le même rôle que le retour à la ligne. .. index:: code;statut, statut;code .. _valeur_de_retour: Valeur de retour d'un processus ------------------------------- .. code-block:: c int main(int argc, char* argv[]) { /* ... */ } * La valeur de retour de ``main`` est récupérée par le |SE|; on l'appelle parfois code de statut (`status code`:eng:). * Par convention, elle indique le succès (0) ou l'échec (≠0) du processus. * La commande ``echo $?`` affiche le code de status de la dernière commande exécutée. .. index:: enchaînement;conditionnel Enchaînements conditionnels --------------------------- * « et alors » ``&&`` : la commande de droite est exécutée si et seulement si la commande de gauche a réussi (status = 0) :: prog1 && prog2 * « ou sinon » ``||`` : la commande de droite est exécutée si et seulement si la commande de gauche a échoué (status ≠ 0) :: prog1 || prog2 * dans tous les cas, le code de statut de l'enchaînement est celui de la dernière commande exécutée. Priorité et parenthèses ----------------------- * Le connecteur `pipe `:ref: (``|``) a priorité sur les connecteurs d'enchaînement. * On peut influer sur les priorités avec des parenthèses :: $ echo Z; echo A | sort Z A $ (echo Z; echo A) | sort A Z Travaux dirigés =============== .. ifslides:: `Consultez les ici <../s4.html#travaux-diriges>`_ .. ifnotslides:: Échauffement ------------ #. À l'aide de la commande ``echo``, affichez ``Bonjour le (beau) monde``. #. À l'aide de la commande ``echo``, affichez un point-virgule (``;``). #. À l'aide de la commande ``echo``, affichez une esperluette (``&``). #. À l'aide de la commande ``echo``, affichez deux esperluettes (``&&``). Exercice 1 ---------- On rappelle que par défaut, ``ps`` n'affiche que les processus de l'utilisateur et du terminal courant. #. Ouvrez un terminal. #. Combien de processus devrait afficher la commande ``ps`` ? Faites le test et expliquez, le cas échéant, la différence avec votre prédiction. Vous pouvez vous aider des options `-f <#cmdoption-ps-f>`_ ou `-H <#cmdoption-ps-h>`_. #. Affichez la mage ``man`` de la commande ``ps``, puis *suspendez* le processus. #. Combien de processus devrait maintenant afficher la commande ``ps`` ? Faites le test et expliquez, le cas échéant, la différence avec votre prédiction. #. Combien de processus devrait afficher la commande ``job`` ? Faites le test et expliquez, le cas échéant, la différence avec votre prédiction. #. Lancez la commande ``jobs -l`` pour voir le PID du/des job(s). Ceci est-il cohérent avec la sortie de la commande ``ps``. #. Arrêtez le processus ``man``. #. Vérifiez avec ``ps`` et ``jobs`` que le processus est bien arrêté. Exercice 2 ---------- #. Affichez tous les processus qui s'exécutent en votre nom. #. Affichez tous les processus du système. #. À l'aide de la commande ``wc``, affichez le nombre total de processus. #. À l'aide de la commande ``egrep``, affichez le nombre de processus dont le nom contient ``gsd``. #. À l'aide de la commande ``cut``, affichez les PIDs des processus dont le nom contient ``gsd``. Exercice 3 ---------- #. Ouvrez la commande ``man ps``, puis suspendez le processus. #. Dans le même terminal, ouvrez la commande ``man top``, puis suspendez le processus. #. Reprenez la lecture de la page man de ``top``. #. Suspendez le processus, puis reprenez la lecture de la page man de ``ps``. #. Suspendez le processus, puis reprenez la lecture de la page man de ``top``. #. Quittez définitivement la lecture de cette page. #. De retour au shell, arrêtez le processus ``man ps`` sans le réactiver. #. Vérifiez que les deux processus ont bien été arrêtés. Exercice 4 ---------- #. Copiez le fichier ``/dev/random`` dans le répertoire courant. #. Si la copie n'est pas terminée au bout de 5 secondes, suspendez le processus et relancez le en tâche de fond. #. Affichez la taille du fichier copié à avec ``ls -l``. #. Patientez quelques secondes, puis vérifiez si le processus ``cp`` est toujours en cours. #. Si c'est le cas, affichez à nouveau la taille du fichier. #. Ça n'était pas une bonne idée... Interompez le processus ``cp`` et supprimez la copie. .. note:: Le fichier ``/dev/random`` est un fichier virtuel, au même titre que ``/dev/null``. Lorsqu'on lit son contenu, ce fichier produit des données aléatoire, sans jamais s'arrêter. .. _guillemets_inversés: Interlude : substitution ------------------------ En plaçant une (ligne de) commande entre guillemets inversés (`````, AltGr+7 sur un clavier PC AZERTY), on peut récupérer sa `sortie standard `:ref: pour la réinjecter la ligne de commande extérieure :: # crée une copie "datée" du fichier /etc/passwd cp /etc/passwd passwd-`date +%Y-%m-%d-%H:%M:%S` * Si la sortie standard contient des espaces (y compris des sauts de ligne), la substitution générera plusieurs arguments. Exercice 5 ---------- #. Ouvrez la commande ``man ps``, puis suspendez le processus. #. Ouvrez la commande ``man top``, puis suspendez le processus. #. Ouvrez la commande ``man kill``, puis suspendez le processus. #. Ouvrez la commande ``man ls``, puis suspendez le processus. #. Affichez la liste des PIDs des processus suspendus à l'aide de la commande jobs. #. À l'aide d'une substitution, tuez tous les processus suspendus en une seule commande. #. Si cela ne fonctionne pas, utilisez le signal SIGKILL au lieu du signal par défaut (SIGTERM). Commande utile : wget [options] ------------------------------------- .. program:: wget Télécharge dans un fichier le contenu de l'URL passée en paramètre. Le nom du fichier correspond à la dernière partie de l'URL. Le code de statut est différent de 0 en cas d'erreur de téléchargement. .. option:: -q, --quiet N'affiche aucune information pendant le téléchargement. Exercice 6 ---------- #. Créez un répertoire vide, et rendez-vous dans ce répertoire. #. Lancez la ligne de commande suivante :: wget -q https://httpbin.org/delay/15 & wget -q https://httpbin.org/delay/5 & wget -q https://httpbin.org/delay/10 & Cette ligne de commande va télécharger en silence (``-q``) en parallèle (``&``) les 3 URLs dans trois fichiers nommés respectivement ``15``, ``5`` et ``10``. #. Utilisez répétitivement la commande ``ls`` pour voir apparaître les fichiers téléchargés. Apparaissent-t-ils dans l'ordre de la ligne de commande ? Cela confirme-t-il que les 3 commandes se sont exécutées en parallèle ? #. Téléchargez maintenant *au premier plan* le contenu de l'URL https://httpbin.org/delay/1?foo=bar (sans utiliser l'option ``-q`` de ``wget``). Quel fichier a été créé ? #. Téléchargez maintenant *au premier plan* le contenu de l'URL https://httpbin.org/delay/2?foo=bar&toto=tata (sans utiliser l'option ``-q`` de ``wget``). Quel(s) fichier(s) a/ont été créé(s) ? Tout s'est-il bien passé ? Avez-vous bien pris toutes les précautions nécessaires ? Complément d'information : egrep [options] -------------------------------------------------- .. program:: egrep ``egrep`` retourne 0 si ``regex`` est trouvée, 1 sinon. .. option:: -q, --quiet, --silent N'affiche pas les lignes ou ``regex`` est trouvée. Avec cette option, seul le code de retour est utile. Par conséquent, ``egrep`` s'arrête à la première correspondance. Exercice 7 ---------- #. À l'aide de la commande ``egrep``, affichez toutes les lignes du fichier ``/var/log/syslog`` qui contiennent le mot ``kernel``. #. Écrivez une ligne de commande qui affiche ``OUI`` si le fichier ``/var/log/syslog`` contient le mot ``gnome``, et ``NON`` sinon. #. Écrivez une ligne de commande qui affiche ``OUI`` si le fichier ``/var/log/syslog`` contient le mot ``lutin``, et ``NON`` sinon.