Сегодня про RANDOM и револьвер

В бородатые 2000е была такая консольная игруля «Русская рулетка», состояла она из одной строчки:

[ $[ $RANDOM % 6 ] == 0 ] && rm -rf / || echo "You live"

Для начала давай сделаем её более безопасной:

[ $[ $RANDOM % 6 ] == 0 ] && echo 'You died' || echo 'You live'

Суть такая: Если деление по модулю псевдослучайного числа переменной RANDOM вернёт - 0, значит тебе песда и пистолет выстрелил. Соответственно если > 0, то ты пока еще жив и тебе повезло.

А теперь давай посмотрим на условия, при которых «пистолет выстрелит» сразу.

Число отличное от 0, указанное в качестве переменной RANDOM используется как seed (семя) для генератора псевдослучайных чисел. Если посеять число 2, то при первом обращении к переменной RANDOM получим значение, которое делится на 6 без остатка.

RANDOM=2
[ $[ $RANDOM % 6 ] == 0 ] && echo 'You died' || echo 'You live'

Этот посев даст нужное в разных версиях интерпретатора. Все дело в том, что в версии bash 5.1 были внесены изменения связанные с этим. Короче если у тебя версия баша > 5.0, то можно изменить поведение генератора с помощью переменной BASH_COMPAT.

Так, давай теперь это проверим:

( BASH_COMPAT=51 ; RANDOM=0 ; echo $RANDOM )

Получаем значение: 20814

( BASH_COMPAT=50 ; RANDOM=0 ; echo $RANDOM )

А тут уже другое: 20034

Если мы задаем 0 в переменную RANDOM, тогда семя (seed) инициализируется жестко заданным значением. При котором генерируется требуемое число, то есть делится на 6 без остатка.

RANDOM=0
[ $[ $RANDOM % 6 ] == 0 ] && echo 'You died' || echo 'You live'

Тут пистолет гарантированно выстрелит. Аналогично предыдущему примеру, если начало строки не число:

RANDOM='bashdays'
[ $[ $RANDOM % 6 ] == 0 ] && echo 'You died' || echo 'You live'

Снова получим 100% выстрел.

Как работает генератор:

  • Начальное значение seed, оболочка получает совершая манипуляции над значениями pid, ppid, uid + текущее время (секунды, микросекунды).

  • Далее полученное значение пропускается через алгоритм, а результат сохраняется. При следующих обращениях также пропускается через алгоритм.

  • Потом полученное число усекается. В документации указано максимальное возможное значение 32767.

Роман Шубин
Роман Шубин
CEO & CTO, Главред в «Цифровой улей»
Задать вопрос
Как я писал выше, руки у нас развязаны и мы можем влиять на начальное значение генератора через переменную RANDOM.

Такие дела, исследуйте!