在Bash中使用$ RANDOM重复编号

时间:2019-08-29 07:53:50

标签: linux bash random debian

我在while循环中用bash编写了一个脚本。代码:

number=0
while [ 1500 -gt $number ]
do
  var="abcdefghijklmnopqrstuvxyz"
  letter1="${var:$(( RANDOM % ${#var} )):1}"
  letter2="${var:$(( RANDOM % ${#var} )):1}"
  a=$RANDOM
  b=$RANDOM
  c=$(( $a * $b))
  echo "$letter1$letter2 $c" >> a.txt
  number=$(( 1 + $number ))
done

但是现在我看到重复的数字:

Result:
ab 15474
at 15474
yh 15474
gd 15474
re 18696
jg 18696

数字重复。

我猜想$RANDOM的变化是不变的,我的脚本再次启动while循环的速度比$RANDOM的变化快。

您能帮我另一种随机方法吗?

4 个答案:

答案 0 :(得分:3)

我已经尝试过您的脚本,并且对我来说效果很好。

bash中有许多generate random number的方式。一种是使用@Service public class RecordsTrackerService { private RestTemplate restTemplate; @Autowired public RecordsTrackerService(RestTemplate restTemplate) { this.restTemplate = restTemplate; } public void updateRecords() { Object obj = restTemplate.getForObject("sample_url", Object.class); } } 特殊设备文件。 /dev/random使用从设备驱动程序和其他来源收集的噪声来生成随机数据。 od(八进制转储)命令可以提取多个字节并显示其十进制等效项。

/dev/random

在这里od -A n -t d -N 1 /dev/urandom 指定输出格式应为十进制符号; -t d说要从/ dev / urandom中读取一个字节。

另一种方法是使用-N 1命令:

jot

这里我们生成10个介于1和1000之间的数字。jot -r 10 1 1000 指定生成随机数。

答案 1 :(得分:1)

您可以将tr/dev/urandom一起使用:

tr -dc 'a-z' </dev/urandom | head -c 2; echo

使用-c函数的head选项设置所需的字符数。

要生成随机数字,请在tr命令中使用另一组数字:

tr -dc '0-9' </dev/urandom | head -c 4; echo

答案 2 :(得分:0)

@ j23提供了一个非常合理的操作答案。通过对观察到的行为的可能解释,您打印的数字不是单个$RANDOM值,而是两个此类值的乘积。伪随机数生成器(PRNG)的成对连续输出不一定像您想要的那样独立。例如,Matlab randn在2006年遇到了关联问题(arXiv:math / 0603058)。

答案 3 :(得分:0)

像这样吗?

#!/bin/bash
export LC_ALL=C
for((i=0; i<1500; ++i)); do
    IFS='' read -n 4 -d '' bytes
    # https://stackoverflow.com/questions/28476611/ord-and-chr-a-file-in-bash
    printf -v a %u "'${bytes:2:1}"
    a=$((a%255))
    printf -v b %u "'${bytes:3:1}"
    b=$((b%255))
    printf "%s %s\n" "$(
        tr '\000-\011\013-\140\173-\377' 'a-za-za-za-za-za-za-za-za-z' <<<"${bytes:0:2}"
    )" $((${a#-}*${b#-}))
done</dev/urandom

当字符代码在0x80以上时,%u转换会奇怪地创建很大的数字,而其模数255会生成一个负数,因此我不得不采取一些非显而易见的解决方法来解决该问题。也许您可以想出一种比较简单的方法来将两个字节解压缩为一个无符号的15位数字。

这是第二行中的更新,其结果范围为200000-1000000。它需要两个额外的随机字节,然后对结果进行取模和加法运算,以使其达到正确的范围。这是Bash内置算法无法实现的,因此我改用bc

#!/bin/bash
export LC_ALL=C
for((i=0; i<1500; ++i)); do
    IFS='' read -n 6 -d '' bytes
    # https://stackoverflow.com/questions/28476611/ord-and-chr-a-file-in-bash
    printf -v a %u "'${bytes:2:1}"
    a=$((a%255))
    printf -v b %u "'${bytes:3:1}"
    b=$((b%255))
    printf -v c %u "'${bytes:4:1}"
    c=$((c%255))
    printf -v d %u "'${bytes:5:1}"
    d=$((d%255))
    printf "%s %s\n" "$(
        tr '\000-\011\013-\140\173-\377' 'a-za-za-za-za-za-za-za-za-z' <<<"${bytes:0:2}"
    )" $(bc <<<"((${a#-}*${b#-}*${c#-}*${d#-})%800000)+200000")
done</dev/urandom

这变得非常复杂。如果Bash对您不是必需的,请尝试使用此Python 3脚本。

from random import choice, randrange
from string import ascii_lowercase

for r in range(1500):
  print('{0}{1} {2}'.format(
    choice(ascii_lowercase),
    choice(ascii_lowercase),
    200000+randrange(999999800000)))