Трубопровід не вимагає, щоб перша інстанція закінчувалася до початку другої. Насправді, все, що вона насправді робить, - це перенаправлення відтінку першої інстанції до stdin другого, щоб вони могли працювати одночасно (як це потрібно, щоб вилка бомба працювала).
Ну, що саме є результатом :
? що передається іншому:
?
":" нічого не пише іншому ":", це просто перенаправлення stdout до stdin другої інстанції. Якщо він пише щось під час його виконання (чого ніколи не буде, оскільки нічого не робить, окрім себе роздвоєння), він би перейшов до стандартне введення іншої інстанції.
Це допомагає уявити stdin та stdout як купу:
Все, що написано на stdin, буде накопичуватися готовим, коли програма вирішить прочитати з нього, тоді як stdout працює так само: купу, в яку можна писати, тому інші програми можуть читати з неї, коли захочуть.
Таким чином, легко уявити такі ситуації, як труба, яка не має зв'язку (дві порожні палі), або несинхронізована запис і зчитування.
Як саме це виконується двічі? На мою думку, до другого нічого не передається, :
поки перший не :
закінчить своє виконання, що насправді ніколи не закінчиться.
Оскільки ми просто переспрямовуємо вхід і вихід примірників, немає необхідності закінчити перший екземпляр до початку другого. Насправді, як правило, бажано, щоб обидва працювали одночасно, щоб другий міг працювати з даними, які першими розбиралися на льоту. Ось що відбувається тут, обидва будуть називатися, не потрібно чекати, коли перший закінчить. Це стосується всіх ліній команд труб .
Я думаю, що та ж логіка стосується: () {: |: &} ;: і
:(){ : & };:
Робить ту саму роботу, що і
:(){ :|: & };:
Перший не працюватиме, оскільки, хоча він працює сам рекурсивно, функція викликається у фоновому режимі ( : &
). Перший :
не чекає, поки «дитина» :
повернеться до того, як закінчиться, тому в кінцевому підсумку ви, мабуть, матимете лише один екземпляр :
запуску. Якби у вас :(){ : };:
це було, то працювало б, оскільки перший :
би чекав :
повернення «дитини» , яка чекала б повернення власної «дитини» :
тощо.
Ось як виглядатимуть різні команди щодо кількості запущених екземплярів:
:(){ : & };:
1 екземпляр (дзвінки :
та виходи) -> 1 екземпляр (дзвінки :
та виходи) -> 1 екземпляр (дзвінки :
та виходи) -> 1 екземпляр -> ...
:(){ :|: &};:
1 екземпляр (дзвінки 2 :
і виклики ) -> 2 екземпляри (кожен викликає 2 :
і виходить) -> 4 екземпляри (кожен викликає 2 :
і виходить) -> 8 екземплярів -> ...
:(){ : };:
1 екземпляр (дзвонить :
і чекає, коли він повернеться) -> 2 екземпляри (дитина дзвонить іншому :
і чекає, коли він повернеться) -> 3 екземпляри (дитина викликає інший :
і чекає повернення) -> 4 екземпляри -> ...
:(){ :|: };:
1 екземпляр (дзвонить 2 :
і чекає, коли вони повернуться) -> 3 екземпляри (діти дзвонять по 2 :
і чекають, коли вони повернуться) -> 7 екземплярів (діти дзвонять по 2 :
і чекають, коли вони повернуться) -> 15 екземплярів -> ...
Як бачимо, виклик функції у фоновому режимі (за допомогою &
) насправді уповільнює вилкову бомбу, оскільки виклик вийде, перш ніж викликані функції повернуться.
:|:
другому:
не потрібно чекати, коли перший завершиться.