Unterstützt bash das Gabeln ähnlich wie Cs fork ()?

25

Ich habe ein Skript, das ich an einer Stelle teilen möchte, damit zwei Kopien desselben Skripts ausgeführt werden.

Ich möchte zum Beispiel, dass das folgende Bash-Skript existiert:

echo $$
do_fork()
echo $$

Wenn dieses Bash-Skript wirklich existieren würde, wäre die erwartete Ausgabe:

<ProcessA PID>
<ProcessB PID>
<ProcessA PID>

oder

<ProcessA PID>
<ProcessA PID>
<ProcessB PID>

Gibt es etwas, das ich anstelle von "do_fork ()" setzen kann, um diese Art von Ausgabe zu erhalten, oder um das Bash-Skript zu veranlassen, eine C-ähnliche Verzweigung auszuführen?

Cory Klein
quelle

Antworten:

23

Ja. Gabelung ist geschrieben &:

echo child & echo parent

Was Sie möglicherweise verwirrt, ist, dass $$es sich nicht um die PID des Shell-Prozesses handelt, sondern um die PID des ursprünglichen Shell-Prozesses. Auf diese Weise wird $$eine eindeutige Kennung für eine bestimmte Instanz des Shell-Skripts festgelegt: Sie ändert sich während der Skriptausführung nicht und unterscheidet sich von $$allen anderen gleichzeitig ausgeführten Skripts. Eine Möglichkeit, die tatsächliche PID des Shell-Prozesses zu ermitteln, ist sh -c 'echo $PPID'.

Der Kontrollfluss in der Shell ist nicht der gleiche wie in C. Wenn Sie in C schreiben würden

first(); fork(); second(); third();

dann ist ein Shell-Äquivalent

after_fork () { second; third; }
first; after_fork & after_fork

Die einfache Schalenform first; child & parententspricht der üblichen C-Sprache

first(); if (fork()) parent(); else child();

&und $$existieren und verhalten sich so in jeder Bourne-artigen Shell und in (t) csh. $PPIDexistierte nicht in der ursprünglichen Bourne-Shell, ist aber in POSIX (also in ash, bash, ksh, zsh, ...).

Gilles 'SO - hör auf böse zu sein'
quelle
3
Aber das ist im Grunde genommen "fork + exec", nicht nur "fork".
Mattdm
@mattdm: Äh? &Ist eine Gabel, da ist keine Führungskraft beteiligt. Fork + exec ist, wenn Sie einen externen Befehl starten.
Gilles 'SO- hör auf böse zu sein'
@mattdm: Ah, ich glaube ich sehe was Cory vorhat. Es gibt keine exec, aber die beiden Sprachen haben unterschiedliche Kontrollabläufe.
Gilles 'SO- hör auf böse zu sein'
1
@Gilles: Der Bash-Control-Operator &startet eine Subshell, in der der angegebene Befehl ausgeführt wird. Gabel + Exec. Sie können nicht einfach &ohne vorangestelltes Kommando ausführen.
Mattdm
5
Nun, wenn "Forking is spelt &" eine wahre Aussage wäre, könnten Sie &selbst eine Zeile setzen. Aber du kannst nicht. Es bedeutet nicht "Gabel hier". Es bedeutet "den vorhergehenden Befehl im Hintergrund in einer Subshell ausführen".
Mattdm
10

Ja, es heißt Subshells . Shell-Code in Klammern wird als Subshell (Fork) ausgeführt. Die erste Shell wartet jedoch normalerweise darauf, dass das Kind fertig ist. Sie können es mit dem &Abschlusszeichen asynchron machen . Sehen Sie es in Aktion mit so etwas:

#!/bin/bash

(sleep 2; echo "subsh 1")&
echo "topsh"

$ bash subsh.sh

Keith
quelle
5
Die Klammern bilden eine Unterschale, aber das ist Fork + Wait. &ist Gabel allein. Wenn Sie mehr als eine Pipeline im untergeordneten Prozess ausführen möchten, ist es ausreichend, geschweifte Klammern zu verwenden (die eine Gruppierung durchführen, ohne einen untergeordneten Prozess zu erstellen):{ sleep 2; echo child; } &
Gilles 'SO - hör auf, böse
6

Es gibt keine native Bash-Methode (oder meines Wissens eine andere typische * nix-Shell), um dies zu tun. Es gibt viele Möglichkeiten, gegabelte Prozesse zu erzeugen, die etwas anderes asynchron ausführen, aber ich glaube, es gibt nichts, das der genauen Semantik des Systemaufrufs fork () entspricht.

Der typische Ansatz wäre, dass Ihr Skript der obersten Ebene Helfer hervorbringt, die genau die Arbeit leisten, die Sie aufteilen möchten. Wenn du das tust $0 $@ &oder was auch immer, fängst du wieder von vorne an und musst das irgendwie herausfinden.

Eigentlich beginne ich mir mehrere clevere Möglichkeiten auszudenken, wie man genau das machen könnte ...

Aber bevor sich mein Gehirn davon zu sehr mitreißt, denke ich, lautet eine ziemlich gute Regel: Wenn Sie versuchen, etwas in Shell zu schreiben und es voller cleverer Tricks ist und Sie sich mehr Sprachfunktionen wünschen, ist Zeit zum Wechseln zu einer echten Programmiersprache .

mattdm
quelle
2
Obwohl die Syntax von bash gut verstanden wird, ist sie wohl schwierig, und es fehlen die eleganteren Datenstrukturen und Funktionen von Perl oder Python, aber bash ist so real, wie es in seiner Domäne nur geht . Es ist eine domänenspezifische Sprache, und ich würde in vielen Fällen sogar besser argumentieren (prägnanter, einfacher) als zB Python. Können Sie einen Raum voller Systeme verwalten und Python nicht kennen? Ja. Schaffst du das und weißt nicht, wie man [programmiert]? Ich würde es nicht versuchen wollen. Nach 30 Jahren Shell-Programmierung sage ich Ihnen, dass es so real ist, wie es nur geht. Und ja, ich spreche Python. Aber verwirren Sie die Jugendlichen nicht.
Mike S
2
Technisch gesehen gefällt mir diese Antwort jedoch besser. Zu sagen, dass "&" die Antwort auf die Frage des Benutzers ist, "an einer Stelle verzweigen, sodass zwei Kopien desselben Skripts ausgeführt werden", ist für mich verwirrend. "&" Führt laut Bash-Handbuch "... den Befehl [given] im Hintergrund in einer Subshell aus". Ein Befehl muss beendet werden, und es handelt sich um eine Verzweigung (technisch gesehen unter Linux um einen Klon ()), aber zu diesem Zeitpunkt werden zwei Kopien desselben Skripts nicht ausgeführt.
Mike S