Frage Wie man pid des gerade begonnenen Prozesses erhält


Ich möchte den Prozess starten (zB myCommand) und seine PID bekommen (um es später zu beenden).

Ich probierte ps und filtere nach Namen, 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 folgendermaßen ausführen:

myCommand &

Ich habe festgestellt, dass ich diese PID bekommen kann durch:

echo $!

Gibt es eine einfachere Lösung?

Ich würde mich freuen, myCommand auszuführen und seine PID als Ergebnis eines einzigen Befehls zu erhalten.


51
2017-11-24 08:28


Ursprung




Antworten:


Was kann einfacher sein als echo $!? Als eine Zeile:

myCommand & echo $!

61
2017-11-24 08:46



Danke, dass du diese Befehle mit "&" zusammengefügt hast, hat mir sehr geholfen. - rafalmag
In einem Bash-Skript, in einer Schleife, die Programme startet, $! ist nicht genau. Manchmal gibt es pid des Skripts selbst, manchmal von grep oder awk ausführen aus dem Skript eine Lösung, um speziell die PID des gerade gestarteten Prozesses in diesem Szenario zu erhalten? etwas wie pid =myprogram wäre großartig gewesen
Beachten Sie, dass dazu der Befehl mit a gestartet werden muss &wie die vorherige Zeile, sonst wird das Echo grundsätzlich leer zurückgegeben. - rogerdpack
Zuweisung an Variable wie command & echo $! friert die Ausführung bei diesem Schritt ein :( - Shashank Vivek
es rettet mein Leben! Vielen Dank. - temple


Wickeln Sie den Befehl in ein kleines Skript ein

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

21
2017-11-24 08:48





Ich kenne keine einfachere Lösung, aber verwende $ nicht! gut genug? Sie können den Wert immer einer anderen Variablen zuweisen, wenn Sie diese später benötigen.

Als eine Randnotiz, anstelle von Piping von PS könnten Sie verwenden pgrep oder pidof.


7
2017-11-24 14:13





Verwenden Sie nach dem Registrieren der PID in einer Datei exec aus einem Bash-Skript:

Beispiel:

Angenommen, Sie haben ein Skript mit dem Namen "forever.sh", das mit den Argumenten p1, p2, p3 ausgeführt werden soll

forever.sh Quellcode:

#!/bin/sh

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

Erschaffe eine reaper.sh:

#!/bin/sh

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

Führen Sie forever.sh über reaper.sh aus:

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

forever.sh tut nichts mehr, als eine Zeile alle 5 Sekunden in 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 aok. 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

5
2018-03-20 16:58



oh, und der "oneliner": / bin / sh -c 'echo $$> / tmp / mein.pid && exec programm args' & - user237419
Um interne Leerzeichen in den Argumenten richtig zu bewahren, sollten Sie verwenden exec "$@" anstatt exec $*. Was Sie technisch beibehalten müssen, sind keine Leerzeichen, sondern Vorkommen der Zeichen im IFS-Shell-Parameter (standardmäßig Space, Tab und Newline). - Chris Johnsen
Punkt genommen. :) - user237419
Danke, ich wusste nicht, $$ Parameter. Es kann sehr nützlich sein. - rafalmag


Sie können verwenden sh -c und exec um die PID des Befehls gleichmäßig zu bekommen Vor es läuft.

Anfangen myCommandDamit die PID gedruckt wird, bevor sie beginnt, können Sie Folgendes verwenden:

sh -c 'echo $$; exec myCommand'

Wie es funktioniert:

Dies startet eine neue Shell, druckt die PID dieser Shell und verwendet dann die exec eingebaut ersetzen die Shell mit Ihrem Befehl, um sicherzustellen, dass sie die gleiche PID hat. Wenn Ihre Shell einen Befehl mit dem Befehl ausführt exec gebaut, deine Schale ist tatsächlich Werden dieser Befehl, eher, als das häufigere Verhalten eine neue Kopie von sich selbst zu fälschen, die ihre eigene separate PID hat und die dann zum Befehl wird.

