Wie genau nennt sich die typische Granatengabelbombe zweimal?

15

Nachdem ich die berühmten Fork Bomb-Fragen auf Askubuntu und vielen anderen Stack Exchange-Sites durchgesehen habe, verstehe ich nicht ganz, was alle sagen, als ob es offensichtlich wäre.

Viele Antworten ( Bestes Beispiel ) sagen dies:

" {:|: &}bedeutet, die Funktion auszuführen :und ihre Ausgabe erneut an die :Funktion zu senden "

Nun, was genau ist die Ausgabe von :? Was wird an den anderen weitergegeben :?

Und auch:

Im Wesentlichen erstellen Sie eine Funktion, die sich bei jedem Aufruf zweimal selbst aufruft und keine Möglichkeit hat, sich selbst zu beenden.

Wie genau wird das zweimal ausgeführt ? Meiner Meinung nach wird nichts an den zweiten weitergegeben, :bis der erste :seine Ausführung beendet hat, was eigentlich niemals enden wird.

In Czum Beispiel

foo()
{
    foo();
    foo(); // never executed 
}

die zweite foo()wird überhaupt nicht ausgeführt, nur weil die erste foo()niemals endet.

Ich denke, dass die gleiche Logik für :(){ :|: & };:und gilt

:(){ : & };:

macht den gleichen Job wie

:(){ :|: & };:

Bitte helfen Sie mir, die Logik zu verstehen.

Severus Tux
quelle
9
Befehle in Pipelines werden parallel ausgeführt. In :|:diesem :Fall muss der zweite Befehl nicht warten, bis der erste abgeschlossen ist.
Cuonglm

Antworten:

26

Das Piping erfordert nicht, dass die erste Instanz beendet wird, bevor die andere gestartet wird. Eigentlich ist alles, was es wirklich tut, die Standardausgabe der ersten Instanz auf die Standardausgabe der zweiten Instanz umzuleiten , damit sie gleichzeitig ausgeführt werden können (da dies erforderlich ist, damit die Gabelbombe funktioniert).

Nun, was genau ist die Ausgabe von :? Was wird an den anderen weitergegeben :?

':' schreibt nichts in die andere ':' Instanz, sondern leitet nur die stdout zur stdin der zweiten Instanz um. Wenn es während seiner Ausführung etwas schreibt (was es niemals tut, da es nichts anderes tut als sich selbst zu forken), würde es zum Standard der anderen Instanz gehen.

Es hilft, sich stdin und stdout als Stapel vorzustellen :

Was auch immer in das stdin geschrieben wird, wird bereit gestapelt, wenn das Programm entscheidet, davon zu lesen, während das stdout auf die gleiche Weise funktioniert: Ein Stapel, auf den Sie schreiben können, damit andere Programme es lesen können, wenn sie wollen.

Auf diese Weise können Sie sich Situationen wie eine Pipe ohne Kommunikation (zwei leere Stapel) oder nicht synchronisierte Schreib- und Lesevorgänge vorstellen.

Wie genau wird das zweimal ausgeführt? Meiner Meinung nach wird nichts an den zweiten weitergegeben, :bis der erste :seine Ausführung beendet hat, was eigentlich niemals enden wird.

Da wir nur die Ein- und Ausgabe der Instanzen umleiten, muss die erste Instanz nicht beendet werden, bevor die zweite gestartet wird. Eigentlich ist es normalerweise erwünscht, dass beide gleichzeitig ausgeführt werden, damit die zweite sofort mit den Daten arbeiten kann, die von der ersten analysiert werden. Das ist, was hier passiert, beide werden angerufen, ohne warten zu müssen, bis der erste fertig ist. Dies gilt für alle Befehlszeilen von Pipe Chains .

Ich denke, dass die gleiche Logik gilt für: () {: |: &} ;: und

:(){ : & };:

Macht den gleichen Job wie

:(){ :|: & };:

