web-dev-qa-db-fra.com

Comment obtenir le PID du processus qui vient de commencer

Je veux démarrer le processus (par exemple. MyCommand) et obtenir son pid (pour permettre de le tuer plus tard).

J'ai essayé ps et filtrer par nom, mais je ne peux pas distinguer le processus par les noms

myCommand
ps ux | awk '/<myCommand>/ {print $2}' 

Parce que les noms de processus ne sont pas uniques.

Je peux exécuter le processus en:

myCommand &

J'ai découvert que je peux obtenir ce PID en:

echo $!

Existe-t-il une solution plus simple?

Je serais heureux d'exécuter myCommand et d'obtenir son PID à la suite d'une commande en ligne.

78
rafalmag

Quoi de plus simple que echo $!? En une seule ligne:

myCommand & echo $!
86
Jacek Konieczny

Enveloppez la commande dans un petit script

#!/bin/bash
yourcommand &
echo $! >/path/to/pid.file
30
user9517

Vous pouvez utiliser sh -c et exec pour obtenir le PID de la commande même avant son exécution.

Pour démarrer myCommand, afin que son PID soit imprimé avant de commencer à s'exécuter, vous pouvez utiliser:

sh -c 'echo $$; exec myCommand'

Comment ça fonctionne:

Cela démarre un nouveau Shell, imprime le PID de ce Shell, puis utilise le exec intégré pour remplacer le Shell par votre commande, s'assurer qu'il a le même PID. Lorsque votre shell exécute une commande avec le module intégré exec, votre shell est en fait devient cette commande , plutôt que le comportement le plus courant de bifurquer une nouvelle copie de lui-même, qui a son propre PID séparé et qui devient alors la commande.

Je trouve cela beaucoup plus simple que les alternatives impliquant une exécution asynchrone (avec &), le contrôle des travaux ou la recherche avec ps. Ces approches sont correctes, mais à moins que vous n'ayez une raison spécifique de les utiliser - par exemple, la commande est peut-être déjà en cours d'exécution, auquel cas la recherche de son PID ou l'utilisation du contrôle des travaux aurait du sens - je suggère d'envisager cette méthode en premier. (Et je n'envisagerais certainement pas d'écrire un script complexe ou un autre programme pour y parvenir).

Cette réponse inclut un exemple de cette technique.


Certaines parties de cette commande peuvent parfois être omises, mais pas habituellement.

Même si le shell que vous utilisez est de style Bourne et prend donc en charge le code intégré exec avec ces sémantiques, vous ne devriez généralement pas essayer d'éviter d'utiliser sh -c (ou équivalent) pour créer un nouveau processus Shell séparé à cet effet, car:

  • Une fois que le Shell est devenu myCommand, il n'y a plus de Shell en attente pour exécuter les commandes suivantes. sh -c 'echo $$; exec myCommand; foo ne pourrait pas essayer d'exécuter foo après s'être remplacé par myCommand. À moins que vous n'écriviez un script qui exécute ceci comme sa dernière commande, vous ne pouvez pas simplement utiliser echo $$; exec myCommand dans un shell où vous exécutez d'autres commandes.
  • Vous ne pouvez pas utiliser un sous-shell pour cela. (echo $$; exec myCommand) peut être syntaxiquement plus agréable que sh -c 'echo $$; exec myCommand', mais lorsque vous exécutez $$ à l'intérieur (), il donne le PID du shell parent, pas du sous-shell lui-même. Mais c'est le PID du sous-shell qui sera le PID de la nouvelle commande. Certains shells fournissent leurs propres mécanismes non portables pour trouver le PID du sous-shell, que vous pourriez utiliser pour cela. En particulier, dans Bash 4 , (echo $BASHPID; exec myCommand) fonctionne.

