【问题标题】:Optimised random number generation in bash优化 bash 中的随机数生成
【发布时间】:2017-05-02 18:24:12
【问题描述】:

我想使用 bash 生成很多介于 0 和 1 之间的整数。

我试过shuf,但是生成速度很慢。还有其他生成数字的方法吗?

【问题讨论】:

  • “0 到 1 之间的整数”,你的意思是 0 和 1 的随机字符串,对吧?另外,谷歌给了我 $RANDOM,你看到/尝试了吗?
  • 你到底用了什么? shuf 本身不会产生任何东西。
  • “0 到 1 之间的整数”集合为空,除非这些端点包含在内。
  • “没有成功”是什么意思?它没有为您生成随机数?您使用的是哪个版本的 bash?
  • @ArthurChaloin,...嗯?你究竟是如何使用总是给你1的$RANDOM$(( RANDOM % 2 )) 应该是 1 几乎一半的时间。

标签: bash random


【解决方案1】:

这将输出无限的字节流,以二进制形式写入并用空格分隔:

cat /dev/urandom | xxd -b | cut -d" " -f 2-7 | tr "\n" " "

举个例子:

10100010 10001101 10101110 11111000 10011001 01111011 11001010 00011010 11101001 01111101 10100111 00111011 10100110 01010110 11101110 01000011 00101011 10111000 01010110 10011101 01000011 00000010 10100001 11000110 11101100 11001011 10011100 10010001 01000111 01000010 01001011 11001101 11000111 11110111 00101011 00111011 10110000 01110101 01001111 01101000 01100000 11011101 11111111 11110001 10001011 11100001 11100110 10101100 11011001 11010100 10011010 00010001 00111001 01011010 00100101 00100100 00000101 10101010 00001011 10101101 11000001 10001111 10010111 01000111 11011000 01111011 10010110 00111100 11010000 11110000 11111011 00000110 00011011 11110110 00011011 11000111 11101100 11111001 10000110 11011101 01000000 00010000 00111111 11111011 01001101 10001001 00000010 10010000 00000001 10010101 11001011 00001101 00101110 01010101 11110101 10111011 01011100 00110111 10001001 00100100 01111001 01101101 10011011 00100001 01101101 01001111 01101000 00100001 10100011 00011000 01000001 00100100 10001101 10110110 11111000 01110111 10110111 11001000 00101000 01101000 01001100 10000001 11011000 11101110 11001010 10001101 00010011^C

如果您不希望字节之间有空格(感谢@Chris):

cat /dev/urandom | xxd -b | head |  cut -d" " -f 2-7 | tr -d "\n "
1000110001000101011111000010011011011111111001000000011000000100111101000001110110011011000000001101111111011000000100101001001110110001111000010100100100010110110000100111111110111011111100101000011000010010111010010001001001111000010101000110010010011011110000000011100110000000100111010001110000000011001011010101111001

【讨论】:

  • 你可以把它缩短一点并去掉空格:xxd -b < /dev/urandom | cut -d" " -f 2-7 | tr -d "\n "。不过,我喜欢您回答的效率:+1 来自我。
  • 谢谢。这是一个品味问题,但我认为|< 更难解析,只是因为它们破坏了从左到右的读取命令流。不过,删除空格的好技巧!
【解决方案2】:

tr -dc '01' < /dev/urandom 是一种快速而肮脏的方法。

如果您使用的是 OSX,tr 可能会有点奇怪,因此您可以使用 perl:perl -pe 'tr/01//dc' < /dev/urandom

【讨论】:

  • 这会浪费掉你的大部分熵——很快就会耗尽池子(然后得到更少的随机数)。
  • @CharlesDuffy /dev/urandom/dev/random 使用 CSPRNG,实际上您必须长时间获取随机数才能耗尽可用熵。见here。这显然不理想,但实际上不太可能引起问题。
  • /dev/random 阻塞,因为熵池不被认为太随机是一个非常真实和常见的情况——从/dev/urandom 读取会耗尽同一个池,尽管它在为空时不会阻塞,所以您正在为需要强伪随机内容(密钥生成等)挂起的应用程序进行设置。
  • 是的,这个命令输出的数字比我的少,但可能绰绰有余。你得到我的投票,因为它更短更容易记住。
  • @这就是克里斯使用urandom的原因。
