Wie starte ich einen Prozess im angehaltenen Zustand unter Linux?

19

Praktisch brauche ich einen Prozess, der sich so verhält, als hätte ich Ctrl+Zgleich nach dem Start gedrückt .

Hoffentlich ist es möglich, so etwas mit einem Shell-Skript zu machen.

(Außerdem wäre es großartig, die resultierende PID zu kennen, damit ich den Prozess anschließend fortsetzen kann.)

java.ist.für.desktop
quelle

Antworten:

7

Nachdem Sie einen Prozess gestartet haben, können Sie ihn an SIGSTOP senden, um ihn anzuhalten. Senden Sie SIGCONT, um den Vorgang fortzusetzen. Ich denke, dass dieses kleine Skript Ihnen helfen kann

#!/bin/bash
$@ &
PID=$!
kill -STOP $PID
echo $PID
wait $PID

Es führt process aus (Befehl send as parameter), setzt es aus, gibt die Prozess-ID aus und wartet, bis es endet.

strahlend
quelle
1
Ich habe es geändert, um am Ende fortzufahren: [enter] #!/bin/bash [enter] $@ & [enter] PID=$! [enter kill -STOP $PID ] echo "Suspended: $PID, press ENTER to continue it" [enter] read [enter] kill -CONT $PID [enter] wait $PID [enter]echo
java.is.for.desktop
7
Damit Sie wissen, wird der Unterprozess möglicherweise beendet, bevor Sie überhaupt die Möglichkeit haben, das STOP-Signal an ihn zu senden.
MikeyB
16
Ein weiterer Tag bei den Rennen.
Strg-Alt-Delor
23

Aus welcher Umgebung erstellen Sie den Prozess?

Wenn Sie dies in einer Umgebung wie C-Code tun, können Sie fork () ausführen und anschließend im untergeordneten Element ein SIGSTOP vor exec () an sich selbst senden, um die weitere Ausführung zu verhindern.

Eine allgemeinere Lösung (wahrscheinlich die beste) wäre, einen Stub zu erstellen, der dies tut. Das Stub-Programm würde also:

  • Nehmen Sie Argumente, die aus dem Namen und den Argumenten des realen Programms bestehen
  • Sende einen SIGSTOP an sich selbst
  • exec () das echte Programm mit entsprechenden Argumenten

Dies stellt sicher, dass Sie vermeiden, dass Rennbedingungen, die mit der neuen Verarbeitung zusammenhängen, zu weit gehen, bevor Sie ein Signal an sie senden können.


Ein Beispiel für die Shell:

#!/bin/bash
kill -STOP $$
exec "$@"

Und obige Codez verwenden:

michael@challenger:~$ ./stopcall.sh ls -al stopcall.sh

[1]+  Stopped                 ./stopcall.sh ls -al stopcall.sh
michael@challenger:~$ jobs -l
[1]+ 23143 Stopped (signal)        ./stopcall.sh ls -al stopcall.sh
michael@challenger:~$ kill -CONT 23143; sleep 1
-rwxr-xr-x 1 michael users 36 2011-07-24 22:48 stopcall.sh
[1]+  Done                    ./stopcall.sh ls -al stopcall.sh
michael@challenger:~$ 

Das jobs -lzeigt die PID. Wenn Sie dies jedoch aus einer Shell heraus tun, benötigen Sie die PID nicht direkt. Sie können einfach Folgendes tun: kill -CONT %1(vorausgesetzt, Sie haben nur einen Job).

Machst du es mit mehr als einem Job? Links als Übung für den Leser :)

MikeyB
quelle
Ich hatte gehofft, dies von einem Shell-Skript aus zu tun ...
java.is.for.desktop
Großartig. Da Sie dies über ein Shell-Skript tun möchten, verwenden Sie das Stub-Programm.
MikeyB
20

MikeyBs Antwort ist richtig. Von dieser Frage auf Superuser, hier ist eine prägnante Version:

( kill -SIGSTOP $BASHPID; exec my_command ) &

Um dies zu verstehen, muss man verstehen, wie Prozesse unter Unix gestartet werden: Der execSystemaufruf ersetzt das aktuell ausgeführte Programm durch ein neues , wobei die vorhandene PID erhalten bleibt. So die Art und Weise ein unabhängiger Prozess erstellt wird , ist zuerst fork, und dann exec, das laufende Programm in dem untergeordneten Prozess mit dem gewünschten Programm zu ersetzen.

Die Bestandteile dieses Shell-Befehls sind:

  1. Die Klammern (...)starten eine Sub-Shell: eine weitere Instanz von BASH.
  2. Der killBefehl sendet das STOP-Signal an diesen Prozess, wodurch er in den angehaltenen Zustand versetzt wird.
  3. Sobald Sie den Vorgang fortsetzen lassen (indem Sie ihm das CONTSignal senden), wird es durch den execBefehl veranlasst , sich durch Ihr gewünschtes Programm zu ersetzen . my_commandbehält die ursprüngliche PID der Unterschale bei.
  4. Sie können die $!Variable verwenden, um die PID des Prozesses abzurufen.
Nibot
quelle
2
Ich mag dieses, da es grundsätzlich korrekt ist (nur, dass ich es -s STOPanstelle von verwenden musste -SIGSTOP). Immer noch wundern: warum muss es $BASHPIDstatt sein $$? (Ich kann den Unterschied nicht wirklich verstehen).
Hibou57
1
Für $$vs $BASHPIDüberprüfe ich, ob letzteres die PID der Unterschale ist, während erstere nicht. Es gibt ein lustiges Problem: Das Anwenden des Trinkgeldes in einem Bash-Skript schlägt meistens fehl und ich muss Folgendes tun: PID=$!; ps -p $PID; kill -s CONT $PID;… es schlägt fehl, wenn ich den ps -p $PIDTeil entferne : Der Prozess scheint irgendwo ohne Fehlermeldung zu verschwinden (getötet?) . Von einer interaktiven Shell aus ist es in Ordnung, das Problem liegt nur im Skript. Das ist zu mysteriös.
Hibou57
Ich habe versucht, diese Lösung zum Auflisten der Dateideskriptoren von my_command zu verwenden. ( goo.gl/cNbUE8 ) aber die Deskriptoren sind immer noch die gleichen, egal was my_command ist.
rasty.g
Optionen zum Ersetzen $BASHPIDvon anderen Muscheln als Bash finden Sie hier
Jakob