Das erste würde nicht funktionieren, da die Funktion im Hintergrund ( : &) aufgerufen wird, obwohl sie selbst rekursiv ausgeführt wird . Das erste :wartet nicht, bis das "Kind" :zurückkehrt, bevor es sich selbst beendet. Am Ende hätten Sie wahrscheinlich nur eine Instanz :ausgeführt. Wenn Sie :(){ : };:es hätten, würde es funktionieren, da das erste :auf die :Rückkehr des "Kindes" warten würde, das auf die Rückkehr des eigenen "Kindes" warten würde :, und so weiter.

So würden verschiedene Befehle in Bezug auf die Anzahl der ausgeführten Instanzen aussehen:

:(){ : & };:

1 Instanz (ruft auf :und beendet sich) -> 1 Instanz (ruft auf :und beendet sich) -> 1 Instanz (ruft auf :und beendet sich) -> 1 Instanz -> ...

:(){ :|: &};:

1 Instanz (ruft 2 auf :und beendet) -> 2 Instanzen (jeder ruft 2 :auf und beendet) -> 4 Instanzen (jeder ruft 2 :auf und beendet) -> 8 Instanzen -> ...

:(){ : };:

1 Instanz (ruft auf :und wartet auf Rückkehr) -> 2 Instanzen (Kind ruft eine andere auf :und wartet auf Rückkehr) -> 3 Instanzen (Kind ruft eine andere auf :und wartet auf Rückkehr) -> 4 Instanzen -> ...

:(){ :|: };:

1 Instanz (ruft 2 auf :und wartet auf ihre Rückkehr) -> 3 Instanzen (Kinder rufen jeweils 2 auf :und warten auf ihre Rückkehr) -> 7 Instanzen (Kinder rufen jeweils 2 auf :und warten auf ihre Rückkehr) -> 15 Instanzen -> ...

Wie Sie sehen, &verlangsamt das Aufrufen der Funktion im Hintergrund (mithilfe von ) die Abzweigbombe, da der Angerufene beendet wird, bevor die aufgerufenen Funktionen zurückkehren.

IanC
quelle
Frage. Würde das :(){ : & && : &}; :auch als Gabelbombe funktionieren? Sie würden auch exponentiell zunehmen, und tatsächlich könnten Sie mehrere einsetzen : &, um es noch schneller zu erhöhen.
JFA
@JFA `─> $: () {: & &&: &}; : `gibt einen Syntaxfehler aus bash: syntax error near unexpected token &&' . Sie könnten dies tun: :(){ $(: &) && $(: &)}; :Aber im Gegensatz zur Pipeline wird das nicht parallel laufen. Welches wäre gleichbedeutend mit :(){: & };:. Möchten Sie überprüfen? versuchen Sie dies time $( $(sleep 1 & ) && $(sleep 1 &) )und dastime $(sleep 1 | sleep 1)
Severus Tux
Genau das :(){ $(: &) && $(: &)};ist eine Funktion, die eine logische AND-Operation in den Rückgabewerten der ersten und zweiten Instanz ausgibt. Das Problem ist, dass aus Effizienzgründen nur die erste Instanz ausgeführt wird, da ein logisches UND nur dann zutrifft, wenn beide Werte zutrifft. Wenn sein Rückgabewert 1 ist, wird die zweite Instanz ausgeführt. Wenn du die :(){ :|:|: &}; :
Gabelbombe
Nur als Randnotiz verwenden viele Skripte dieses Verhalten von AND in der folgenden Situation: Angenommen, Sie möchten prog2 ausführen, wenn prog1 true zurückgibt (was in bash 0 ist). Anstatt eine if-Anweisung ( if [ prog1 ]; then; prog2; fi) prog1 && prog2auszuführen, können Sie auch nur write ( ) ausführen, und prog2 wird nur ausgeführt, wenn der Rückgabewert von prog1 wahr ist.
IanC
Ok, das sind alles großartige Punkte. Früher habe ich &&angerufen apt-get update && apt-get upgradeund &am Ende der Leitung im Hintergrund ausgeführt, aber das ist ein großartiger Punkt, dass sie nicht zusammenarbeiten. Ein Semikolon funktioniert auch nicht mit dem kaufmännischen Und.
JFA