2011-01-12 3 views
4

Как я могу генерировать случайное число между 0-60 в sh (/ bin/sh, not bash)? Это спутниковая коробка, нет $RANDOM переменной, а также других товаров [cksum, od (od -vAn -N4 -tu4 </dev/urandom)].sh случайное число между диапазоном

Я хочу рандомизировать время работы crontab.

ответ

6

Если тр, головы и/Dev/urandom, вы можете написать следующее:

tr -cd 0-9 </dev/urandom | head -c 3 

Тогда вы должны использовать оператор остатка положить в 0-60 диапазоне.

+0

Мне это нравится! – Adrian

+0

Ах. Я прочитал вопрос таким образом, чтобы убедиться, что/dev/urandom нет. Это отличное решение. – Thedward

+0

Я получаю 'tr: незаконная последовательность байтов' –

8

Как насчет использования наносекунд системного времени?

date +%N 

Это не похоже на криптографически полезные номера здесь.

В зависимости от версии /bin/sh она есть, вы можете быть в состоянии сделать:

$ ((date +%N% 60))

Если он не поддерживает синтаксис $(()), но у вас есть DC , вы можете попробовать:

dc -e `date +%N`' 60 % p' 

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

+0

Unfortunatelly не работал с датой, нет постоянного ../бен/ш --help /бен/ш --help BusyBox v1.15.3 (2010-07- 21 18:00:33 CEST) multi-call binary – Adrian

2

У вас есть awk? Вы можете вызвать функцию rand() awk. Например:

awk 'BEGIN { printf("%d\n",rand()*60) }' < /dev/null 
+0

Я всегда получаю номер «50» – Adrian

+1

@Adrian: Вы должны засеять генератор случайных чисел: 'awk 'BEGIN {srand(); printf ("% d \ n", rand() * 60)} ''. Переадресация не требуется, если существует только предложение BEGIN. –

+0

@Dennis, это правда, если вы планируете звонить rand() более одного раза в секунду. В противном случае srand() должен автоматически засеяться к моменту – frankc

0
value=`od -An -N2 -tu2 /dev/urandom` 
minutes=`expr $value % 60`

Семя будет находиться в диапазоне от 0 до 65535, который не является кратным 60, поэтому минут 0-15 имеет немного больше шансов быть выбранным О.Б., но расхождение, вероятно, не важно.

Если вы хотите, чтобы достичь совершенства, использовать «спосо -An -N1 -tu1» и цикл до тех пор, пока значение меньше 240.

Испытано с BusyBox ода.

0

ответ Марко потерпит неудачу, когда генерируется число начинается с 0 и имеет другие цифры больше, чем 7, как это интерпретируется как восьмеричное, я хотел бы предложить:

tr -cd 0-9 </dev/urandom | head -c 4 | sed -e 's/^00*// 

особенно в случае, если вы хотите, чтобы обработать его дальше , например, чтобы установить диапазон:

RANDOM=`tr -cd 0-9 </dev/urandom | head -c 4 | sed -e 's/^00*//'` 
RND50=$((($RANDOM%50)+1)) // random number between 1 and 50 
1

Я знаю, что этот пост старый, но предлагаемые ответы не создают единые беспристрастные случайные числа. Принятый ответ по существу это:

% echo $(($(tr -cd 0-9 </dev/urandom | head -c 3) % 60)) 

Проблема с этим предложением в том, что при выборе 3-значное число от /dev/urandom, диапазон 0-999, в общей сложности 1000 номеров. Однако 1000 не делятся на 60 равномерно. Таким образом, вы будете склонны к созданию 0-959 чуть более 960-999.

Второго ответ, в то время как творческий подход в использовании наносекунд от ваших часов, страдает от того же предвзятого подхода:

% echo $(($(date +%N) % 60)) 

Диапазона наносекунд 0-999,999,999, что на 1 млрд номеров. Итак, если вы разделите этот результат на 60, вы снова будете смещены в сторону создания 0-999,999,959 немного больше, чем 999,999,960-999,999,999.

Все остальные ответы являются одинаково предвзятыми неравномерными поколениями.

Чтобы создать непредвзятые однородные случайные числа в диапазоне 0-59 (это то, что я предполагаю, что он означает, а не 0-60, если он пытается рандомизировать запись crontab(1)), нам нужно заставить результат быть множественным 60.

Во-первых, мы будем генерировать случайные 32-разрядное число в диапазоне от 0 и 4294967295:

% RNUM=$(od -An -N4 -tu2 /dev/urandom | awk '{print $1}') 

Теперь мы заставим наш диапазон составляет от $ MIN и 4294967295, что является кратным 60:

% MIN=$((2**32 % 60)) # 16 

Это означает:

4294967296 - 16 = 4294967280 
4294967280/60 = 71582788.0 

Другими словами, мой диапазон [16, 4294967295] точно кратны 60. Таким образом, каждый номер я произвожу в этом диапазоне, а затем разделить на 60, будет в равной степени вероятно, как любое другое число. Таким образом, у меня есть несмещенный генератор чисел 0-59 (или 1-60, если вы добавите 1).

Единственное, что осталось сделать, это убедиться, что мой номер от 16 до 4294967295. Если мое число меньше 16, то мне нужно создать новый номер:

% while [ $RNUM -lt $MIN ]; do RNUM=$(od -An -N1 -tu2 /dev/urandom); done 
% MINUTE=$(($RNUM % 60)) 

Все, что положить вместе для копирования/вставки goodnees:

#!/bin/bash 
RNUM=$(od -An -N4 -tu2 /dev/urandom | awk '{print $1}') 
MIN=$((2**32 % 60)) 
while [ $RNUM -lt $MIN ]; do RNUM=$(od -An -N1 -tu2 /dev/urandom); done 
MINUTE=$(($RNUM % 60)) 
Смежные вопросы