| труба

| труба

Я понимаю, как работает обычная fork-бомба, но не совсем понимаю, зачем нужен & в конце обычной bash-бомбы и почему эти скрипты ведут себя по-разному:

:(){ (:) | (:) }; :

и

:(){ : | :& }; :

Первый вызывает скачок использования процессора, прежде чем отбросить меня обратно на экран входа в систему. Второй вместо этого просто зависает мою систему, заставляя меня делать жесткую перезагрузку. Почему так? Оба постоянно создают новые процессы, так почему же система ведет себя по-разному?

Оба скрипта также ведут себя по-разному.

:(){ : | : }; :

что не вызывает никаких проблем вообще, хотя я ожидал, что они будут одинаковыми. На странице руководства bash указано, что команды в конвейере уже выполняются в подоболочке, поэтому я склонен полагать, что : | : уже должно быть достаточно. Я считаю, что и должен просто запустить конвейер в новой подоболочке, но почему это так сильно меняет?

Редактировать: Используя htop и ограничивая количество процессов, я смог увидеть, что первый вариант создает фактическое дерево процессов, второй вариант создает все процессы на одном уровне, а последний вариант, похоже, вообще не создает никаких процессов. Это еще больше меня сбивает с толку, но, может быть, это как-то помогает?

решение1

ВНИМАНИЕ! НЕ ПЫТАЙТЕСЬ ЗАПУСТИТЬ ЭТО НА ПРОИЗВОДСТВЕННОЙ МАШИНЕ. ПРОСТО НЕ ДЕЛАЙТЕ ЭТОГО. Предупреждение: Чтобы попробовать любые "бомбы", убедитесь, ulimit -uчто используется. Читайте ниже [a] .

Давайте определим функцию для получения PID и даты (времени):

bize:~$ d(){ printf '%7s %07d %s\n' "$1" "$BASHPID" "$(date +'%H:%M:%S')"; }

Простая, не вызывающая проблем bombфункция для нового пользователя (защитите себя: прочтите [a] ):

bize:~$ bomb() { d START; echo "yes"; sleep 1; d END; } >&2

Когда эта функция вызывается для выполнения, она работает следующим образом:

bize:~$ bomb
  START 0002786 23:07:34
yes
    END 0002786 23:07:35
bize:~$

Команда dateвыполняется, затем печатается "да", сон на 1 секунду, затем команда закрытия date, и, наконец, функция завершает работу, печатая новую командную строку. Ничего особенного.

| труба

Когда мы вызываем функцию следующим образом:

bize:~$ bomb | bomb
  START 0003365 23:11:34
yes
  START 0003366 23:11:34
yes
    END 0003365 23:11:35
    END 0003366 23:11:35
bize:~$

Две команды начинаются одновременно, обе команды завершатся через 1 секунду изатемприглашение возвращается.

Вот почему существует канал |, позволяющий запускать два процесса параллельно.

& фон

Если мы изменим вызов, добавив окончание &:

bize:~$ bomb | bomb &
[1] 3380
bize:~$
  START 0003379 23:14:14
yes
  START 0003380 23:14:14
yes
    END 0003379 23:14:15
    END 0003380 23:14:15

Приглашение возвращается немедленно (все действия отправляются в фоновый режим), и две команды выполняются, как и прежде. Обратите внимание на значение "job number", [1]напечатанное перед PID процесса 3380. Позже тот же номер будет напечатан, чтобы указать, что конвейер завершен:

[1]+  Done                    bomb | bomb

Таков эффект &.

Вот в чем причина &: ускорить запуск процессов.

Более простое название

Мы можем создать функцию, которая называется просто bдля выполнения двух команд. Набирается в три строки:

bize:~$ b(){
> bomb | bomb
> }

И выполнено как:

bize:~$ b
  START 0003563 23:21:10
yes
  START 0003564 23:21:10
yes
    END 0003564 23:21:11
    END 0003563 23:21:11

Обратите внимание, что мы использовали no ;в определении b(переходы строк использовались для разделения элементов). Однако для определения в одну строку обычно используют ;, например:

bize:~$ b(){ bomb | bomb ; }

Большинство пробелов также не являются обязательными, мы можем написать эквивалент (но менее понятный):

bize:~$ b(){ bomb|bomb;}

Мы также можем использовать a &для разделения }(и отправки двух процессов в фоновый режим).

Бомба.

Если мы заставим функцию укусить себя за хвост (вызвав саму себя), то получим «бомбу-развилку»:

bize:~$ b(){ b|b;}       ### May look better as b(){ b | b ; } but does the same.

А чтобы ускорить вызов большего количества функций, отправьте конвейер в фоновый режим.

bize:~$ b(){ b|b&}       ### Usually written as b(){ b|b& }

Если мы добавим первый вызов функции после required ;и изменим имя на , то :получим:

bize:~$ :(){ :|:&};:

Обычно пишется как:(){ :|:& }; :

Или, если написать в веселой форме, с другим названием (снеговик):

☃(){ ☃|☃&};☃

Параметр ulimit (который вы должны были установить перед запуском) заставит подсказку возвращаться довольно быстро после большого количества ошибок (нажмите Enter, когда список ошибок остановится, чтобы получить подсказку).

Причина, по которой это называется «бомбой-разветвлением», заключается в том, что оболочка запускает подоболочку, разветвляя запущенную оболочку и затем вызывая exec() для разветвленного процесса с командой на запуск.

Труба "разветвит" два новых процесса. Если делать это до бесконечности, получится бомба.
Или кролик, как его изначально называли, потому что он очень быстро размножается.


Сроки:

  1. :(){ (:) | (:) }; time :
    Завершено
    реально 0m45.627s

  2. :(){ : | :; }; time :
    Завершено
    реально 0m15.283s

  3. :(){ : | :& }; time :
    реальный 0m00.002 s
    все еще работает


Ваши примеры:

  1. :(){ (:) | (:) }; :

    Там, где второе закрытие )разделяет , }есть более сложная версия :(){ :|:;};:. Каждая команда в конвейере в любом случае вызывается внутри подоболочки. Что является эффектом ().

  2. :(){ : | :& }; :

    Это более быстрая версия, записанная без пробелов: :(){(:)|:&};:(13 символов).

  3. :(){ : | : }; : ### работает в zsh, но не в bash.

    Имеет синтаксическую ошибку (в bash), перед закрывающим символом необходим метасимвол },
    как здесь:

     :(){ : | :; }; :
    

[а] Создайте нового чистого пользователя (я назову своего bize). Войдите в систему под этим новым пользователем в консоли либо sudo -i -u bize, либо:

$ su - bize
Password: 
bize:~$

Проверьте и измените max user processesлимит:

bize:~$ ulimit -a           ### List all limits (I show only `-u`)
max user processes              (-u) 63931
bize:~$ ulimit -u 10        ### Low
bize:~$ ulimit -a
max user processes              (-u) 1000

Использование только 10 работает, так как есть только один новый пользователь: bize. Это облегчает вызов killall -u bizeи избавление системы от большинства (не всех) бомб. Пожалуйста, не спрашивайте, какие из них все еще работают, я не скажу. Но все же:Довольно низкий, но на всякий случай адаптируйте к своей системе.
Этотгарантирует, что «вилочная бомба» не разрушит вашу систему.

Дальнейшее чтение:

Связанный контент