Ich möchte den Prozess starten (zB myCommand) und seine PID erhalten (um ihn später töten zu können).
Ich habe ps ausprobiert und nach Namen gefiltert, aber ich kann den Prozess nicht nach Namen unterscheiden
myCommand
ps ux | awk '/<myCommand>/ {print $2}'
Weil Prozessnamen nicht eindeutig sind.
Ich kann den Prozess ausführen durch:
myCommand &
Ich habe festgestellt, dass ich diese PID erhalten kann durch:
echo $!
Gibt es eine einfachere Lösung?
Ich würde gerne myCommand ausführen und seine PID als Ergebnis eines einzeiligen Befehls erhalten.
myprogram
wäre&
wie in der vorherigen Zeile starten müssen , andernfalls wird das Echo im Grunde leer zurückgegeben.command & echo $!
die Ausführung in diesem Schritt eingefroren :(Schließen Sie den Befehl in ein kleines Skript ein
quelle
Sie können
sh -c
und verwendenexec
, um die PID des Befehls zu ermitteln, noch bevor dieser ausgeführt wird.Zum Starten
myCommand
, damit die PID gedruckt wird, bevor die Ausführung beginnt, können Sie Folgendes verwenden:Wie es funktioniert:
Dies startet eine neue Shell, gibt die PID dieser Shell aus und ersetzt die Shell mit dem
exec
eingebauten Befehl, um sicherzustellen, dass sie dieselbe PID hat. Wenn Ihre Shell einen Befehl mit der eingebauten Funktion ausführt, wird Ihre Shell tatsächlich zu diesem Befehl und nicht zu dem häufigeren Verhalten, eine neue Kopie von sich selbst zu erstellen, die eine eigene separate PID hat und dann zum Befehl wird.exec
Ich finde das viel einfacher als Alternativen, die asynchrone Ausführung (mit
&
), Jobsteuerung oder Suche mit beinhaltenps
. Diese Ansätze sind in Ordnung, aber es sei denn, Sie haben einen bestimmten Grund, sie zu verwenden. Beispielsweise wird der Befehl bereits ausgeführt. In diesem Fall ist es sinnvoll, nach seiner PID zu suchen oder die Jobsteuerung zu verwenden. (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önnten gelegentlich weggelassen werden, aber normalerweise nicht.
Auch wenn die von Ihnen verwendete Shell einen Bourne-Stil hat und daher die
exec
integrierte Semantik unterstützt, sollten Sie im Allgemeinen nicht versuchen, die Verwendungsh -c
(oder eine gleichwertige Methode ) zum Erstellen eines neuen, separaten Shell-Prozesses für diesen Zweck zu vermeiden , da:myCommand
, gibt es keine Shell, die darauf wartet, nachfolgende Befehle auszuführen.sh -c 'echo $$; exec myCommand; foo
wäre nicht in der Lage zu versuchen,foo
nach dem Ersetzen durchmyCommand
. Wenn Sie kein Skript schreiben, das dieses als letzten Befehl ausführt, können Sie es nicht einfachecho $$; exec myCommand
in einer Shell verwenden, in der Sie andere Befehle ausführen.(echo $$; exec myCommand)
kann syntaktisch besser sein alssh -c 'echo $$; exec myCommand'
, aber wenn Sie$$
innerhalb ausführen(
)
, gibt es die PID der übergeordneten Shell, nicht der Subshell selbst. Es ist jedoch die PID der Subshell, die die PID des neuen Befehls ist. Einige Schalen bieten ihre eigenen , nicht tragbaren Mechanismen für die Subshell PID zu finden, die Sie könnten für diese. Insbesondere in Bash 4 ,(echo $BASHPID; exec myCommand)
funktioniert.Beachten Sie schließlich, dass einige Shells eine Optimierung ausführen, bei der sie einen Befehl ausführen, als ob
exec
sie dies tun (dh zuerst auf das Forken verzichten), wenn bekannt ist, dass die Shell danach nichts mehr tun muss. Einige Shells versuchen dies immer dann, wenn es sich um den letzten auszuführenden Befehl handelt, 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 , wenn Ihr vergessen zu schreibenexec
und einfach zu verwenden ,sh -c 'echo $$; myCommand'
dann wird manchmal Sie die richtige PID geben auf einigen Systemen mit einigen Muscheln. Ich rate davon ab, sich jemals auf ein solches Verhalten zu verlassen und stattdessen immerexec
anzugeben, wann Sie dies benötigen.quelle
myCommand
, muss ich in meinem Bash-Skript eine Reihe von Umgebungsvariablen festlegen. Übertragen diese in die Umgebung, in der derexec
Befehl ausgeführt wird?exec
Befehl übertragen. Dieser Ansatz funktioniert jedoch nicht, wennmyCommand
andere Prozesse gestartet werden, mit denen Sie arbeiten müssen. wenn ich eine Ausgabe vonkill -INT <pid>
wopid
erhält auf diese Weise, wird das Signal nicht die Teilprozesse erreicht gestartet durchmyCommand
, während , wenn ich laufemyCommand
in der aktuellen Sitzung und Strg + C, die Signale richtig ausbreiten.sh -c 'echo $$; exec /usr/local/bin/mbdyn -f "input.file" -o "/path/to/outputdir" > "command_output.txt" 2>&1 &'
Ich kenne keine einfachere Lösung, verwende aber nicht $! gut genug? Sie können den Wert immer einer anderen Variablen zuweisen, wenn Sie ihn später benötigen, wie von anderen gesagt.
Als Randnotiz, anstatt von ps zu leiten, könnten Sie
pgrep
oder verwendenpidof
.quelle
benutze exec aus einem Bash-Skript, nachdem du die PID in einer Datei registriert hast:
Beispiel:
Angenommen, Sie haben ein Skript mit dem Namen "forever.sh", das Sie mit den Argumenten p1, p2, p3 ausführen möchten
forever.sh Quellcode:
erstelle eine reaper.sh:
Laufen Sie forever.sh durch reaper.sh:
forever.sh protokolliert lediglich alle 5 Sekunden eine Zeile in syslog
Sie haben jetzt die PID in /var/run/forever.sh.pid
und forever.sh rennt aok. Syslog grep:
Sie können es in der Prozesstabelle sehen:
quelle
exec "$@"
anstelle von verwendenexec $*
. Technisch gesehen müssen Sie nicht das Leerzeichen, sondern das Vorkommen der Zeichen im IFS-Shell-Parameter (standardmäßig Leerzeichen, Tabulator und Zeilenvorschub) beibehalten.In der Bash-Shell könnte eine Alternative
$!
diejobs -p
eingebaute sein. In einigen Fällen wird das!
In$!
von der Shell vor (oder anstelle von) der Variablenexpansion interpretiert, was zu unerwarteten Ergebnissen führt.Das funktioniert zum Beispiel nicht:
während dies wird:
quelle
Sie können Folgendes verwenden:
Oder
Die beiden Befehle können Gelenke mit
;
oder sein&&
. Im zweiten Fall wird die pid nur gesetzt, wenn der erste Befehl erfolgreich ist. Sie können die Prozess-ID von erhalten$pid
.quelle
$!
nach&&
oder referenzieren;
, erhalten Sie niemals die PID des Prozesses, der für die linke Seite des Befehlstrennzeichens gestartet wurde.$!
wird nur für asynchron gestartete Prozesse gesetzt (zB normalerweise mit,&
aber einige Shells haben auch andere Methoden).Dies ist eine knifflige Antwort und wird wahrscheinlich für die meisten Leute nicht funktionieren. Es ist auch ein riesiges Sicherheitsrisiko, machen Sie es also nur, wenn Sie sicher sind, dass Sie sicher sind und die Eingaben bereinigt sind, und ... Sie haben die Idee.
Kompilieren Sie das kleine C-Programm hier in eine aufgerufene Binärdatei
start
(oder was auch immer Sie wollen), und führen Sie Ihr Programm als aus./start your-program-here arg0 arg1 arg2 ...
Kurz gesagt, dies gibt die PID aus
stdout
und lädt dann Ihr Programm in den Prozess. Es sollte immer noch die gleiche PID haben.quelle
stdout
scheint in diesem Beispiel nicht aufgezeichnet zu werden:RESULT="$(./start_and_get_pid.out echo yo)"; echo "$RESULT"
sleep 10 & PID_IS=$!; echo $PID_IS