【解决方案3】:

只是为了好玩--

一个本机 bash 函数,用于打印指定数量的随机位,从$RANDOM 的最小可能评估数量中提取:

randbits() {
  local x x_bits num_bits

  num_bits=$1

  while (( num_bits > 0 )); do
    x=$RANDOM
    x_bits="$(( x % 2 ))$(( x / 2 % 2 ))$(( x / 4 % 2 ))$(( x / 8 % 2 ))$(( x / 16 % 2 ))$(( x / 32 % 2 ))$(( x / 64 % 2 ))$(( x / 128 % 2 ))$(( x / 256 % 2 ))$(( x / 512 % 2 ))$(( x / 1024 % 2 ))$(( x / 2048 % 2 ))$(( x / 4096 % 2))$(( x / 8192 % 2 ))$(( x / 16384 % 2 ))"
    if (( ${#x_bits} < $num_bits )); then
      printf '%s' "$x_bits"
      (( num_bits -= ${#x_bits} ))
    else
      printf '%s' "${x_bits:0:num_bits}"
      break
    fi
  done
  printf '\n'
}

用法:

$ randbits 64
1011010001010011010110010110101010101010101011101100011101010010

因为它使用$RANDOM,所以它的行为可以通过在调用它之前为$RANDOM 分配一个种子值来重现。如果您希望能够在使用“随机”输入的软件中重现错误,这会很方便。

【讨论】:

    【解决方案4】:

    由于问题要求整数between 1 和0,因此有这种极其随机且非常快速的方法。肯定是一个很好的单线:

    echo "0.$(printf $(date +'%N') | md5sum | tr -d '[:alpha:][:punct:]')"
    

    当在 for 循环中抛出 10 次迭代时,此命令将为您提供与此类似的输出:

    0.97238535471032972041395  
    0.8642459339189067551494  
    0.18109959700829495487820  
    0.39135471514800072505703651  
    0.624084503017958530984255  
    0.41997456791539740171  
    0.689027289676627803  
    0.22698852059605560195614  
    0.037745437519184791498537  
    0.428629619193662260133
    

    如果您需要打印 1 和 0 的随机字符串,正如其他人所假设的那样,您可以对命令稍作更改,如下所示:

    printf $(date +'%N') | sha512sum | tr -d '[2-9][:alpha:][:punct:]'
    

    当被扔进具有 10 次迭代的 for 循环时,这将产生与此类似的随机 0 和 1 的输出:

    011101001110  
    001110011011  
    0010100010111111  
    0000001101101001111011111111  
    1110101100  
    00010110100  
    1100101101110010  
    101100110101100  
    1100010100  
    0000111101100010001001
    

    据我所知,根据我在网上找到的信息,这是我们可以在 bash 中获得的最接近真正随机性的方法。我什至做了一个骰子游戏(骰子有 10 面 0-9)来测试随机性,使用这种方法生成从 09 的单个数字。在 100 次骰子投掷中,每一方都几乎完美地落下 10 次。在 1000 次投掷中,每一方的命中次数约为 890-1100 次。投掷 1000 次后,哪边落地的变化不大。所以你可以非常确定这种方法是非常理想的,至少对于生成伪随机数的 bash 工具来说是这样。

    如果您只需要一个绝对令人难以置信的荒谬随机性,那么简单的md5sum checksum 命令可以自行组合很多次,并且仍然非常快。举个例子:

    printf $(date +'%N') | md5sum | md5sum | md5sum | tr -d '[:punct:][:space:]'
    

    这将有一个非随机数,通过打印date 命令的纳秒选项获得,并通过管道传输到md5sum。然后将该 md5 哈希通过管道传输到md5sum,然后最后一次将“那个”哈希发送到md5sum。输出是一个完全随机的哈希,您可以使用awksedgreptr 等工具来控制要打印的内容。

    希望这会有所帮助。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2021-05-23
      • 1970-01-01
      • 2017-08-05
      • 2010-11-14
      • 1970-01-01
      • 2016-12-06
      • 2013-12-04
      • 1970-01-01
      相关资源
      最近更新 更多