Depois de passar pelas famosas perguntas de Fork Bomb no Askubuntu e em muitos outros sites do Stack Exchange, não entendo bem o que todo mundo está dizendo como se fosse óbvio.
Muitas respostas ( melhor exemplo ) dizem o seguinte:
"
{:|: &}
significa executar a função:
e enviar sua saída para a:
função novamente"
Bem, qual é exatamente a saída :
? O que está sendo passado para o outro :
?
E também:
Essencialmente, você está criando uma função que se chama duas vezes a cada chamada e não tem como se finalizar.
Como exatamente isso é executado duas vezes ? Na minha opinião, nada é passado para o segundo :
até que o primeiro :
termine sua execução, o que realmente nunca terminará.
Por C
exemplo,
foo()
{
foo();
foo(); // never executed
}
o segundo foo()
não é executado, apenas porque o primeiro foo()
nunca termina.
Eu estou pensando que a mesma lógica se aplica a :(){ :|: & };:
e
:(){ : & };:
faz o mesmo trabalho que
:(){ :|: & };:
Por favor me ajude a entender a lógica.
fonte
:|:
segundo,:
não é necessário esperar o primeiro ser concluído.Respostas:
A tubulação não exige que a primeira instância termine antes da outra iniciar. Na verdade, tudo o que está realmente fazendo é redirecionar o stdout da primeira instância para o stdin da segunda, para que eles possam estar executando simultaneamente (como é necessário para o fork bomb funcionar).
':' não está escrevendo nada para a outra instância ':', apenas redirecionando o stdout para o stdin da segunda instância. Se ele escreve alguma coisa durante a sua execução (que nunca, uma vez que não faz nada, mas se bifurcar em si) que iria para o stdin da outra instância.
Ajuda a imaginar stdin e stdout como uma pilha:
Tudo o que está escrito no stdin será empilhado pronto para quando o programa decidir ler a partir dele, enquanto o stdout funciona da mesma maneira: uma pilha na qual você pode escrever, para que outros programas possam ler quando quiserem.
Dessa forma, é fácil imaginar situações como um canal sem comunicação (duas pilhas vazias) ou gravações e leituras não sincronizadas.
Como estamos apenas redirecionando a entrada e a saída das instâncias, não é necessário que a primeira instância termine antes do início da segunda. Na verdade, geralmente é desejável que ambos sejam executados simultaneamente para que o segundo possa trabalhar com os dados analisados pelo primeiro em tempo real. É o que acontece aqui, ambos serão chamados sem precisar esperar o primeiro final. Isso se aplica a todas as linhas de comandos de cadeias de tubulação .
O primeiro não funcionaria, porque, embora esteja executando recursivamente, a função está sendo chamada em segundo plano (
: &
). O primeiro:
não espera até que o "filho":
retorne antes de terminar, então no final você provavelmente terá apenas uma instância de:
execução. Se você tivesse:(){ : };:
, funcionaria, pois o primeiro:
aguardaria o:
retorno do "filho" , o que esperaria o retorno do seu "filho":
, e assim por diante.Veja como seriam os comandos diferentes em termos de quantas instâncias seriam executadas:
:(){ : & };:
1 instância (chamadas
:
e saídas) -> 1 instância (chamadas:
e saídas) -> 1 instância (chamadas:
e saídas) -> 1 instância -> ...:(){ :|: &};:
1 instância (chama 2
:
's e encerra) -> 2 instâncias (cada uma chama 2:
' e encerra) -> 4 instâncias (cada uma chama 2:
'e encerra) -> 8 instâncias -> ...:(){ : };:
1 instância (chama
:
e aguarda o retorno) -> 2 instâncias (o filho chama outro:
e espera o retorno) -> 3 instâncias (o filho chama outro:
e espera o retorno) -> 4 instâncias -> ...:(){ :|: };:
1 instância (chama 2
:
e espera que eles retornem) -> 3 instâncias (filhos chama 2:
e cada um e espera que eles retornem) -> 7 instâncias (filhos chama 2:
e cada e espera que eles retornem) -> 15 instâncias -> ...Como você pode ver, chamar a função em segundo plano (usando
&
) na verdade reduz a velocidade da bifurcação, porque o chamado termina antes que as funções chamadas retornem.fonte
:(){ : & && : &}; :
também funcionam como uma bomba garfo? Você também aumentaria exponencialmente e, de fato, poderia colocar múltiplos: &
para aumentar ainda mais rapidamente.bash: syntax error near unexpected token &&'
. Você pode fazer o seguinte:,:(){ $(: &) && $(: &)}; :
Mas, ao contrário do pipeline, isso não será executado em paralelo. O que seria equivalente a:(){: & };:
. Gostaria de verificar? tente issotime $( $(sleep 1 & ) && $(sleep 1 &) )
e isso #time $(sleep 1 | sleep 1)
:(){ $(: &) && $(: &)};
é uma função que está emitindo uma operação AND lógica nos valores de retorno da primeira e da segunda instância. O problema é que, uma vez que um AND lógico é verdadeiro apenas se ambos os valores forem verdadeiros, por eficiência, apenas a primeira instância será executada. Se seu valor de retorno for 1, a segunda instância será executada. Se você quiser fazer a bomba fork ainda mais rápido eu acho que você poderia apenas tubos mais instâncias na cadeia, como:(){ :|:|: &}; :
if [ prog1 ]; then; prog2; fi
), você poderia apenas escrever (prog1 && prog2
), e prog2 seria executado apenas se o valor de retorno de prog1 fosse verdadeiro.&&
ligarapt-get update && apt-get upgrade
e,&
no final da linha, executar em segundo plano, mas esse é um ótimo ponto para eles não funcionarem juntos. Um ponto-e-vírgula também não funciona com o e comercial.