如何在sh(/bin/sh,不是bash)中生成0-60之间的随机数?这是一个卫星盒,没有$RANDOM变量,其他商品[cksum,od(od -货车-N4 -tu 4〈/dev/urandom)]。我想随机化一个crontab作业的时间。
$RANDOM
ql3eal8s1#
如果你有tr、head和/dev/urandom,你可以这样写:
tr -cd 0-9 </dev/urandom | head -c 3
然后你必须使用余数运算符把0-60的范围。
iklwldmw2#
如何使用系统时间的纳秒?
date +%N
这里不需要密码学上有用的数字。根据/bin/sh的版本,您可以执行以下操作:$((date +%N % 60))如果它不支持$(())语法,但你有dc,你可以尝试:
/bin/sh
$(())
dc -e `date +%N`' 60 % p'
如果不知道哪个操作系统、/bin/sh的版本或可用的工具,很难提出保证有效的解决方案。
xj3cbfub3#
我知道这篇文章已经很老了,但建议的答案并不是产生均匀无偏的随机数。公认的答案基本上是这样的:
% echo $(( $(tr -cd 0-9 </dev/urandom | head -c 3) % 60))
这个建议的问题是,通过从/dev/urandom中选择一个3位数,范围是从0到999,总共1,000个数字。然而,1,000不能平均分为60。因此,您将偏向于生成0-959,而不是960-999。第二个答案,虽然创造性地使用了你的时钟的纳秒,但也有同样的偏见:
/dev/urandom
% echo $(( $(date +%N) % 60 ))
纳秒的范围是0- 999,999,999,这是10亿个数字。因此,如果将结果除以60,您将再次偏向于生成0- 999,999,959略高于999,999,960 - 999,999,999。所有其余的答案都是相同的--有偏见的非均匀生成。要生成0-59范围内的无偏均匀随机数(我假设他的意思是0-60,如果他试图随机化crontab(1)条目),我们需要强制输出为60的倍数。首先,我们将生成一个介于0和4294967295之间的随机32位数:
crontab(1)
% 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))
watbbzwu4#
你有awk吗?你可以调用awk的兰德()函数。例如:
awk 'BEGIN { printf("%d\n",rand()*60) }' < /dev/null
bqjvbblv5#
value=`od -An -N2 -tu2 /dev/urandom` minutes=`expr $value % 60`
种子将在0和65535之间,这不是60的偶数倍,因此分钟0-15具有稍大的机会ob被选择,但是差异可能并不重要。如果你想达到完美,使用“od -An -N1 -tu 1”并循环直到值小于240。使用busybox od测试。
rseugnpd6#
当生成的数字从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
v2g6jxz67#
经过一年的使用投票最高的解决方案,从这个线程,在Shell中生成一个范围之间的随机数,我已经证实,正如@Aaron Toponce所建议的那样,这种方法是有偏差的,不是均匀随机的。在范围1-65535中,以下数字随机生成不超过一次(在一年内):3、4、6、7、9、13、17、19、20、21、58080、60020、60443、61532、61900、62078、63331、64623、64680、65000、65129、65389。请注意,这些数字是范围的钟形曲线上的统计异常值。相反,同样的方法有一种趋势,即在钟形曲线内“随机”生成公共数字,其中某些频率被证明对于生产实施是不可靠的。同时,仍然在寻找一个纯Shell解决方案,该解决方案生成一个范围之间的随机数,这不需要替代应用程序。
7条答案
按热度按时间ql3eal8s1#
如果你有tr、head和/dev/urandom,你可以这样写:
然后你必须使用余数运算符把0-60的范围。
iklwldmw2#
如何使用系统时间的纳秒?
这里不需要密码学上有用的数字。
根据
/bin/sh
的版本,您可以执行以下操作:$((
date +%N
% 60))如果它不支持
$(())
语法,但你有dc,你可以尝试:如果不知道哪个操作系统、
/bin/sh
的版本或可用的工具,很难提出保证有效的解决方案。xj3cbfub3#
我知道这篇文章已经很老了,但建议的答案并不是产生均匀无偏的随机数。公认的答案基本上是这样的:
这个建议的问题是,通过从
/dev/urandom
中选择一个3位数,范围是从0到999,总共1,000个数字。然而,1,000不能平均分为60。因此,您将偏向于生成0-959,而不是960-999。第二个答案,虽然创造性地使用了你的时钟的纳秒,但也有同样的偏见:
纳秒的范围是0- 999,999,999,这是10亿个数字。因此,如果将结果除以60,您将再次偏向于生成0- 999,999,959略高于999,999,960 - 999,999,999。
所有其余的答案都是相同的--有偏见的非均匀生成。
要生成0-59范围内的无偏均匀随机数(我假设他的意思是0-60,如果他试图随机化
crontab(1)
条目),我们需要强制输出为60的倍数。首先,我们将生成一个介于0和4294967295之间的随机32位数:
现在我们将强制我们的范围在$MIN和4294967295之间,这是60的倍数:
这意味着:
换句话说,我的区间[16,4294967295]正好是60的倍数。因此,我在该区间生成的每个数字,然后除以60,将与任何其他数字一样可能。因此,我有一个无偏的数字生成器0-59(或1-60,如果你加1)。
剩下唯一要做的就是确保我的号码在16和4294967295之间。如果我的号码小于16,那么我需要生成一个新号码:
一切放在一起复制/粘贴goodnees:
watbbzwu4#
你有awk吗?你可以调用awk的兰德()函数。例如:
bqjvbblv5#
种子将在0和65535之间,这不是60的偶数倍,因此分钟0-15具有稍大的机会ob被选择,但是差异可能并不重要。
如果你想达到完美,使用“od -An -N1 -tu 1”并循环直到值小于240。
使用busybox od测试。
rseugnpd6#
当生成的数字从0开始并且有大于7的其他数字时,请注意错误,因为它被解释为八进制,我建议:
特别是如果你想进一步处理它,例如建立一个范围:
v2g6jxz67#
经过一年的使用投票最高的解决方案,从这个线程,在Shell中生成一个范围之间的随机数,我已经证实,正如@Aaron Toponce所建议的那样,这种方法是有偏差的,不是均匀随机的。在范围1-65535中,以下数字随机生成不超过一次(在一年内):3、4、6、7、9、13、17、19、20、21、58080、60020、60443、61532、61900、62078、63331、64623、64680、65000、65129、65389。请注意,这些数字是范围的钟形曲线上的统计异常值。相反,同样的方法有一种趋势,即在钟形曲线内“随机”生成公共数字,其中某些频率被证明对于生产实施是不可靠的。同时,仍然在寻找一个纯Shell解决方案,该解决方案生成一个范围之间的随机数,这不需要替代应用程序。