【发布时间】:2021-02-24 04:59:22
【问题描述】:
如何在 sh(/bin/sh,而不是 bash)中生成 0-60 之间的随机数?这是卫星箱,没有$RANDOM变量,其他货[cksum,od(od -vAn -N4 -tu4/urandom)]。
我想随机化一个 crontab 作业的时间。
【问题讨论】:
如何在 sh(/bin/sh,而不是 bash)中生成 0-60 之间的随机数?这是卫星箱,没有$RANDOM变量,其他货[cksum,od(od -vAn -N4 -tu4/urandom)]。
我想随机化一个 crontab 作业的时间。
【问题讨论】:
如果你有 tr、head 和 /dev/urandom,你可以这样写:
tr -cd 0-9 </dev/urandom | head -c 3
那么你必须使用余数运算符来输入 0-60 范围。
【讨论】:
tr: illegal byte sequence
使用纳秒的系统时间怎么样?
date +%N
这里不需要加密有用的数字。
根据/bin/sh 的版本,您可能可以这样做:
$((date +%N%60))
如果它不支持$(())语法,但你有dc,你可以试试:
dc -e `date +%N`' 60 % p'
不知道哪个操作系统、/bin/sh 的版本或什么
工具是可用的,很难想出一个保证有效的解决方案。
【讨论】:
你有 awk 吗?您可以调用 awk 的 rand() 函数。例如:
awk 'BEGIN { printf("%d\n",rand()*60) }' < /dev/null
【讨论】:
awk 'BEGIN { srand(); printf("%d\n",rand()*60) }'。如果只有BEGIN 子句,则不需要重定向。
awk 'BEGIN {print rand(), rand()}'; sleep 3; awk 'BEGIN {print rand(), rand()}' 两次为 GNU awk 和 BusyBox awk 提供了相同的一对值(不同版本的值不同)。如果我包含srand(),即使我删除了sleep,值也会有所不同。必须显式地播种随机数生成器并不罕见。部分原因是您可以在测试期间获得可预测的序列。
我知道这篇文章很旧,但建议的答案不会生成统一的无偏随机数。接受的答案基本上是这样的:
% echo $(( $(tr -cd 0-9 </dev/urandom | head -c 3) % 60))
这个建议的问题是,通过从/dev/urandom中选择一个3位数字,范围是0-999,一共1000个数字。但是,1,000 并不能平均分为 60。因此,您将偏向于生成 0-959,略高于 960-999。
第二个答案虽然创造性地使用时钟中的纳秒,但也存在同样的偏见:
% echo $(( $(date +%N) % 60 ))
纳秒的范围是 0-999,999,999,即 10 亿个数字。因此,如果您将该结果除以 60,您将再次倾向于生成 0-999,999,959,略多于 999,999,960-999,999,999。
其余所有答案都是相同的偏向非均匀生成。
要生成 0-59 范围内的无偏均匀随机数(如果他试图随机化 crontab(1) 条目,我认为他的意思是他的意思而不是 0-60),我们需要强制输出为60 的倍数。
首先,我们将生成一个介于 0 和 4294967295 之间的 32 位随机数:
% 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,则为 1-60)的无偏生成器。
剩下要做的就是确保我的号码在 16 到 4294967295 之间。如果我的号码小于 16,那么我需要生成一个新号码:
% while [ $RNUM -lt $MIN ]; do RNUM=$(od -An -N1 -tu2 /dev/urandom); done
% MINUTE=$(($RNUM % 60))
所有东西都放在一起复制/粘贴好东西:
#!/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))
【讨论】:
值=`od -An -N2 -tu2 /dev/urandom` 分钟=`expr $value % 60`
种子将介于 0 和 65535 之间,这不是 60 的偶数倍,因此选择 0-15 分钟的 ob 的机会稍大一些,但差异可能并不重要。
如果你想达到完美,使用“od -An -N1 -tu1”并循环直到值小于240。
用busybox od测试。
【讨论】:
当生成的数字以 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
【讨论】: