it-swarm.com.de

Wie kann ich einen neuen Prozess starten, der KEIN Kind des ursprünglichen Prozesses ist?

(OSX 10.7) In einer von uns verwendeten Anwendung können Sie Skripts zuweisen, die aufgerufen werden, wenn bestimmte Aktivitäten in der Anwendung ausgeführt werden. Ich habe ein Bash-Skript zugewiesen, das gerade aufgerufen wird. Das Problem ist, dass ich nur ein paar Befehle ausführen muss, 30 Sekunden warten und dann einige weitere Befehle ausführen muss. Wenn ich mein Bash-Skript "sleep 30" machen lasse, friert die gesamte Anwendung für diese 30 Sekunden ein, während sie darauf wartet, dass mein Skript beendet wird.

Ich habe versucht, die Wartezeit von 30 Sekunden (und den zweiten Satz von Befehlen) in ein separates Skript zu schreiben und "./secondScript &" aufzurufen, aber die Anwendung bleibt 30 Sekunden lang dort und tut nichts. Ich gehe davon aus, dass die Anwendung darauf wartet, dass das Skript und alle untergeordneten Prozesse beendet werden.

Ich habe diese Varianten ausprobiert, um das zweite Skript aus dem Hauptskript heraus aufzurufen. Sie haben alle das gleiche Problem:

  • Nohup ./secondScript &
  • ((./secondScript &) &)
  • (./secondScript &)
  • Nohup-Skript -q/dev/null secondScript &

Ich kann die Anwendung nicht ändern und anweisen, mein Skript zu starten und nicht auf den Abschluss zu warten.

Wie kann ich einen Prozess starten (ich würde es vorziehen, dass der Prozess in einer Skriptsprache ausgeführt wird), sodass der neue Prozess kein untergeordnetes Element des aktuellen Prozesses ist?

Danke, Chris

p.s. Ich habe den Befehl "disown" ausprobiert und es hat auch nicht geholfen. Mein Hauptskript sieht so aus:

[initial commands]
echo Launching second script
./secondScript &
echo Looking for jobs
jobs
echo Sleeping for 1 second
sleep 1
echo Calling disown
disown
echo Looking again for jobs
jobs
echo Main script complete

und was ich für die Ausgabe bekomme, ist Folgendes:

Launching second script
Looking for jobs
[1]+ Running ./secondScript &
Sleeping for 1 second
Calling disown
Looking again for jobs
Main script complete

und zu diesem Zeitpunkt wartet die aufrufende Anwendung 45 Sekunden lang darauf, dass secondScript beendet wird.

p.p.s

Wenn ich oben im Hauptskript "ps" ausführe, wird nur die Prozess-ID der interaktiven Bash-Sitzung zurückgegeben, die ich in einem separaten Terminalfenster geöffnet habe.

Der Wert von $ Shell ist/bin/bash

Wenn ich "ps -p $$" ausführe, wird mir dies korrekt mitgeteilt

PID   TTY TIME    CMD
26884 ??  0:00.00 mainScript

Wenn ich "lsof -p $$" ausführe, erhalte ich alle möglichen Ergebnisse (ich habe hier nicht alle Spalten eingefügt, sofern sie nicht relevant sind):

FD   TYPE   NAME
cwd  DIR    /private/tmp/blahblahblah
txt  REG    /bin/bash
txt  REG    /usr/lib/dyld
txt  REG    /private/var/db/dyld/dyld_shared_cache_x86_64
0    PIPE   
1    PIPE   -> 0xffff8041ea2d10
2    PIPE   -> 0xffff 8017d21cb
3r   DIR    /private/tmp/blahblah
4r   REG    /Volumes/DATA/blahblah
255r REG    /Volumes/DATA/blahblah
17
Betty Crokker

Die typische Methode, um dies unter Unix zu tun, ist die doppelte Gabelung. In Bash können Sie dies mit tun

( sleep 30 & )

(..) erstellt einen untergeordneten Prozess und & erstellt einen Enkelprozess. Wenn der Kindprozess stirbt, wird der Enkelprozess von init geerbt. 


Wenn dies nicht funktioniert, wartet Ihre Anwendung nicht auf untergeordnete Prozesse. 

Andere Dinge, auf die es möglicherweise wartet, sind die Sitzung und die geöffneten Sperrdateien:

Um eine neue Sitzung zu erstellen, verfügt Linux über eine setsid. Unter OS X können Sie dies möglicherweise über script durchführen, wodurch übrigens auch eine neue Sitzung erstellt wird:

# Linux:
setsid sleep 30

# OS X:
Nohup script -q -c 'sleep 30' /dev/null &

Um eine Liste der geerbten Dateideskriptoren zu finden, können Sie lsof -p yourpid verwenden, was etwa Folgendes ausgibt:

sleep   22479 user    0u   CHR 136,32      0t0       35 /dev/pts/32
sleep   22479 user    1u   CHR 136,32      0t0       35 /dev/pts/32
sleep   22479 user    2u   CHR 136,32      0t0       35 /dev/pts/32
sleep   22479 user    5w   REG  252,0        0  1048806 /tmp/lockfile

