Ещё немного про random() в bc
Как я уже рассказывал, bc под «Линуксом» очень старый, — на всех машинах, куда у меня есть доступ, установлена версия 1.07.1 2017-го года. Непонятно с чем связан такой консерватизм, но чем богаты. В этой версии отсутствует до печального много удобных вещей, например, функция для получения случайного числа.
Ранее я обнаружил недокументированную функцию random(), но генератор случайных чисел в линуксовом bc не инициализируется и функция выдаёт на старте всегда одно и тоже число. Её можно покрутить снаружи случайное число раз и это исправляет ситуацию, но способ, который я тогда придумал для этого, так себе.
Сегодня, пока ехал в такси, придумывал ещё более так себе способы это сделать.
Мысль моя крутилась вокруг запуска через утилиту env. В мире командной строки так частенько делают, так что этот способ как будто бы чуть более честный, так шелл тут не используется:
#!/usr/bin/env -S -i seed_="0${XDG_SESSION_ID};while(seed_--).=random()#" bc /proc/self/environ
print random()
quit()
Здорово, правда?
Вся чёрная магия сосредоточена в первой строке. Файл /proc/self/environ формируется в «Линуксе» для каждого запущенного процесса и содержит унаследованные переменные окружения. Так как там много ненужного нам мусора, очищаем его целиком при помощи ключа -i утилиты env.
Далее мы создаём переменную окружения seed_, а внутри её формируем небольшую программу, которая запустится до нашего кода. Для bc результат будет выглядеть так:
seed_=0123456
while(seed_--).=random()
#^@
print random()
quit()
Я развернул односрочную программу в многострочную для удобства.
Вместо 123456, конечно, будет подставлено число из переменной окружения $XDG_SESSION_ID, которая содержит число. Ноль там впереди, чтобы не случилось ничего страшного, если эта переменная в вашем дистрибутиве «Линукс» отсутствует.
Мне кажется, это неплохой способ, жаль только что содержимое $XDG_SESSION_ID остаётся одинаковым на всём протяжении жизни сессии. То есть, если запустить программу несколько раз в одном и том же окне терминала, случайные числа будут генерироваться всегда в одной и той же последовательности.
В конце файла /proc/self/environ всегда есть символ с кодом ноль, который мог бы нам всё испортить, но мы спрятали его за символом комментария — #.
Как видно, функция random() вызывается seed_ раз, что позволяет остановиться на каком-то случайном значении. Точка (.), которой я присваиваю random(), — специальная переменная bc. У неё есть значение, но, фактически, её частенько используют, чтобы присвоить куда-нибудь ненужные возвращаемые значения; иначе они попадут на экран.
Несложно додуматься до похожего способа, который позволяет читать число из какого-нибудь файла в системе. Нужно только, чтобы оно было там одно. Надо создать файл с содержимым seed_=\ и подключить его до файла с числом. Файлы подключаются через перевод строки, действие которого отменяет слеш, так что число, опять же, попадёт в переменную seed_. Дальше всё как в предыдущем примере.
есть же файл /dev/random для генерации почти честных случайных чисел:
https://ru.wikipedia.org/?title=/dev/random_%D0%B8_/dev/urandom
Есть, конечно, но чем он мне поможет-то? Числа-то там в бинарном виде и сплошным потоком. В bc это ни прочитать, ни отрезать.
вот рандом загонит в bc (thx to deepseek):
dd if=/dev/random bs=4 count=1 status=none | od -An -t u4 | bc
Мне свободный stdin нужен. Как дальше с программой-то взаимодействовать? То, что подсказал ДипСик, можно сделать куда проще: bc <<<$RANDOM.
наверное можно и в env засунуть.
кстати, оригинальная идея,в shebang вставить запуск чего-то многоэтажного. ещё не видел такого.
В env можно засунуть только значения переменных, результат выполнения программы туда не поместить. Тут подойдёт способ, который я придумал вчера, но хотелось без запуска шелла обойтись.
Не самый плохой вариант!
$ bc ––version
fish: Unknown command: bc
Надо же :-) И dc тоже нет?
https://unix.stackexchange.com/a/636196
похоже в баше таки есть таймстамп
$ echo ${EPOCHSECONDS}
1738875578
$ echo ${EPOCHREALTIME}
1738875599.715386
$ env -S -i mtest="${EPOCHSECONDS}"
mtest=1738875693
Такое только из командной строки работает, там где шелл есть. При запуске через #! строку обрабатывает сам env и такие фокусы не проходят.
А так-то и более пригодная переменная есть — $RANDOM.
неа :)
$ dc
fish: Unknown command: dc
Но вообще в арче похоже свежий bc: bc 1.08.1-1, 2025-01-05
Ещё в моём wayland этот «рандом» бы тоже работал так себе: XDG_SESSION_ID=1 :)
Это тоже очень старый, на самом деле, на «Маке» — 6.5.0. Такое ощущение, что bc на две ветки развалился — линуксовый, который не развивается, и… ну… фришный, который на «Маке»; там видно развитие.
Хах :-) А cat /proc/self/sessionid что выдаёт?
с форматирование в эгее, конечно, своя атмосфера
Какой-то сильно ограниченный маркдаун.
Похоже что в линуксе gnu bс (https://ftp.gnu.org/gnu/bc/), а у вас там bsd bc (https://git.gavinhoward.com/gavin/bc)
Тоже один, это похоже существует только для того чтобы X-овые приложения запускались в wayland и иницилизируется какой-нибудь прослойкой.
$ cat /proc/self/sessionid
1
Понятно :-) Надо ещё какую-нибудь переменную искать, в выдаче env ничего нет, содержащего только цифры?
У меня есть вот эти две, но я бы не надеялся на них (возможно что без моего терминала их не будет):
WINDOWID=108603892187776
ALACRITTY_WINDOW_ID=108603892187776
Но когда я залогинился в текстовую консоль, то стало XDG_SESSION_ID=3! Надо просто перед запуском залогиниться пару тысяч раз!
Да у меня скорее размышления и эксперименты, а не готовые решения, я всё же не учебник по bc пишу :-)