2014-01-13 3 views
5

Ich bin Debuggen eine Kuriosität mit einem Shell-Skript und fragen, ob ich das falsch verstanden habe, wie Bash „fork“ (&) arbeitet, vielleicht, weil ich es in der Regel über einen Anschluss in einzelnen Befehlen verwenden, zB:Was passiert, wenn ich `&` mit einer Funktion in einem Bash-Skript verwende?

[~me]$ someExecutable & 

nun in einem Shell-Skript:

foo() { 
    echo "logic" 
} 

bar() { 
    echo "idic" 
} 

baz() { 
    echo "katra" 
} 

foo & 
bar 
baz 

Meine Absicht für die Funktion ist foo asynchron aufgerufen werden, und dann für den Rest des Skripts in dem ursprünglichen Prozesskontext weiterzuführen.

Wenn ich dieses Beispiel Skript ausführen ich erhalten die erwartete Ausgabe tun :

logic 
idic 
katra 

(das heißt, nur einzelne offensichtlich Anrufe bar und baz, ich bin überhaupt nicht durch die relative gestört um der drei Zeilen der Ausgabe, die ich kann variieren verstehen)

aber ich sowohl die Ausgabe wird Mißverständnis kann und das Skript selbst. Wenn dem so wäre, würde das sicherlich die Kuriosität erklären, die ich in meinem echten Code sehe, und mich davor bewahren, weiter zu graben.

Ist es möglich, dass das gabelförmige Shell-Skript im untergeordneten Prozess nach dem Aufruf von foo fortgesetzt wird? Bedeutet, dass der Rest meines Shell-Skripts zweimal ausgeführt wird?

Was passiert wirklich, wenn ich & so in einem Bash-Skript verwende?

Antwort

3

Der Ampersand wird Forking nur um den Anruf zu foo() in Ihrem Beispiel. Es ist nicht das gesamte Skript. Nur foo() läuft in einem separaten Thread, der beendet wird, wenn foo() beendet wird. bar() und baz() weiter im selben Thread laufen

+0

Danke - das war es, was ich suchte! –

+4

+1 für die Adressierung des Problems. Quibble: foo() läuft in einer (asynchronen) * Subshell *, was ein separater * Prozess * ist. – mklement0

1

Das Zeichen & weist die Shell an, einen Befehl (oder eine Gruppe von Befehlen) im Hintergrund auszuführen.

Die nächsten Befehle werden sofort ausgeführt.

Es besteht keine Gefahr, das Skript zweimal auszuführen, daher ist es in diesem Zusammenhang anders als C fork().

2

Die & in Bash ist keine Gabel. Es teilt bash mit, den Befehl in einer Subshell zu starten, und fährt fort, nach anderen Befehlen zu suchen (anstatt darauf zu warten, dass dieser Befehl beendet wird).

Daher, wie Sie erwartet haben, führt es 'foo' im Hintergrund und weiterhin den Befehl 'bar' und 'baz' in der Shell der obersten Ebene. Es gab keine Abzweigung der aufrufenden Shell, aber 'foo' wurde im Hintergrund ausgeführt.

So könnte die Ausgabe von "foo" tatsächlich nach bar oder baz passieren, abhängig von ihrem Inhalt .. aber wie es "Echo" verwendet, was eine eingebaute Shell ist, bis der "foo" Hintergrundprozess eingerichtet ist Das "Echo" steht sofort zur Verfügung: Die Chancen stehen also gut, dass Sie die Ausgabe sehen, bevor die aufrufende Shell zum nächsten Befehl übergeht, was in Ihrem Fall offensichtlich der Fall ist. (Aber YMMV!Wenn "foo" einen schweren externen Befehl aufruft, wird es wahrscheinlich später ausgegeben)

Im Terminal ist es fast das Gleiche: Sie könnten ein Terminalfenster mit einer Shell-Eingabeaufforderung als Dateiskript dafür betrachten shell, dass die Login-Shell "während der Eingabe" liest. Das Verhalten ist fast gleich.

+0

Ich kümmere mich nicht um die Reihenfolge der Ausgabe, nur dass ich nur drei Zeilen bekomme. –

+0

Wie wenn Sie es in einem Terminal eingegeben haben. Aber ich nehme an, du hast das schon gemunkelt :) Es stolpert alles um: '&' ist kein Fork, dh es gibt die aufrufende Shell (oder vielmehr Shell + Script) nicht aus. Die Shell erzeugt den Befehl in einem separaten Prozess und behandelt ihn dann im Hintergrund, anstatt darauf zu warten, dass er beendet wird, bevor er fortgesetzt wird. Ref http://web.mit.edu/gnu/doc/html/features_5.html –

+0

Kopieren Sie das. Es bedeutet, dass mein Instinkt darüber in all den Jahren korrekt war, aber auch, dass mein ursprünglicher Bug unerklärt bleibt :( –

1

Abgesehen von der Tatsache, dass der Steueroperator & den Befehl asynchron 1 in einer Subshell ausgeführt werden verursacht, könnte man den Einsatz von Coprocesses macht die Ausgabe zu steuern.

Statt die Funktion aufrufen, indem er sagte:

foo & 

sagen:

coproc fubar { foo; } 

und dann die Ausgabe lesen, indem er sagte:

cat <&"${fubar[0]}" 

Dies würde erlauben Sie auch zu kontrollieren die Ausgabe (ob sie nach oder vor anderen Funktionen wieausgegeben werden soll 210 oder baz).


Zum Beispiel die folgenden:

foo() { 
    echo "logic1" 
    echo "logic2" 
} 

bar() { 
    echo "idic" 
} 

baz() { 
    echo "katra" 
} 

coproc fubar { foo; } 
bar 
baz 
cat <&"${fubar[0]}" 

produzieren würde:

idic 
katra 
logic1 
logic2 
+0

Während das OP-Problem nicht direkt angesprochen wird, ist es gut, über Coprozesse zu wissen (bash 4+). – mklement0

0

Eigentlich dieser Befehl Ihre Funktion ausgeführt wird foo den Hintergrund:

foo & 

Aber die Zeit, die Sie eingeben bar und baz foo hat bereits seinen Lauf abgeschlossen und seine Ausgabe auf Ihrem Terminal gedruckt.

Allerdings, wenn Sie Ihre Funktionen wie folgt ausführen, dann werden Sie den Unterschied bemerken:

foo & bar; baz 
[1] 46453 
idic 
katra 
logic 
[1]+ Done     foo 

Hier Ihre Prozess-ID als meine anders sein könnte, aber man kann sehen, dass logic am Ende nach Ausgaben von anderen gedruckt wird 2 Funktionen.

+0

Ich kümmere mich nicht um die Reihenfolge der Ausgabe; Es ist, dass _only_ 'foo' im Hintergrund ausgeführt wird und nicht das gesamte Skript abgezweigt wird. –

+0

Nein, ich habe die Reihenfolge nicht betont, ich habe nur darauf hingewiesen, dass die Funktion 'foo' tatsächlich im Hintergrund aufgerufen wurde und' bar', 'baz' wurden normalerweise aufgerufen, deshalb wurde die Reihenfolge der Ausgabe geändert. – anubhava

+0

Ich weiß, dass 'foo' im Hintergrund ausgeführt wird, aber ich wollte sicherstellen, dass der Subprozess _nur_' foo' ausführt und nicht mit dem Rest des Skripts fortfährt (was dazu führt, dass der Rest des Skripts zweimal ausgeführt wird). –

Verwandte Themen