Je comprends comment fonctionne une bombe fork normale, mais je ne comprends pas vraiment pourquoi le & à la fin de la bombe bash fork commune est requis et pourquoi ces scripts se comportent différemment:
:(){ (:) | (:) }; :
et
:(){ : | :& }; :
Le premier provoque une pointe d'utilisation du processeur avant de me renvoyer à l'écran de connexion. À la place, ce dernier provoque simplement le gel de mon système, ce qui m'oblige à un redémarrage dur. Pourquoi donc? Les deux créent continuellement de nouveaux processus, alors pourquoi le système se comporte-t-il différemment?
Les deux scripts se comportent également différemment de
:(){ : | : }; :
ce qui ne pose aucun problème, même si je m'attendais à ce qu'ils se ressemblent. La page de manuel bash indique que les commandes dans un pipeline sont déjà exécutées dans un sous-shell, donc je suis amené à croire que: | : devrait déjà suffire. Je crois que je devrais simplement exécuter le pipeline dans un nouveau sous-shell, mais pourquoi cela change-t-il tant?
Edit: En utilisant htop et en limitant la quantité de processus, j'ai pu voir que la première variante crée un arbre de processus réel, la deuxième variante crée tous les processus au même niveau et la dernière variante ne semble pas créer de processus du tout. Cela m'embrouille encore plus, mais peut-être que cela aide d'une manière ou d'une autre?
la source
:(){ : | :; }; :
Réponses:
AVERTISSEMENT N'ESSAYEZ PAS DE L'EXÉCUTER SUR UNE MACHINE DE PRODUCTION. JUSTE PAS. Avertissement: pour essayer des "bombes", assurez-vous qu'elles
ulimit -u
sont en cours d'utilisation. Lisez ci-dessous [a] .Définissons une fonction pour obtenir le PID et la date (heure):
Une fonction simple et sans problème
bomb
pour le nouvel utilisateur (protégez-vous: lisez [a] ):Lorsque cette fonction est appelée pour être exécutée, cela fonctionne comme suit:
La commande
date
est exécutée, puis un "oui" est imprimé, un sommeil pendant 1 seconde, puis la commande de fermeturedate
et, enfin, la fonction quitte l'impression d'une nouvelle invite de commande. Rien d'extraordinaire.| tuyau
Lorsque nous appelons la fonction comme ceci:
Deux commandes démarrent à un moment donné, les deux se terminent 1 seconde plus tard, puis l'invite revient.
C'est la raison pour laquelle la pipe
|
, pour démarrer deux processus en parallèle.& Contexte
Si nous changeons l'appel en ajoutant une fin
&
:L'invite revient immédiatement (toute l'action est envoyée en arrière-plan) et les deux commandes sont exécutées comme précédemment. Veuillez noter la valeur du "numéro de travail"
[1]
imprimé avant le PID du processus3380
. Plus tard, le même numéro sera imprimé pour indiquer que le tuyau est terminé:C'est l'effet de
&
.C'est la raison de
&
: accélérer le démarrage des processus.Nom plus simple
Nous pouvons créer une fonction appelée simplement
b
pour exécuter les deux commandes. Tapé en trois lignes:Et exécuté comme:
Notez que nous avons utilisé non
;
dans la définition deb
(les retours à la ligne ont été utilisés pour séparer les éléments). Cependant, pour une définition sur une ligne, il est habituel d'utiliser;
, comme ceci:La plupart des espaces ne sont pas non plus obligatoires, nous pouvons écrire l'équivalent (mais moins clair):
Nous pouvons également utiliser un
&
pour séparer le}
(et envoyer les deux processus en arrière-plan).La bombe.
Si nous faisons mordre sa queue (en se faisant appeler), nous obtenons la "bombe fourchette":
Et pour le faire appeler plus de fonctions plus rapidement, envoyez le tuyau en arrière-plan.
Si nous ajoutons le premier appel à la fonction après un requis
;
et changeons le nom,:
nous obtenons:Habituellement écrit comme
:(){ :|:& }; :
Ou, écrit d'une manière amusante, avec un autre nom (un bonhomme de neige):
L'ulimit (que vous auriez dû définir avant d'exécuter ceci) fera revenir l'invite assez rapidement après beaucoup d'erreurs (appuyez sur Entrée lorsque la liste d'erreurs s'arrête pour obtenir l'invite).
La raison pour laquelle on appelle cela une "bombe fork" est que la façon dont le shell démarre un sous-shell est de forker le shell en cours d'exécution, puis d'appeler exec () au processus forké avec la commande à exécuter.
Un tuyau va "bifurquer" deux nouveaux processus. Le faire à l'infini provoque une bombe.
Ou un lapin comme on l'appelait à l'origine parce qu'il se reproduit si rapidement.
Horaire:
:(){ (:) | (:) }; time :
Terminé
réel 0m45.627s
:(){ : | :; }; time :
Terminé
réel 0m15.283s
:(){ : | :& }; time :
réel 0m00.002 s
Toujours en marche
Vos exemples:
:(){ (:) | (:) }; :
Là où la deuxième fermeture
)
sépare,}
c'est une version plus complexe de:(){ :|:;};:
. Chaque commande d'un tube est de toute façon appelée dans un sous-shell. Quel est l'effet du()
.:(){ : | :& }; :
Est la version la plus rapide, écrite sans espaces:
:(){(:)|:&};:
(13 caractères).:(){ : | : }; :
### fonctionne en zsh mais pas en bash.A une erreur de syntaxe (en bash), un métacaractère est nécessaire avant la fermeture
}
,comme ceci:
[a] Créez un nouvel utilisateur propre (j'appellerai le mien
bize
). Connectez-vous à ce nouvel utilisateur dans une consolesudo -i -u bize
, ou:Vérifiez puis modifiez la
max user processes
limite:En utilisant seulement 10 fonctionne comme qu'un seul nouvel utilisateur solitaire:
bize
. Il est plus facile d'appelerkillall -u bize
et de débarrasser le système de la plupart des bombes (pas toutes). S'il vous plaît ne demandez pas lesquels fonctionnent toujours, je ne le dirai pas. Mais quand même: est assez faible mais du côté sûr, adaptez-vous à votre système .Cela garantira qu'une "bombe à fourche" n'effondrera pas votre système .
Lectures complémentaires:
la source