web-dev-qa-db-fra.com

Comment obtenir le Job ID?

Comme nous le savons, le shell permet à l'utilisateur d'exécuter des processus d'arrière-plan à l'aide de & à la fin de la ligne de commande. Chaque processus d'arrière-plan est identifié par un ID de travail et, bien sûr, par son PID.

Lorsque j'exécute un nouveau travail, la sortie est quelque chose comme [1] 1234 (le deuxième nombre est l'ID du processus). Essayer d'appeler des commandes comme stop 1 et stop %1 provoque un message d'échec: stop: Unknown job: 1

Comprenant que la commande stop entraîne la suspension d'un travail, je me demandais comment obtenir l'ID du travail et le faire correctement. Si la seule façon de tuer un travail est par son ID de processus, quel est le but de l'ID de travail?

14
Reflection

Après l'envoi d'un processus à l'arrière-plan avec &, Son PID peut être récupéré à partir de la variable $!. Les ID de tâche peuvent être affichés à l'aide de la commande jobs, le commutateur -l Affiche également le PID.

 $ sleep 42 &
 [1] 5260
 $ echo $!
 5260
 $ jobs -l
 [1]  - 5260 running    sleep 42

Certaines implémentations kill permettent de tuer par ID de travail au lieu de PID. Mais une utilisation plus judicieuse de l'ID de tâche consiste à mettre en avant de manière sélective un processus particulier. Si vous démarrez cinq processus en arrière-plan et que vous souhaitez mettre en avant-plan le troisième, vous pouvez exécuter la commande jobs pour voir quels processus vous avez lancés, puis fg %3 Pour mettre en avant celui avec l'ID de travail trois .

24
Marco

Le contrôle des tâches est une fonctionnalité qui a été ajoutée aux systèmes BSD au début des années 80. csh étant le shell BSD, il n'est pas surprenant que la fonctionnalité ait été introduite en premier dans ce shell. Vous avez dû attendre plusieurs années avant d'ajouter le contrôle des tâches aux unités non BSD et aux autres shells (à commencer par le Korn Shell).

Il convient de noter que le contrôle des travaux n'est pas la possibilité de démarrer un processus de manière asynchrone (c'est-à-dire que le Shell n'attend pas sa fin avant d'émettre la prochaine invite; le Bourne Shell avait & Dès le début, mais n'a pas '' t prend en charge le contrôle des tâches jusqu'à 10 ans plus tard), mais la capacité d'interagir avec plusieurs tâches à partir du même terminal.

Nous parlons de emplois, pas processus. Pour implémenter le contrôle des travaux, groupes de processus ont été introduits. Un travail est un groupe de processus (travail du point de vue de l'utilisateur, groupe de processus du point de vue de la mise en œuvre du système d'exploitation).

Ce sont généralement des shells interactifs qui créent et gèrent des groupes de processus, et encore une fois, tout est question d'interaction avec le terminal.

Lorsque vous exécutez une commande, tous les processus et leurs descendants sont placés dans un nouveau groupe de processus.

Dans une session sur un terminal donné, un groupe de processus bénéficie d'un accès privilégié au terminal. C'est le groupe de processus de premier plan du terminal. Ce groupe de processus est celui dont les membres reçoivent un SIGINT/SIGTSTP/SIGQUIT lorsque vous appuyez sur CTRL-{C,Z,\}. Les processus dans d'autres groupes de processus sont suspendus lorsqu'ils tentent de lire (et parfois d'écrire) sur le terminal. etc.

Lorsque vous démarrez un travail au premier plan, le shell interactif fait de son groupe de processus le groupe de processus de premier plan du terminal, et non pour ceux démarrés en arrière-plan.

De cette façon, un utilisateur peut faire plusieurs choses à la fois dans un terminal, il peut avoir une liste de jobs, qui sont des groupes de processus qui peuvent être au premier plan (avec un accès privilégié au terminal), en arrière-plan, en cours d'exécution ou suspendus. Et le travail peut être déplacé de/vers l'arrière-plan/premier plan et suspendu/en cours d'exécution.

De nos jours, tous les systèmes et tous les shells prennent en charge le contrôle des travaux (bien que dans le Bourne Shell, vous devez le demander explicitement avec set -m IIRC).

Toutes les commandes démarrées à l'invite reçoivent un numéro de travail. Du point de vue du système, ceux-ci sont mappés aux ID de groupe de processus.

 $ ps -fj | cat
UID        PID  PPID  PGID   SID  C STIME TTY          TIME CMD
chazelas  8237  7315  8237  8237  0 15:54 pts/7    00:00:00 /bin/zsh
chazelas 10720  8237 10720  8237  0 21:25 pts/7    00:00:00 ps -fj
chazelas 10721  8237 10720  8237  0 21:25 pts/7    00:00:00 cat

Ci-dessus, j'ai commencé ce travail ps -j | cat Au premier plan. Il a été affecté au groupe de processus 10720 (qui se trouve également être l'ID de processus de ps). Si vous aviez interrogé l'ID du groupe de processus de premier plan du terminal au moment où ils étaient en cours d'exécution (avec tcgetpgrp()), vous auriez obtenu 10720.

