Solution 1 :
Quoi de plus simple que echo $!
? En une seule ligne :
myCommand & echo $!
Solution 2 :
Vous pouvez utiliser sh -c
et exec
pour obtenir le PID de la commande même avant ça marche.
Pour commencer myCommand
, afin que son PID soit imprimé avant qu'il ne commence à s'exécuter, vous pouvez utiliser :
sh -c 'echo $$; exec myCommand'
Comment ça marche :
Cela démarre un nouveau shell, imprime le PID de ce shell, puis utilise le exec
intégré pour remplacer le shell avec votre commande, en vous assurant qu'il a le même PID. Lorsque votre shell exécute une commande avec le exec
intégré, votre shell est en train de devenir cette commande, plutôt que le comportement plus courant consistant à forker une nouvelle copie d'elle-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 tâches ou la recherche avec ps
. Ces approches sont correctes, mais à moins que vous n'ayez une raison spécifique de les utiliser - par exemple, peut-être que la commande est déjà en cours d'exécution, auquel cas la recherche de son PID ou l'utilisation du contrôle des tâches aurait du sens - je suggère de considérer 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.
Des parties de cette commande peuvent parfois être omises, mais pas généralement.
Même si le shell que vous utilisez est de style Bourne et prend donc en charge le exec
intégré avec cette sémantique, vous ne devriez généralement pas essayer d'éviter d'utiliser sh -c
(ou équivalent) pour créer un nouveau, séparé processus shell à cette fin, car :
- Une fois que le shell est devenu
myCommand
, aucun shell n'attend pour exécuter les commandes suivantes.sh -c 'echo $$; exec myCommand; foo
ne serait pas en mesure d'essayer d'exécuterfoo
après s'être remplacé parmyCommand
. À moins que vous n'écriviez un script qui l'exécute comme sa dernière commande, vous ne pouvez pas simplement utiliserecho $$; 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 quesh -c 'echo $$; exec myCommand'
, mais lorsque vous exécutez$$
à l'intérieur de(
)
, 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, ce 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écuteront une commande comme si par exec
(c'est-à-dire qu'ils renoncent à bifurquer en premier) quand on sait que le shell n'aura plus rien à faire par la suite. 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 a 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 ça va parfois vous donner le bon PID sur certains systèmes avec certains coquilles. Je recommande de ne jamais compter sur un tel comportement, et à la place de toujours inclure exec
quand c'est ce dont vous avez besoin.
Solution 3 :
Enveloppez la commande dans un petit script
#!/bin/bash
yourcommand &
echo $! >/path/to/pid.file
Solution 4 :
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 d'autres l'ont dit.
En remarque, au lieu de passer de ps, vous pouvez utiliser pgrep
ou pidof
.
Solution 5 :
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 souhaitez exécuter avec les arguments p1,p2,p3
code source pour toujours.sh :
#!/bin/sh
while [ 1 -lt 2 ] ; do
logger "$0 running with parameters \"[email protected]\""
sleep 5
done
créez un reaper.sh :
#!/bin/sh
echo $$ > /var/run/$1.pid
exec "[email protected]"
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 fonctionne correctement. grep syslog :
Nov 24 16:07:17 pinkpony cia: ./forever.sh running with parameters "p1 p2 p3 p4"
vous pouvez le voir dans le tableau des 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