Enfin, notez que certains shells effectueront une optimisation où ils exécutent une commande comme si par exec (c'est-à-dire qu'ils renoncent d'abord à la fourche) quand on sait que le Shell n'aura pas besoin de faites quoi que ce soit après. Certains shells essaient de le faire chaque fois que c'est la dernière commande à exécuter, tandis que d'autres ne le feront que lorsqu'il n'y aura pas d'autres commandes avant ou après la commande, et d'autres ne le feront pas du tout. L'effet est que si vous oubliez d'écrire exec et utilisez simplement sh -c 'echo $$; myCommand' alors il parfois vous donnera le bon PID sur certains systèmes avec quelques coquilles . Je déconseille de toujours compter sur n tel comportement , et à la place, toujours inclure exec quand c'est ce dont vous avez besoin.

24
Eliah Kagan

Je ne connais pas de solution plus simple, mais n'utilise pas $! assez bien? Vous pouvez toujours affecter la valeur à une autre variable si vous en avez besoin plus tard, comme l'ont dit d'autres.

En guise de remarque, au lieu de canaliser à partir de ps, vous pouvez utiliser pgrep ou pidof.

7
carlpett

utilisez exec à partir d'un script bash après avoir enregistré le pid dans un fichier:

exemple:

supposons que vous ayez un script nommé "forever.sh" que vous voulez exécuter avec args p1, p2, p3

forever.sh sourcecode:

#!/bin/sh

while [ 1 -lt 2 ] ; do
    logger "$0 running with parameters \"$@\""
    sleep 5
done

créer un reaper.sh:

#!/bin/sh

echo $$ > /var/run/$1.pid
exec "$@"

exécutez forever.sh via reaper.sh:

./reaper.sh ./forever.sh p1 p2 p3 p4 &

forever.sh ne fait rien de plus que d'enregistrer une ligne dans syslog toutes les 5 secondes

vous avez maintenant le pid dans /var/run/forever.sh.pid

cat /var/run/forever.sh.pid 
5780

et forever.sh exécute aok. grep syslog:

Nov 24 16:07:17 pinkpony cia: ./forever.sh running with parameters "p1 p2 p3 p4"

vous pouvez le voir dans la table de processus:

ps axuwww|grep 'forever.sh p1' |grep -v grep
root      5780  0.0  0.0   4148   624 pts/7    S    16:07   0:00 /bin/sh ./forever.sh p1 p2 p3 p4
5
user237419

Dans le shell bash, une alternative à $! pourrait être le jobs -p intégré. Dans certains cas, le ! dans $! est interprété par le shell avant (ou au lieu de) l'expansion de variable, ce qui conduit à des résultats inattendus.

Cela, par exemple, ne fonctionnera pas:

((yourcommand) & echo $! >/var/run/pidfile)

alors que cela:

((yourcommand) & jobs -p >/var/run/pidfile)
3
mustaccio

Ceci est un peu une réponse bidouille et ne fonctionnera probablement pas pour la plupart des gens. C'est aussi un énorme risque pour la sécurité, alors ne le faites pas à moins d'être sûr que vous serez en sécurité et que les entrées soient désinfectées et ... eh bien, vous avez l'idée.

Compilez le petit programme C ici dans un binaire appelé start (ou ce que vous voulez), puis exécutez votre programme en tant que ./start your-program-here arg0 arg1 arg2 ...

#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <unistd.h>

int main(int argc, char **argv)
{
    if (argc >= 2)
    {
        printf("%lu\n", (long unsigned) getpid());
        if (execvp(argv[1], &argv[1]) < 0)
        {
            perror(NULL);
            return 127;
        }
    }
    return 0;
}

Pour faire court, cela imprimera le PID dans stdout, puis chargera votre programme dans le processus. Il devrait toujours avoir le même PID.

1
tonysdg

Vous pouvez utiliser quelque chose comme:

$ myCommand ; pid=$!

Ou

$ myCommand && pid=$!

Les deux commandes peuvent être des liaisons utilisant ; ou &&. Dans le second cas, le pid ne sera défini que si la première commande réussit. Vous pouvez obtenir l'ID de processus à partir de $pid.

1
Khaled