-1

I'd like to generate a lot of integers between 0 and 1 using bash.

I tried shuf but the generation is very slow. Is there another way to generate numbers ?

Arthur Chaloin
  • 610
  • 1
  • 5
  • 12
  • "integers between 0 and 1", you mean a random string of 0s and 1s, right? Also, google gives me $RANDOM, did you see/try that? – msb Dec 16 '16 at 22:19
  • What exactly did you use? `shuf` on its own doesn't generate anything. – choroba Dec 16 '16 at 22:20
  • Possible duplicate of [How to generate random number in Bash?](http://stackoverflow.com/questions/1194882/how-to-generate-random-number-in-bash) – msb Dec 16 '16 at 22:22
  • I tried $RANDOM too, without success. – Arthur Chaloin Dec 16 '16 at 22:29
  • 1
    The set of "integers between 0 and 1" is empty, unless those endpoints are inclusive. – Charles Duffy Dec 16 '16 at 22:29
  • 1
    what do you mean by 'without success'? it didn't generate random numbers for you? which version of bash are you using? – msb Dec 16 '16 at 22:31
  • When I said "without success" I meaned that the output number was always 1. But now it works when using /dev/urandom, thanks! – Arthur Chaloin Dec 16 '16 at 22:40
  • 1
    @ArthurChaloin, ...eh? How exactly were you using `$RANDOM` that always gave you 1? `$(( RANDOM % 2 ))` should be 1 very nearly half the time. – Charles Duffy Dec 16 '16 at 22:46
  • `$((RANDOM!=0))` maybe? It's a random number between 0 and 1 which is very probably 1 :D – Eric Duminil Dec 16 '16 at 22:50
  • @CharlesDuffy indeed, this works perfectly. I can't remember how I did to produce only 1 now, but my problem is solved. Thanks all – Arthur Chaloin Dec 17 '16 at 18:37

4 Answers4

4

This will output an infinite stream of bytes, written in binary and separated by a space :

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

As an example :

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

If you don't want spaces between bytes (thanks @Chris):

cat /dev/urandom | xxd -b | head |  cut -d" " -f 2-7 | tr -d "\n "
1000110001000101011111000010011011011111111001000000011000000100111101000001110110011011000000001101111111011000000100101001001110110001111000010100100100010110110000100111111110111011111100101000011000010010111010010001001001111000010101000110010010011011110000000011100110000000100111010001110000000011001011010101111001
Eric Duminil
  • 52,989
  • 9
  • 71
  • 124
  • You can make this a little shorter and cut out the spaces: `xxd -b < /dev/urandom | cut -d" " -f 2-7 | tr -d "\n "`. I like the efficiency of your answer though: +1 from me. – Chris Dec 16 '16 at 23:12
  • Thanks. It's a matter of taste, but I think that `|` and `<` are harder to parse, just because they break the flow of reading commands from left to right. Good tip for removing spaces, though! – Eric Duminil Dec 16 '16 at 23:20
1

tr -dc '01' < /dev/urandom is a quick and dirty way to do this.

If you're on OSX, tr can work a little weird, so you can use perl instead: perl -pe 'tr/01//dc' < /dev/urandom

Chris
  • 1,613
  • 17
  • 24
  • That's throwing away most of your entropy -- going to exhaust the pool really quickly (and get less-random numbers thereafter). – Charles Duffy Dec 16 '16 at 22:25
  • 1
    @CharlesDuffy `/dev/urandom` and `/dev/random` use a CSPRNG, and in reality you would have to take random numbers for a long, long time to exhaust available entropy. See [here](http://www.2uo.de/myths-about-urandom/). It's clearly not ideal, but it's unlikely to actually cause problems. – Chris Dec 16 '16 at 22:32
  • `/dev/random` blocking because the entropy pool isn't considered too random is a very real and common occurrence -- and reading from `/dev/urandom` drains that same pool, despite not blocking when it's empty, so you're setting up for applications that need strong pseudorandom content (key generation &c) to hang. – Charles Duffy Dec 16 '16 at 22:42
  • Yes, this command outputs less numbers than mine, but it's probably more than enough. You get my vote, because it's shorter and easier to remember. – Eric Duminil Dec 16 '16 at 22:43
  • @That's why Chris used `urandom`. – Eric Duminil Dec 16 '16 at 22:43
  • @EricDuminil, yes, I know Chris used `urandom`, but my point is that it negatively impacts *other applications on the same system* if they use `/dev/random`. – Charles Duffy Dec 16 '16 at 22:44
  • @CharlesDuffy. Okay, I answered before your edit. You have a point, but we still don't know much about the OP needs. This solution could be good enough, especially if the OP only needs a few hundred bytes worth of random data. – Eric Duminil Dec 16 '16 at 22:47
  • @CharlesDuffy Yes, that is a good point, though many applications that need randomness use `/dev/urandom` anyway (since for most such applications, blocking is not acceptable). – Chris Dec 16 '16 at 22:54
0

Just for fun --

A native-bash function to print a specified number of random bits, extracted from the smallest possible number of evaluations of $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'
}

Usage:

$ randbits 64
1011010001010011010110010110101010101010101011101100011101010010

Because this uses $RANDOM, its behavior can be made reproducible by assigning a seed value to $RANDOM before invoking it. This can be handy if you want to be able to reproduce bugs in software that uses "random" inputs.

Charles Duffy
  • 280,126
  • 43
  • 390
  • 441
0

Since the question asks for integers between 1 and 0, there is this extremely random and very fast method. A good one-liner for sure:

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

This command will give you an output similar to this when thrown inside a for loop with 10 iterations:

0.97238535471032972041395  
0.8642459339189067551494  
0.18109959700829495487820  
0.39135471514800072505703651  
0.624084503017958530984255  
0.41997456791539740171  
0.689027289676627803  
0.22698852059605560195614  
0.037745437519184791498537  
0.428629619193662260133

And if you need to print random strings of 1's and 0's, as others have assumed, you can make a slight change to the command like this:

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

Which will yield an output of random 0's and 1's similar to this when thrown into a for loop with 10 iterations:

011101001110  
001110011011  
0010100010111111  
0000001101101001111011111111  
1110101100  
00010110100  
1100101101110010  
101100110101100  
1100010100  
0000111101100010001001

To my knowledge, and from what I have found online, this is the closest to true randomness we can get in bash. I have even made a game of dice (where the dice has 10 sides 0-9) to test the randomness, using this method for generating a single number from 0 to 9. Out of 100 dice throws, each side lands almost a perfect 10 times. Out of 1000 throws, each side hits around 890-1100 times. The variation of what side lands doesn't change much after 1000 throws. So you can be very sure that this method is highly ideal, at least for bash tools generating pseudo-random numbers, for the job.

And if you need just an absolute mind-blowingly ridiculous amount of randomness, the simple md5sum checksum command can be compounded upon itself many, many times and still be very fast. As an example:

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

This will have a not-so-random number, obtained from printing the date command's nanosecond option, piped into md5sum. Then that md5 hash is piped into md5sum and then "that" hash is sent into md5sum for a last time. The output is a completely randomized hash that you can use tools like awk, sed, grep, and tr to control what you want printed.

Hope this helps.

Yokai
  • 1,170
  • 13
  • 17