Linux shell中范围之间的随机数
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/4673830/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Random number between range in shell
提问by Adrian
How I can generate random number between 0-60 in sh (/bin/sh, not bash)? This is a satellite box, there is no $RANDOM
variable, and other goods [cksum, od (od -vAn -N4 -tu4 < /dev/urandom)].
如何在 sh(/bin/sh,而不是 bash)中生成 0-60 之间的随机数?这是一个卫星箱,没有$RANDOM
变量,其他货[cksum,od(od -vAn -N4 -tu4 < /dev/urandom)]。
I want to randomize a crontab job's time.
我想随机化 crontab 工作的时间。
采纳答案by marco
If you have tr, head and /dev/urandom, you can write this:
如果你有 tr、head 和 /dev/urandom,你可以这样写:
tr -cd 0-9 </dev/urandom | head -c 3
Then you have to use the remainder operator to put in 0-60 range.
然后您必须使用余数运算符放入 0-60 范围内。
回答by Thedward
How about using the nanoseconds of system time?
如何使用系统时间的纳秒?
date +%N
It isn't like you need cryptographically useful numbers here.
在这里您不需要加密有用的数字。
Depending on which version of /bin/sh
it is, you may be able to do:
根据它的版本/bin/sh
,您可以执行以下操作:
$(( date +%N
% 60 ))
$(( date +%N
% 60 ))
If it doesn't support the $(())
syntax, but you have dc, you could try:
如果它不支持$(())
语法,但你有 dc,你可以尝试:
dc -e `date +%N`' 60 % p'
Without knowing which operating system, version of /bin/sh
or what
tools are available it is hard to come up with a solution guaranteed to work.
在不知道/bin/sh
可用的操作系统、版本或工具的情况下,很难想出一个保证有效的解决方案。
回答by frankc
Do you have awk? You can call awk's rand() function. For instance:
你有awk吗?您可以调用 awk 的 rand() 函数。例如:
awk 'BEGIN { printf("%d\n",rand()*60) }' < /dev/null
回答by Anonymous
value=`od -An -N2 -tu2 /dev/urandom` minutes=`expr $value % 60`
The seed will be between 0 and 65535, which is not an even multiple of 60, so minutes 0-15 have a slightly greater chance ob being chosen, but the discrepancy is probably not important.
种子将在 0 到 65535 之间,这不是 60 的偶数倍,因此 0-15 分钟被选中的机会略大,但差异可能并不重要。
If you want to achieve perfection, use "od -An -N1 -tu1" and loop until value is less than 240.
如果你想达到完美,使用“od -An -N1 -tu1”并循环直到值小于240。
Tested with busybox od.
用busybox od测试。
回答by Javier Puche
Marco's answer will fail whenever generated number starts by 0 and has other digits greater than 7, as it is interpreted as octal, I would propose:
每当生成的数字以 0 开头并且其他数字大于 7 时,Marco 的答案就会失败,因为它被解释为八进制,我建议:
tr -cd 0-9 </dev/urandom | head -c 4 | sed -e 's/^00*//
specially in case you want to process it any further, for example to establish a range:
特别是如果您想进一步处理它,例如建立一个范围:
RANDOM=`tr -cd 0-9 </dev/urandom | head -c 4 | sed -e 's/^00*//'`
RND50=$((($RANDOM%50)+1)) // random number between 1 and 50
回答by Aaron Toponce
I know this post is old, but the suggested answers are not generating uniform unbiased random numbers. The accepted answer is essentially this:
我知道这篇文章很旧,但建议的答案并没有生成统一的无偏随机数。接受的答案基本上是这样的:
% echo $(( $(tr -cd 0-9 </dev/urandom | head -c 3) % 60))
The problem with this suggestion is that by choosing a 3-digit number from /dev/urandom
, the range is from 0-999, a total of 1,000 numbers. However, 1,000 does not divide into 60 evenly. As such, you'll be biased towards generating 0-959 just slightly more than 960-999.
此建议的问题在于,通过从 中选择一个 3 位数字/dev/urandom
,范围是 0-999,总共 1,000 个数字。但是,1,000 并不能平均分为 60。因此,您将倾向于生成 0-959,仅略高于 960-999。
The second answer, while creative in using nanoseconds from your clock, suffers from the same biased approach:
第二个答案虽然创造性地使用了时钟中的纳秒,但也受到了同样的偏见方法的影响:
% echo $(( $(date +%N) % 60 ))
The range for nanoseconds is 0-999,999,999, which is 1 billion numbers. So, if you're dividing that result by 60, you'll again be biased towards generating 0-999,999,959 slightly more than 999,999,960-999,999,999.
纳秒的范围是 0-999,999,999,即 10 亿个数字。因此,如果您将该结果除以 60,您将再次倾向于生成 0-999,999,959 略高于 999,999,960-999,999,999。
All the rest of the answers are the same- biased non-uniform generation.
所有其余的答案都是相同偏置的非均匀生成。
To generate unbiased uniform random numbers in the range of 0-59 (is what I assume he means rather than 0-60, if he's attempting to randomize a crontab(1)
entry), we need to force the output to be a multiple of 60.
要生成 0-59 范围内的无偏均匀随机数(我假设他的意思是 0-60,如果他试图随机化一个crontab(1)
条目),我们需要强制输出为 60 的倍数。
First, we'll generate a random 32-bit number between 0 and 4294967295:
首先,我们将生成一个介于 0 和 4294967295 之间的随机 32 位数字:
% RNUM=$(od -An -N4 -tu2 /dev/urandom | awk '{print }')
Now we'll force our range to be between $MIN and 4294967295 that is a multiple of 60:
现在我们将强制我们的范围在 $MIN 和 4294967295 之间,即 60 的倍数:
% MIN=$((2**32 % 60)) # 16
This means:
这意味着:
4294967296 - 16 = 4294967280
4294967280 / 60 = 71582788.0
In other words, my range of [16, 4294967295] is exactly a multiple of 60. So, every number I generate in that range, then divide by 60, will be equally likely as any other number. Thus, I have an unbiased generator of numbers 0-59 (or 1-60 if you add 1).
换句话说,我的范围 [16, 4294967295] 恰好是 60 的倍数。因此,我在该范围内生成的每个数字,然后除以 60,与任何其他数字的可能性相同。因此,我有一个数字 0-59(如果加 1,则为 1-60)的无偏生成器。
The only thing left to do is make sure that my number is between 16 and 4294967295. If my number is less than 16, then I'll need to generate a new number:
剩下要做的就是确保我的号码介于 16 和 4294967295 之间。如果我的号码小于 16,那么我需要生成一个新号码:
% while [ $RNUM -lt $MIN ]; do RNUM=$(od -An -N1 -tu2 /dev/urandom); done
% MINUTE=$(($RNUM % 60))
Everything put together for copy/paste goodnees:
一切为了复制/粘贴好东西放在一起:
#!/bin/bash
RNUM=$(od -An -N4 -tu2 /dev/urandom | awk '{print }')
MIN=$((2**32 % 60))
while [ $RNUM -lt $MIN ]; do RNUM=$(od -An -N1 -tu2 /dev/urandom); done
MINUTE=$(($RNUM % 60))