Генерация случайных чисел в определенном диапазоне


84

Немного погуглив, я не смог найти простой способ использовать команду оболочки для генерации случайного десятичного целого числа, включенного в определенный диапазон, то есть между минимумом и максимумом.

Я читал о /dev/random, /dev/urandomи $RANDOM, но ни один из них не может сделать то, что мне нужно.

Есть ли другая полезная команда или способ использовать предыдущие данные?


2
См. Этот раздел вопросов и ответов: stackoverflow.com/questions/8988824/…, а также этот stackoverflow.com/questions/2556190/… .
SLM

Возможно , связанные с : unix.stackexchange.com/questions/42045/random-number-needed/...
ОДС

Ответы:


46

В инструментарии POSIX вы можете использовать awk:

awk -v min=5 -v max=10 'BEGIN{srand(); print int(min+rand()*(max-min+1))}'

Как не использовать его в качестве источника для генерации паролей или секретные данные , например, как и в большинстве awkреализаций, число легко можно догадаться на основе времени эта команда была запущена.

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


1
+1 .. Как используется в сценарии для назначения вывода переменной (без введения символа новой строки и использования нулевого заполнения для двух мест):x=$(awk -v min=$min_var -v max=$max_var 'BEGIN{srand(); printf("%.2d", int(min+rand()*(max-min+1)))}')
Кристофер

Это основано на времени? так как я получил то же значение в 2 последовательных прогонах ...
Шай Алон

@ShaiAlon текущее время часто используется как начальное значение по умолчанию для srand (), поэтому обычно да, оно основано на времени, см. Предложение Стефана об этом в его ответе. Вы можете обойти это, изменив начальное начальное число на случайное число с помощью awk -v min=5 -v max=10 -v seed="$(od -An -N4 -tu4 /dev/urandom)" 'BEGIN{srand(seed+0); print int(min+rand()*(max-min+1))}'. Вы можете использовать $RANDOMвместо, od ... /dev/randomно тогда ваше начальное значение находится в относительно небольшом диапазоне от 0 до 32767, и, таким образом, вы, вероятно, получите заметные повторения в выходных данных со временем.
Эд Мортон

142

Вы можете попробовать shufиз GNU coreutils:

shuf -i 1-100 -n 1

Это также работает с Busybox shuf.
СОУ

Работает также в raspbian и GitBash.
nPcomp

30

йота

В BSD и OSX вы можете использовать jot для возврата единственного числа random ( -r) из интервала minв maxвключительно.

$ min=5
$ max=10
$ jot -r 1 $min $max

Проблема распределения

К сожалению, на диапазон и распределение случайно сгенерированных чисел влияет тот факт, что jot внутренне использует арифметику с плавающей запятой двойной точности и printf (3) для формата вывода, что вызывает проблемы с округлением и усечением. Поэтому интервалы minи maxгенерируются реже, как показано:

$ jot -r 100000 5 10 | sort -n | uniq -c
9918  5
20176 6
20006 7
20083 8
19879 9
9938  10

На OS X 10.11 (El Capitan) это, кажется, было исправлено:

$ jot -r 100000 5 10 | sort -n | uniq -c
16692 5
16550 6
16856 7
16579 8
16714 9
16609 10  

а также...

$ jot -r 1000000 1 10 | sort -n | uniq -c
100430 1
99965 2
99982 3
99796 4
100444 5
99853 6
99835 7
100397 8
99588 9
99710 10

Решение проблемы распределения

Для более старых версий OS X, к счастью, есть несколько обходных путей. Одним из них является использование printf (3) целочисленного преобразования. Единственное предостережение в том, что максимальный интервал теперь становится max+1. Используя целочисленное форматирование, мы получаем справедливое распределение по всему интервалу:

$ jot -w %i -r 100000 5 11 | sort -n | uniq -c
16756 5
16571 6
16744 7
16605 8
16683 9
16641 10

Идеальное решение

И, наконец, чтобы получить правильное бросок костей с помощью обходного пути, мы имеем:

$ min=5
$ max_plus1=11  # 10 + 1
$ jot -w %i -r 1 $min $max_plus1

Дополнительная домашняя работа

См. Jot (1) для подробной информации о математике и форматировании, а также многих других примеров.


15

$RANDOMПеременный обычно не является хорошим способ генерируемых хороших случайных значений. Выходные данные /dev/[u]randomнеобходимо также преобразовать в первую очередь.

Проще всего использовать языки более высокого уровня, например, python:

