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

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-05 02:27:23  来源:igfitidea点击:

Random number between range in shell

linuxshellrandom

提问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 $RANDOMvariable, 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/shit 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/shor 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))