Ich finde dies viel einfacher als Alternativen mit asynchroner Ausführung (mit &), Jobkontrolle oder Suche mit ps. Diese Herangehensweisen sind in Ordnung, aber wenn Sie nicht einen bestimmten Grund haben, sie zu verwenden - zum Beispiel, vielleicht läuft der Befehl bereits, in welchem ​​Fall die Suche nach seiner PID oder der Verwendung der Jobsteuerung sinnvoll wäre - schlage ich vor, zuerst diesen Weg zu betrachten. (Und ich würde sicherlich nicht in Erwägung 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 konnten gelegentlich weggelassen werden, aber normalerweise nicht.

Selbst wenn die Shell, die Sie verwenden, ein Bourne-Stil ist und somit unterstützt exec Mit diesen Semantiken sollten Sie nicht versuchen, die Verwendung zu vermeiden sh -c (oder gleichwertig), um ein neues, trennen Shell-Prozess für diesen Zweck, weil:

  • Sobald die Schale geworden ist myCommandEs gibt keine Shell, die darauf wartet, nachfolgende Befehle auszuführen. sh -c 'echo $$; exec myCommand; foo wäre nicht in der Lage zu versuchen, zu laufen foo nachdem er sich selbst ersetzt hat myCommand. Es sei denn, Sie schreiben ein Skript, das dies als seinen letzten Befehl ausführt, können Sie nicht einfach verwenden echo $$; exec myCommand in einer Shell, in der Sie andere Befehle ausführen.
  • Sie können keine verwenden Unterschale dafür. (echo $$; exec myCommand) kann syntaktisch schöner sein als sh -c 'echo $$; exec myCommand'aber wenn du rennst $$ Innerhalb (  ), gibt es die PID der übergeordneten Shell, 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 zum Finden der PID der Subshell, die Sie könnte Verwenden Sie dafür. Im Speziellen, in Bash 4, (echo $BASHPID; exec myCommand) funktioniert.

Beachten Sie schließlich, dass einige Shells eine ausführen Optimierung wo sie einen Befehl ausführen, als ob exec (d. h., sie verzichten zuerst auf das Abzweigen), wenn bekannt ist, dass die Schale danach nichts mehr tun muss. Einige Shells versuchen dies immer dann, wenn der letzte Befehl ausgeführt wird, während andere nur dann ausgeführt werden, wenn vor oder nach dem Befehl keine anderen Befehle vorhanden sind, während andere dies überhaupt nicht tun. Der Effekt ist, dass wenn Sie vergessen zu schreiben exec und benutze es einfach sh -c 'echo $$; myCommand' dann wird es manchmal geben Sie die richtige PID an etwas Systeme mit etwas Muscheln. Ich empfehle, dass man sich niemals darauf verlässt so ein Verhaltenund stattdessen immer inklusive exec wenn du das brauchst.


5
2017-07-19 17:02



Bevor ich rennen kann myCommand, Ich muss eine Anzahl von Umgebungsvariablen in meinem Bash-Skript einstellen. Werden diese auf die Umgebung übertragen, in der die exec Befehl läuft? - user5359531
Sieht so aus, als ob meine Umgebung sich in die Welt überträgt exec Befehl. Dieser Ansatz funktioniert jedoch nicht wann myCommand startet andere Prozesse, mit denen Sie arbeiten müssen; wenn ich a kill -INT <pid> woher pid wurde auf diese Weise erhalten, erreicht das Signal die von ihm begonnenen Teilprozesse nicht myCommandwährend ich laufe myCommand  In der aktuellen Sitzung und Strg + C werden die Signale korrekt weitergeleitet. - user5359531
Ich habe das versucht, aber die PID des myCommand-Prozesses scheint die pid-Ausgabe von echo $$ +1 zu sein. Mache ich etwas falsch? - crobar
Mein Befehl sieht so aus: sh -c 'echo $$; exec /usr/local/bin/mbdyn -f "input.file" -o "/path/to/outputdir" > "command_output.txt" 2>&1 &' - crobar


In der Bash Shell eine Alternative zu $! könnte der sein jobs -p eingebaut. In einigen Fällen ! im $! wird von der Shell vor (oder statt) der Variablenerweiterung interpretiert, was zu unerwarteten Ergebnissen führt.

Dies wird zum Beispiel nicht funktionieren:

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

während dies wird:

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

3
2017-11-24 08:46



Ich denke du meintest ((yourcommand) & jobs -p> / var / run / pidfile). - Dom
@ DominicO'Brien du hast natürlich Recht. Vielen Dank. - mustaccio


Sie können etwas wie verwenden:

$ myCommand ; pid=$!

Oder

$ myCommand && pid=$!

Die beiden Befehle können Gelenke sein mit ; oder &&. Im zweiten Fall wird die PID nur gesetzt, wenn der erste Befehl erfolgreich ist. Sie können die Prozess-ID abrufen $pid.


1
2017-07-26 22:52



OP möchte die PID bekommen, damit er sie später töten kann. ; und && verlangen, dass der ursprüngliche Prozess beendet wird, bevor das Echo $! wird ausgeführt. - Iain
Ja, du hast recht. Dadurch erhalten Sie die PID, nachdem myCommand beendet wurde. - Khaled
Referenzieren $! nach dem && oder ; gibt Ihnen niemals die PID des Prozesses, der für die linke Seite des Befehlstrennzeichens gestartet wurde. $! wird nur für Prozesse festgelegt, die asynchron gestartet werden (z. B. normalerweise mit & aber einige Shells haben auch andere Methoden). - Chris Johnsen
es ist hilfreich, und warum niemand abstimmen außer mir? gute Arbeit obwohl :) - temple


Dies ist ein bisschen eine Hack-Antwort und wird wahrscheinlich nicht für die meisten Menschen funktionieren. Es ist auch ein großes Sicherheitsrisiko, also mach es nicht, wenn du nicht sicher bist, dass du sicher bist und die Eingaben sauber gemacht werden und ... nun, du hast die Idee.

Kompiliere das kleine C-Programm hier in eine binäre namens start (oder was auch immer Sie wollen), dann führen Sie Ihr Programm als ./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;
}

Lange Rede, kurzer Sinn, dies wird die PID drucken stdout, dann laden Sie Ihr Programm in den Prozess. Es sollte immer noch die gleiche PID haben.


1