Чтобы сгенерировать случайную целочисленную переменную от 5 до 10 (5 <= N <= 10), используйте

python -c "import random; print random.randint(5,10)"

Не используйте это для криптографических приложений.


Это было полезно. Большое спасибо :) Поскольку подпись часто работала с Unix-> Solaris 10, утилиты GNU по умолчанию не интегрированы. Это сработало однако.
терпение

11

Вы можете получить случайное число через urandom

head -200 /dev/urandom | cksum

Выход:

3310670062 52870

Чтобы получить одну часть вышеуказанного номера.

head -200 /dev/urandom | cksum | cut -f1 -d " "

Тогда вывод

3310670062


head -200(или его эквивалент POSIX head -n 100) возвращает первые 200 строк из /dev/urandom. /dev/urandomэто не текстовый файл, эта команда может возвращать от 200 байтов (все 0x0a, LF в ASCII) до бесконечности (если байт 0xa никогда не возвращается), но значения между 45k и 55k являются наиболее вероятными. cksum возвращает 32-битное число, поэтому бессмысленно получать более 4 байтов /dev/urandom.
Стефан Шазелас

7

Чтобы сгенерировать случайную целочисленную переменную от 5 до 10 (включая оба), используйте

echo $(( RANDOM % (10 - 5 + 1 ) + 5 ))

% работает как оператор по модулю.

Вероятно, есть более эффективные способы преобразования случайной величины $RANDOMв определенный диапазон. Не используйте это для криптографических приложений или в случаях, когда вам нужны реальные, равномерно распределенные случайные величины (например, для моделирования).


3
Во многих реализациях оболочки, которые имеют $ RANDOM (особенно старые, особенно bash), это не очень случайно. В большинстве оболочек это число находится в диапазоне от 0 до 65535, поэтому любой диапазон, ширина которого не является степенью двойки, будет иметь дискретность распределения вероятностей. (в этом случае числа с 5 по 8 будут иметь вероятность 10923/65536, а у 9 и 10 будет вероятность 10922/65536). Чем шире диапазон, тем больше дискретность.
Стефан Шазелас

Извините, это 32767, а не 65535, поэтому приведенный выше расчет неверен (и на самом деле он хуже).
Стефан Шазелас

@ StéphaneChazelas Я имел в виду это, когда писал, что есть лучшие способы ...
jofel

5

# echo $(( $RANDOM % 256 )) выдаст «случайное» число от 0 до 255 на современных диалектах.


Похож на этот другой ответ от 2 лет назад.
Джефф Шаллер

1
Это зависит от проблемы с «голубым отверстием» (TL; DR: некоторые результаты более вероятны, чем другие), если вместо 256 вы используете значение, которое не делит 32768 поровну.
toon81

4

Может быть UUID(в Linux) можно использовать для получения случайного числа

$ cat /proc/sys/kernel/random/uuid
cdd52826-327d-4355-9737-895f58ad11b4

Чтобы получить случайное число между 70и100

POSIXLY_CORRECT=1 awk -F - '{print(("0x"$1) % 30 + 70)}
   ' /proc/sys/kernel/random/uuid

3
cat /dev/urandom | tr -dc 'a-fA-F0-9' | fold -w 8 | head -n 1

Это сгенерирует шестнадцатеричное число длиной 8 цифр.


1

Чтобы полностью остаться в bash и использовать переменную $ RANDOM, но избегайте неравномерного распределения:

#!/bin/bash
range=10 
floor=20

if [ $range -gt 32768 ]; then
echo 'range outside of what $RANDOM can provide.' >&2
exit 1 # exit before entering infinite loop
fi 

max_RANDOM=$(( 2**15/$range*$range ))
r=$RANDOM
until [ $r -lt $max_RANDOM ]; do
r=$RANDOM
done
echo $(( r % $range + $floor ))

Этот пример предоставит случайные числа от 20 до 29.


$rследует инициализировать до 65535 или другого высокого значения, чтобы избежать [: -lt: unary operator expectedошибки.
LawrenceC

Исправлена ​​инициализация $ r перед проверкой цикла. Спасибо @LawrenceC!
Чем Энджелл

0

Распределение это хорошо:

for ((i = 1; i <= 100000; i ++)) do echo $ ((RANDOM% (20 - 10 + 1) + 10)); сделано | сортировать -n | uniq -c

значение счета

9183 10

9109 11

8915 12

9037 13

9100 14

9138 15

9125 16

9261 17

9088 18

8996 19

9048 20

Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.