$ (sleep 100;:) | sleep 101 &
[1] 10787 10789
$ ps -fj
UID        PID  PPID  PGID   SID  C STIME TTY          TIME CMD
chazelas  8237  7315  8237  8237  0 15:54 pts/7    00:00:00 /bin/zsh
chazelas 10787  8237 10787  8237  0 21:33 pts/7    00:00:00 /bin/zsh
chazelas 10788 10787 10787  8237  0 21:33 pts/7    00:00:00 sleep 100
chazelas 10789  8237 10787  8237  0 21:33 pts/7    00:00:00 sleep 101
chazelas 10790  8237 10790  8237  0 21:33 pts/7    00:00:00 ps -fj

Cette fois, j'ai commencé un pipeline en arrière-plan. Le shell m'a donné un numéro de travail (1) et 2 identifiants de processus ((t)csh, pdksh et zsh donne tous les identifiants de processus, le comportement varie dans les autres shells), un pour un sous-shell, un pour sleep 101. Soit dit en passant, ce sous-shell a engendré un 3ème processus (sleep 100). Le shell n'a pas signalé le pid de celui-ci car il n'en sait rien, mais il fait toujours partie du même travail (groupe de processus 10787 ci-dessus).

Maintenant, vous avez quelques commandes pour manipuler ces travaux: fg, bg, kill, wait et jobs (certains les shells ont également un disown et des alias à kill pour envoyer un signal par défaut différent).

Ceux-ci prennent les identifiants de travail au format %nn est le numéro de travail. Il y a %foo Pour faire référence au travail dont la commande commence par foo, et plus (voir le manuel de votre Shell).

kill %1

envoie le signal SIGTERM à tous les processus du travail 1. kill -s STOP %1 parfois aliasé à stop envoie à la place le signal SIGSTOP.

fg %1

le met au premier plan (en fait le groupe de processus de premier plan du terminal, envoie le signal SIGCONT et dit au Shell d'attendre sa fin).

bg %1

reprend (envoie un SIGCONT) un travail d'arrière-plan arrêté.

wait %1

ne met pas le travail au premier plan, mais attend sa fin (ou jusqu'à ce qu'il soit suspendu).

jobs

répertorie les travaux en cours (jobs -l avec pgids et/ou pids).

%% Et %+ Font référence au travail actuel. Il convient de noter que l'emploi actuel n'est pas nécessairement l'emploi le plus récemment commencé. C'est le travail marqué d'un + Dans la sortie jobs '. C'est aussi le travail avec lequel fg ou bg sans argument. Il s'agit du dernier travail suspendu s'il y en a, ou du dernier démarré s'ils sont tous en cours d'exécution.

Donc, attention kill %% Ne va pas tuer le travail que vous venez de démarrer en arrière-plan s'il y a des travaux suspendus. C'est toujours une bonne idée d'exécuter jobs pour voir quels travaux sont en cours d'exécution avant d'en tuer.

Il convient de noter que vous devez pas utiliser avec les identifiants de processus lorsque vous traitez des travaux.

$! Renvoie l'ID de processus de la dernière commande exécutée en arrière-plan. Dans le cas d'un pipeline, c'est le pid de la commande la plus à droite.

$ sleep 100 | sleep 101 & ps -fj; echo "$!"
[1] 11044 11045
UID        PID  PPID  PGID   SID  C STIME TTY          TIME CMD
chazelas  8237  7315  8237  8237  0 15:54 pts/7    00:00:00 /bin/zsh
chazelas 11044  8237 11044  8237  0 22:08 pts/7    00:00:00 sleep 100
chazelas 11045  8237 11044  8237  0 22:08 pts/7    00:00:00 sleep 101
chazelas 11046  8237 11046  8237  0 22:08 pts/7    00:00:00 ps -fj
11045

Au-dessus de $! est 11045, mais le groupe de processus du travail 1 est 11044. Si je kill "$1", je ne tuerai que sleep 101, pas sleep 100. Si je kill -- "-$!" (C'est-à-dire tuer tous les processus du groupe de processus 11045), cela échouera car il n'y a pas de groupe de processus de ce type.

Là, vous voulez utiliser kill %1 (Ou kill %sleep Ou peut-être kill %%) Pour tuer ce travail (qui fera un kill -- -11044).

11
Stéphane Chazelas

Il semble que lorsque vous avez tapé stop, vous exécutiez en fait la commande fournie avec upstart, qui n'est pas liée au csh ou ksh builtin stop commandes que vous connaissez. Ainsi, son message d'erreur concernant un "travail inconnu" ne s'applique pas à ce que vous essayez de faire.

ksh implémente stop comme alias pour kill -s STOP, qui comprend le %n notation pour les travaux ou les ID de groupe de processus. Cet alias fonctionnera également dans d'autres shells, par exemple si votre shell est bash:

$ alias stop='kill -s STOP'
$ sleep 30&
[3] 9820
$ stop %3
[3]+  Stopped     sleep 30
3
Mark Plotnick