Come si chiama due volte la tipica "bomba a forcella" della shell?


15

Dopo aver esaminato le famose domande su Fork Bomb su Askubuntu e su molti altri siti di Stack Exchange, non capisco bene cosa stiano dicendo tutti, è ovvio.

Molte risposte ( miglior esempio ) dicono questo:

" {:|: &}significa eseguire la funzione :e inviare :nuovamente il suo output alla funzione"

Bene, qual è esattamente l'output di :? Cosa viene passato all'altro :?

E anche:

In sostanza stai creando una funzione che si chiama due volte ogni chiamata e non ha alcun modo di terminare se stessa.

Come viene eseguito esattamente due volte ? Secondo me, nulla è passato al secondo :fino a quando il primo non :termina la sua esecuzione, che in realtà non finirà mai.

Ad Cesempio,

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

il secondo foo()non viene eseguito affatto, solo perché il primo foo()non finisce mai.

Sto pensando che la stessa logica si applica a :(){ :|: & };:e

:(){ : & };:

fa lo stesso lavoro di

:(){ :|: & };:

Per favore, aiutami a capire la logica.


9
Il comando in pipeline viene eseguito in parallelo, in :|:, il secondo :non deve attendere il primo completato.
cuonglm,

Risposte:


26

Il piping non richiede che la prima istanza termini prima che inizi l'altra. In realtà, tutto ciò che sta realmente facendo è reindirizzare lo stdout della prima istanza allo stdin della seconda, in modo che possano funzionare simultaneamente (come devono fare per far funzionare la bomba a forcella).

Bene, qual è esattamente l'output di :? cosa viene passato all'altro :?

':' non sta scrivendo nulla sull'altra ':' istanza, sta semplicemente reindirizzando lo stdout allo stdin della seconda istanza. Se scrive qualcosa durante la sua esecuzione (cosa che non farà mai, poiché non fa altro che biforcarsi) andrebbe allo stdin dell'altra istanza.

Aiuta a immaginare lo stdin e lo stdout come una pila:

Qualunque cosa sia scritta sullo stdin verrà accumulata pronta per quando il programma decide di leggere da esso, mentre lo stdout funziona allo stesso modo: una pila in cui puoi scrivere, così altri programmi possono leggere da esso quando vogliono.

In questo modo è facile immaginare situazioni come una pipe senza comunicazione (due pile vuote) o scritture e letture non sincronizzate.

Come viene eseguito esattamente due volte? Secondo me, nulla è passato al secondo :fino a quando il primo non :termina la sua esecuzione, che in realtà non finirà mai.

Poiché stiamo semplicemente reindirizzando l'input e l'output delle istanze, non è necessario che la prima istanza termini prima che inizi la seconda. In realtà, in genere si desidera che entrambi vengano eseguiti contemporaneamente in modo che il secondo possa funzionare con i dati analizzati dal primo al volo. Ecco cosa succede qui, entrambi saranno chiamati senza dover aspettare che il primo finisca. Questo vale per tutte le linee di comandi di catene di tubi .

Sto pensando che la stessa logica si applica a: () {: |: &} ;: e

:(){ : & };:

Fa lo stesso lavoro di

:(){ :|: & };:

Il primo non funzionerebbe, perché anche se si sta eseguendo in modo ricorsivo, la funzione viene chiamata in background ( : &). Il primo :non aspetta che il "figlio" :ritorni prima di terminare se stesso, quindi alla fine avresti probabilmente solo un'istanza di :esecuzione. Se avessi :(){ : };:funzionato, però, dal momento che il primo :aspetterebbe il :ritorno del "bambino" , che aspetterebbe il ritorno del proprio "bambino" :, e così via.

Ecco come apparirebbero diversi comandi in termini di quante istanze sarebbero in esecuzione:

:(){ : & };:

1 istanza (chiamate :e uscite) -> 1 istanza (chiamate :e uscite) -> 1 istanza (chiamate :e uscite) -> 1 istanza -> ...

:(){ :|: &};:

1 istanza (chiama 2 :'ed esce) -> 2 istanze (ognuno chiama 2 :' ed esce) -> 4 istanze (ognuno chiama 2 :'ed esce) -> 8 istanze -> ...

:(){ : };:

1 istanza (chiama :e aspetta che ritorni) -> 2 istanze (il bambino chiama un'altra :e aspetta che ritorni) -> 3 istanze (il bambino chiama un'altra :e aspetta che ritorni) -> 4 istanze -> ...

:(){ :|: };:

1 istanza (chiama 2 :e attende che ritornino) -> 3 istanze (i bambini chiamano 2 :ciascuno e attendono che ritornino) -> 7 istanze (i bambini chiamano 2 :ciascuno e attendono che ritornino) -> 15 istanze -> ...

Come puoi vedere, chiamare la funzione in background (usando &) in realtà rallenta la bomba a forcella, perché la chiamata uscirà prima che le funzioni chiamate ritornino.


Domanda. Funzionerebbe :(){ : & && : &}; :anche come bomba a forcella? Aumenteresti anche in modo esponenziale e, in effetti, potresti mettere molti più : &lì per aumentarlo ancora più velocemente.
JFA,

@JFA `─> $: () {: & &&: &}; : `dà errore di sintassi bash: syntax error near unexpected token &&' . Potresti farlo:, :(){ $(: &) && $(: &)}; :ma, a differenza della pipeline, ciò non funzionerà in parallelo. Quale sarebbe equivalente :(){: & };:. Vuoi verificare? prova questi time $( $(sleep 1 & ) && $(sleep 1 &) )e questotime $(sleep 1 | sleep 1)
Severus Tux,

Esattamente, :(){ $(: &) && $(: &)};è una funzione che sta eseguendo un'operazione AND logica nei valori di ritorno della prima e della seconda istanza. Il problema è che poiché un AND logico è vero solo se entrambi i valori sono veri, per efficienza verrà eseguita solo la prima istanza. Se il valore restituito è 1, verrà eseguita la seconda istanza. Se vuoi rendere la bomba a forcella ancora più veloce penso che potresti semplicemente :(){ :|:|: &}; :
incanalare

Proprio come una nota a margine, molti script usano questo comportamento di AND nella seguente situazione: supponiamo che tu voglia eseguire prog2 se prog1 restituisce true (che in bash è 0). Invece di fare un'istruzione if ( if [ prog1 ]; then; prog2; fi) potresti semplicemente scrivere ( prog1 && prog2) e prog2 verrebbe eseguito solo se il valore di ritorno di prog1 fosse vero.
IanC,

Ok, questi sono tutti punti fantastici. Io &&chiamo apt-get update && apt-get upgrade, e &alla fine della linea per correre in background, ma è un ottimo punto che non funzioneranno insieme. Un punto e virgola non funziona anche con la e commerciale.
JFA,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.