Entendo como uma bomba de forquilha normal funciona, mas realmente não entendo por que o & no final da bomba de forquilha comum é necessária e por que esses scripts se comportam de maneira diferente:
:(){ (:) | (:) }; :
e
:(){ : | :& }; :
O primeiro causa um aumento no uso da CPU antes de me lançar de volta à tela de login. O último apenas faz com que meu sistema congele, forçando-me a reinicializar com força. Por que é que? Ambos criam continuamente novos processos, então por que o sistema se comporta de maneira diferente?
Ambos os scripts também se comportam de maneira diferente de
:(){ : | : }; :
o que não causa nenhum problema, mesmo que eu esperasse que eles fossem iguais. A página do manual do bash afirma que os comandos em um pipeline já foram executados em um subshell, então sou levado a acreditar que: | : já deve ser suficiente. Eu acredito e deveria apenas executar o pipeline em um novo subshell, mas por que isso muda tanto?
Edit: Usando htop e limitando a quantidade de processos, eu pude ver que a primeira variante cria uma árvore de processos real, a segunda variante cria todos os processos no mesmo nível e a última variante não parece criar nenhum processo em absoluto. Isso me confunde ainda mais, mas talvez ajude de alguma forma?
fonte
:(){ : | :; }; :
Respostas:
AVISO NÃO TENTE EXECUTAR ISTO EM UMA MÁQUINA DE PRODUÇÃO. APENAS NÃO. Aviso: Para tentar qualquer "bomba", verifique se
ulimit -u
está em uso. Leia abaixo [a] .Vamos definir uma função para obter o PID e a data (hora):
Uma função simples e sem problemas
bomb
para o novo usuário (proteja-se: leia [a] ):Quando essa função é chamada para ser executada, funciona assim:
O comando
date
é executado, um "sim" é impresso, um sono por 1 segundo, o comando de fechamentodate
e, finalmente, a função sai da impressão de um novo prompt de comando. Nada chique.| tubo
Quando chamamos a função assim:
Dois comandos começar em algum momento, os dois terminam 1 segundo mais tarde e , em seguida, o prompt retornos.
Essa é a razão do canal
|
, para iniciar dois processos em paralelo.& fundo
Se mudarmos a chamada, adicionamos um final
&
:O prompt retorna imediatamente (toda a ação é enviada para o plano de fundo) e os dois comandos são executados como antes. Observe o valor do "número do trabalho"
[1]
impresso antes do PID do processo3380
. Posteriormente, o mesmo número será impresso para indicar que o tubo terminou:Esse é o efeito de
&
.Essa é a razão da
&
: para iniciar os processos mais rapidamente.Nome mais simples
Podemos criar uma função chamada simplesmente
b
para executar os dois comandos. Digitado em três linhas:E executado como:
Observe que não usamos no
;
na definição deb
(as novas linhas foram usadas para separar elementos). No entanto, para uma definição em uma linha, é comum usar;
, assim:A maioria dos espaços também não é obrigatória, podemos escrever o equivalente (mas menos claro):
Também podemos usar a
&
para separar o}
(e enviar os dois processos para o plano de fundo).A bomba
Se fizermos a função morder sua cauda (chamando a si mesma), obteremos a "bomba de forquilha":
E para torná-lo mais rápido, envie o canal para o segundo plano.
Se anexarmos a primeira chamada à função após um requisito
;
e alterar o nome para:
obtermos:Geralmente escrito como
:(){ :|:& }; :
Ou, escrito de uma maneira divertida, com outro nome (um homem da neve):
O ulimit (que você deveria ter definido antes de executar isso) fará com que o prompt retorne rapidamente depois de muitos erros (pressione enter quando a lista de erros parar para obter o prompt).
A razão para isso ser chamado de "fork pump" é que a maneira pela qual o shell inicia um sub shell é bifurcando o shell em execução e depois chamando exec () para o processo bifurcado com o comando para executar.
Um tubo "bifurcará" dois novos processos. Fazer isso até o infinito causa uma bomba.
Ou um coelho como era originalmente chamado porque se reproduz muito rapidamente.
Cronometragem:
:(){ (:) | (:) }; time :
Terminados
0m45.627s reais
:(){ : | :; }; time :
Terminados
0m15.283s reais
:(){ : | :& }; time :
0m00.002 s reais
ainda em execução
Seus exemplos:
:(){ (:) | (:) }; :
Onde o segundo fechamento
)
separa}
é uma versão mais complexa de:(){ :|:;};:
. Cada comando em um pipe é chamado dentro de um sub-shell de qualquer maneira. Qual é o efeito do()
.:(){ : | :& }; :
É a versão mais rápida, escrita para não ter espaços:
:(){(:)|:&};:
(13 caracteres).:(){ : | : }; :
### funciona no zsh, mas não no bash.Possui um erro de sintaxe (no bash), um metacaractere é necessário antes do fechamento
}
,assim:
[a] Crie um novo usuário limpo (eu chamarei de meu
bize
). Efetue login neste novo usuário em um consolesudo -i -u bize
ou:Verifique e altere o
max user processes
limite:Usando apenas 10 obras, como é apenas um usuário novo solitária:
bize
. Torna mais fácil chamarkillall -u bize
e livrar o sistema da maioria das bombas (não todas). Por favor, não pergunte quais ainda funcionam, não vou contar. Mas ainda: é bastante baixo, mas no lado seguro, adapte-se ao seu sistema .Isso garantirá que uma "bomba de forquilha" não entrará em colapso no seu sistema .
Leitura adicional:
fonte