Lösung 1:
Was kann einfacher sein als echo $!
? Als eine Zeile:
myCommand & echo $!
Lösung 2:
Sie können sh -c
verwenden und exec
um die PID des Befehls noch vorher zu erhalten es läuft.
Um myCommand
zu starten , damit seine PID gedruckt wird, bevor es zu laufen beginnt, können Sie verwenden:
sh -c 'echo $$; exec myCommand'
Wie es funktioniert:
Dies startet eine neue Shell, gibt die PID dieser Shell aus und verwendet dann den exec
eingebaut, um zu ersetzen die Shell mit Ihrem Befehl und stellen Sie sicher, dass sie dieselbe PID hat. Wenn Ihre Shell einen Befehl mit dem exec
ausführt builtin, Ihre Shell wird tatsächlich werden diesen Befehl, anstatt das üblichere Verhalten, eine neue Kopie von sich selbst zu forken, die ihre eigene separate PID hat und die dann zum Befehl wird.
Ich finde das viel einfacher als Alternativen mit asynchroner Ausführung (mit &
), Auftragssteuerung oder Suche mit ps
. Diese Ansätze sind in Ordnung, aber es sei denn, Sie haben einen bestimmten Grund, sie zu verwenden - beispielsweise wird der Befehl möglicherweise bereits ausgeführt, in diesem Fall wäre die Suche nach seiner PID oder die Verwendung der Jobsteuerung sinnvoll -, schlage ich vor, zuerst diesen Weg in Betracht zu ziehen. (Und ich würde sicherlich nicht in Betracht ziehen, ein komplexes Skript oder ein anderes Programm zu schreiben, um dies zu erreichen).
Diese Antwort enthält ein Beispiel für diese Technik.
Teile dieses Befehls können gelegentlich weggelassen werden, aber normalerweise nicht.
Auch wenn die von Ihnen verwendete Shell im Bourne-Stil ist und daher die exec
unterstützt Mit dieser Semantik eingebaut, sollten Sie im Allgemeinen nicht versuchen, die Verwendung von sh -c
zu vermeiden (oder gleichwertig), um eine neue, separate zu erstellen Shell-Prozess für diesen Zweck, denn:
- Sobald die Shell zu
myCommand
geworden ist , gibt es keine Shell, die darauf wartet, nachfolgende Befehle auszuführen.sh -c 'echo $$; exec myCommand; foo
nicht versuchen könnte,foo
auszuführen nachdem es sich selbst durchmyCommand
ersetzt hat . Sofern Sie kein Skript schreiben, das dies als letzten Befehl ausführt, können Sie nicht einfachecho $$; exec myCommand
verwenden in einer Shell, in der Sie andere Befehle ausführen. - Sie können dafür keine Subshell verwenden.
(echo $$; exec myCommand)
kann syntaktisch schöner sein alssh -c 'echo $$; exec myCommand'
, aber wenn Sie$$
ausführen innerhalb von(
)
, gibt es die PID der übergeordneten Shell an, nicht der Subshell selbst. Aber es ist die PID der Subshell, die die PID des neuen Befehls sein wird. Einige Shells bieten ihre eigenen nicht-portablen Mechanismen, um die PID der Subshell zu finden, was Sie könnten dafür verwenden. Insbesondere in Bash 4,(echo $BASHPID; exec myCommand)
funktioniert.
Beachten Sie schließlich, dass einige Shells eine Optimierung durchführen, bei der sie einen Befehl wie von exec
ausführen (d.h. sie verzichten zuerst auf das Forken), wenn bekannt ist, dass die Shell danach nichts tun muss. Einige Shells versuchen dies immer dann zu tun, wenn es der letzte auszuführende Befehl ist, während andere dies nur tun, wenn vor oder nach dem Befehl keine anderen Befehle vorhanden sind, und andere dies überhaupt nicht tun. Der Effekt ist, dass Sie vergessen, exec
zu schreiben und verwenden Sie einfach sh -c 'echo $$; myCommand'
dann wird es manchmal geben Ihnen die richtige PID für einige Systeme mit einigen Muscheln. Ich rate davon ab, sich jemals auf ein solches Verhalten zu verlassen und stattdessen immer exec
einzufügen wenn Sie das brauchen.
Lösung 3:
Verpacken Sie den Befehl in ein kleines Skript
#!/bin/bash
yourcommand &
echo $! >/path/to/pid.file
Lösung 4:
Ich kenne keine einfachere Lösung, aber ich verwende kein $! gut genug? Sie können den Wert jederzeit einer anderen Variablen zuweisen, wenn Sie ihn später benötigen, wie andere sagten.
Als Randbemerkung, anstatt von ps zu pipen, könnten Sie pgrep
verwenden oder pidof
.
Lösung 5:
Verwenden Sie exec aus einem Bash-Skript, nachdem Sie die PID in einer Datei registriert haben:
Beispiel:
Angenommen, Sie haben ein Skript namens "forever.sh", das Sie mit den Argumenten p1,p2,p3
ausführen möchtenQuellcode für forever.sh:
#!/bin/sh
while [ 1 -lt 2 ] ; do
logger "$0 running with parameters \"[email protected]\""
sleep 5
done
erstelle eine reaper.sh:
#!/bin/sh
echo $$ > /var/run/$1.pid
exec "[email protected]"
Führen Sie forever.sh bis reaper.sh aus:
./reaper.sh ./forever.sh p1 p2 p3 p4 &
forever.sh tut nichts anderes, als alle 5 Sekunden eine Zeile im Syslog zu protokollieren
Sie haben jetzt die PID in /var/run/forever.sh.pid
cat /var/run/forever.sh.pid
5780
und forever.sh läuft einwandfrei. syslog grep:
Nov 24 16:07:17 pinkpony cia: ./forever.sh running with parameters "p1 p2 p3 p4"
Sie können es in der Prozesstabelle sehen:
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