In diesem Fall haben Sie zusätzlich zu den Standard-FDs 0, 1 und 2 auch eine fd 5 mit einer Sperrdatei geöffnet, auf die das übergeordnete Element warten kann. 

Um fd 5 zu schließen, können Sie exec 5>&- verwenden. Wenn Sie der Meinung sind, dass die Sperrdatei selbst stdin/stdout/stderr sein könnte, können Sie Nohup verwenden, um sie auf etwas anderes umzuleiten.

23
that other guy

Ich denke, es hängt davon ab, wie Ihr übergeordneter Prozess versucht zu erkennen, ob Ihr untergeordneter Prozess abgeschlossen ist. In meinem Fall (mein übergeordneter Prozess war gnu make), schließe ich stdout und stderr ab (etwas basierend auf dem Antwort von diesem anderen Typ ) wie folgt:

sleep 30 >&- 2>&- &

Sie könnten auch stdin schließen

sleep 30 <&- >&- 2>&- &

oder zusätzlich Ihren Kindprozess ablehnen (nicht für Mac)

sleep 30 <&- >&- 2>&- & disown

Derzeit nur in bash auf kubuntu 14.04 und Mac OSX getestet.

11
Joe

Eine andere Möglichkeit besteht darin, das Kind zu verlassen

#!/bin/bash

yourprocess &

disown

Soweit ich weiß, ersetzt die Anwendung die normale Bash-Shell, da sie immer noch auf den Abschluss eines Prozesses wartet, selbst wenn init sich um diesen untergeordneten Prozess gekümmert hätte. Es könnte sich um die " Anwendung handeln "fängt die Orphan-Behandlung ab, die normalerweise von init ausgeführt wird.

In diesem Fall kann nur ein paralleler Prozess mit einigen IPC eine Lösung bieten (siehe meine andere Antwort).

11
thom

Wenn alle Stricke reißen:

  1. Erstellen Sie eine Named Pipe

  2. starten Sie das "langsame" Skript unabhängig aus dem " application ". Stellen Sie sicher, dass die Task in einer Endlosschleife ausgeführt wird, beginnend mit dem Lesen aus der Pipe. Es wird Leseblockiert, wenn es zu lesen versucht.

  3. starten Sie in der Anwendung Ihr anderes Skript. Wenn das "langsame" Skript aufgerufen werden muss, schreiben Sie einfach einige Daten in die Pipe. Das langsame Skript startet unabhängig, damit das Skript nicht auf das "langsame" Skript wartet, um zu beenden.

Um die Frage zu beantworten:
bash - wie kann ich einen neuen Prozess starten, der KEIN Kind des ursprünglichen Prozesses ist?

Einfach: Starten Sie es nicht, sondern lassen Sie es von einer unabhängigen Entität während des Startvorgangs starten ... wie init oder im laufenden Betrieb mit dem Befehl at oder batch

1
thom

Hier habe ich eine Muschel

└─bash(13882)

Wo ich einen Prozess wie diesen beginne:

$ (urxvt -e ssh somehost&)

Ich bekomme einen Prozessbaum (diese Ausgabe wurde aus pstree -p geschnitten):

├─urxvt(14181)───ssh(14182)

wo der Prozess unter pid 1 (in meinem Fall systemd) untergeordnet ist.

Hätte ich dies jedoch getan (beachten Sie, wo der & ist):

$ (urxvt -e ssh somehost)&

dann wäre der Prozess ein Kind der Shell:

└─bash(13882)───urxvt(14181)───ssh(14182)

In beiden Fällen wird die Shell-Eingabeaufforderung sofort zurückgegeben, und ich kann exit , Ohne den Prozessbaum zu beenden, den ich oben gestartet habe.

Im letzteren Fall wird der Prozessbaum unterhalb von pid 1 wiederhergestellt, wenn Die Shell verlässt, so dass er wie im ersten Beispiel endet.

├─urxvt(14181)───ssh(14182)

In jedem Fall ist das Ergebnis ein Prozessbaum, der die Shell überlebt. Der einzige Unterschied zwischen Ist die anfängliche Erziehung dieses Prozessbaums.

Als Referenz können Sie auch verwenden

  • Nohup urxvt -e ssh somehost &
  • urxvt -e ssh somehost & disown $!

Beide geben denselben Prozessbaum wie das zweite Beispiel oben.

└─bash(13882)───urxvt(14181)───ssh(14182)

Wenn die Shell beendet ist, wird der Prozessbaum wie zuvor in In pid 1 umbenannt.

Nohup leitet die Standardausgabe des Prozesses zusätzlich in eine Datei Nohup.out um. Wenn dies eine nützliche Eigenschaft ist, kann dies eine nützlichere Wahl sein.

Andernfalls haben Sie mit dem ersten Formular sofort einen vollständig Separaten Prozessbaum.

0
starfry