1

I wrote a script with bash in while loop. The code:

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

but now I see duplicate numbers in result:

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

The numbers are duplicate.

I guess the $RANDOM changes after a invariant time and my script starts again the the while loop faster than the $RANDOM changes.

Can you help me an other randomization way?

jww
  • 97,681
  • 90
  • 411
  • 885
  • Not the most efficient, but you could read from `/dev/urandom` and filter for only-letters – knittl Aug 29 '19 at 08:25
  • 4
    Was RANDOM changed in any way before this code is executed? `man bash` warns that while RANDOM should produce a new random number each time it is referenced, it will lose this special property if it is unset at some point. Also, I [can't reproduce](https://ideone.com/l0AKzs) – Aaron Aug 29 '19 at 08:44
  • @knittl how can i use the /dev/urandom . im not pro at linux. i use debian – Ali emaditaj Aug 29 '19 at 08:55
  • all guys. i want to save the random result to a $reslut – Ali emaditaj Aug 29 '19 at 11:02

4 Answers4

3

I have tried your script and it worked fine for me.

There are many ways to generate random number in bash. One is using the /dev/random special device file. The /dev/random uses the noise collected from the device drivers and other sources to generate random data. The od (octal dump) command can extract a number of bytes and displays their decimal equivalent.

od -A n -t d -N 1 /dev/urandom

Here, -t d specifies that the output format should be signed decimal; -N 1 says to read one byte from /dev/urandom.

One other way is using the jot command:

jot -r 10 1 1000

Here we generate 10 numbers between 1 and 1000. -r specifies to generate random number.

j23
  • 3,139
  • 1
  • 6
  • 13
  • how to install jot . i didnt see that in comand list and apt install list – Ali emaditaj Aug 29 '19 at 10:37
  • Try this `sudo apt-get install athena-jot ` – j23 Aug 29 '19 at 10:41
  • how to save this random result to a Variable(i used google translate for the Variable )(the $ in bash) – Ali emaditaj Aug 29 '19 at 10:59
  • @Aliemaditaj you can use command substitution (using `resultVariable=$(command)` ) to write the result to the variable. For example, `a=$(jot -r 2 1 1000)` or `a=$(od -A n -t d -N 1 /dev/urandom)` will store the results in `a` and then `echo $a` will print the result. – j23 Aug 29 '19 at 11:09
  • it dont works at high numbers . please see this screenshot: https://ibb.co/5LDzBbq – Ali emaditaj Aug 29 '19 at 14:13
  • Pictures of text are pretty universally loathed. Maybe at this point create a new question with your *actual* requirements instead of heaping on follow-up questions in comments. – tripleee Aug 29 '19 at 14:25
1

You could use tr together with /dev/urandom:

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

Set the number of characters you want with the -c option of the head function.

To generate random digit, use another set in the tr command:

tr -dc '0-9' </dev/urandom | head -c 4; echo
oliv
  • 12,690
  • 25
  • 45
0

@j23 has given a very reasonable operational answer. By way of possible explanation of the behaviour you observed, the number you are printing is not a single $RANDOM value, but the product of two such values. Pairs of consecutive outputs of a pseudorandom number generator (PRNG) are not necessarily as independent as you might like. E.g., Matlab randn had a correlation problem in 2006 (arXiv:math/0603058).

cxw
  • 16,685
  • 2
  • 45
  • 81
0

Something like this?

#!/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

The %u conversion oddly creates really big numbers when the character code is above 0x80, and the modulo 255 of that creates a negative number, so I had to do some nonobvious workarounds to fix that. Perhaps you could come up with a less contorted way to unpack two bytes into an unsigned 15-bit number.

Here's an update which gets results in the range 200000-1000000 in the second column. It needs two additional random bytes and then performs a modulo and addition on the result to bring it into the correct range. This is outside the reach of the Bash built-in arithmetic so I used bc instead.

#!/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

This is getting pretty complex, though. If Bash is not essential for you, try this Python 3 script.

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)))
tripleee
  • 175,061
  • 34
  • 275
  • 318