21

How can print a value, either 1, 2 or 3 (at random). My best guess failed:

#!/bin/bash

1 = "2 million"
2 = "1 million"
3 = "3 million"

print randomint(1,2,3)
Ciro Santilli OurBigBook.com
  • 347,512
  • 102
  • 1,199
  • 985
Switchkick
  • 2,716
  • 6
  • 21
  • 28

5 Answers5

30

To generate random numbers with bash use the $RANDOM internal Bash function:

arr[0]="2 million"
arr[1]="1 million"
arr[2]="3 million"

rand=$[ $RANDOM % 3 ]
echo ${arr[$rand]}

From bash manual for RANDOM:

Each time this parameter is referenced, a random integer between 0 and 32767 is generated. The sequence of random numbers may be initialized by assigning a value to RANDOM. If RANDOM is unset,it loses its special properties, even if it is subsequently reset.

codaddict
  • 445,704
  • 82
  • 492
  • 529
  • 3
    `$[ ]` is a compatibility construct to support 1970s-era Bourne syntax; that construct is *not* found in more recent standards, and thus not guaranteed to be supported by more modern shells other than bash (which has historically included it). Since 1991, when POSIX sh was published, the *standardized* math construct has been `$(( ))`, so this should be `rand=$(( RANDOM % 3 ))`. – Charles Duffy Jan 23 '17 at 22:47
  • I would also suggest quoting -- as in, `echo "${arr[$rand]}"`; that way we won't have unexpected behavior with different values in IFS, or with array values that expand as globs. (For instance, if `IFS=0123456789`, then `echo ${arr[$rand}` without the quotes wouldn't print any number at all). – Charles Duffy Jan 23 '17 at 22:50
  • 1
    How about rand=$[ $RANDOM % ${#arr[@]} ] to avoid hardcoding 3? – David Airapetyan Sep 06 '19 at 17:32
9

Coreutils shuf

Present in Coreutils, this function works well if the strings don't contain newlines.

E.g. to pick a letter at random from a, b and c:

printf 'a\nb\nc\n' | shuf -n1

POSIX eval array emulation + RANDOM

Modifying Marty's eval technique to emulate arrays (which are non-POSIX):

a1=a
a2=b
a3=c
eval echo \$$(expr $RANDOM % 3 + 1)

This still leaves the RANDOM non-POSIX.

awk's rand() is a POSIX way to get around that.

Ciro Santilli OurBigBook.com
  • 347,512
  • 102
  • 1,199
  • 985
  • what is "shuf"; linux? i don't see it on mac osx, and arrays are so ugly. see following answer – Marty McGowan Apr 28 '15 at 12:41
  • @MartyMcGowan GNU non-POSIX as linked. Agree that arrays are ugly, but first option with shuf does not use the arrays. Agree that greater portability would be cool. I didn't know `set` could set the arguments as you proposed, that's interesting. – Ciro Santilli OurBigBook.com Apr 28 '15 at 12:56
5

64 chars alpha numeric string

randomString32() {
    index=0
    str=""

    for i in {a..z}; do arr[index]=$i; index=`expr ${index} + 1`; done
    for i in {A..Z}; do arr[index]=$i; index=`expr ${index} + 1`; done
    for i in {0..9}; do arr[index]=$i; index=`expr ${index} + 1`; done
    for i in {1..64}; do str="$str${arr[$RANDOM%$index]}"; done

    echo $str
}
ByteHamster
  • 4,884
  • 9
  • 38
  • 53
1
~.$ set -- "First Expression" Second "and Last"
~.$ eval echo \$$(expr $RANDOM % 3 + 1)
and Last
~.$ 
Marty McGowan
  • 356
  • 2
  • 10
1

Want to corroborate using shuf from coreutils using the nice -n1 -e approach.

Example usage, for a random pick among the values a, b, c:

CHOICE=$(shuf -n1 -e a b c)
echo "choice: $CHOICE"

I looked at the balance for two samples sizes (1000, and 10000):

$ for lol in $(seq 1000); do shuf -n1 -e a b c; done > shufdata
$ less shufdata | sort | uniq -c
    350 a
    316 b
    334 c
$ for lol in $(seq 10000); do shuf -n1 -e a b c; done > shufdata
$ less shufdata | sort | uniq -c
   3315 a
   3377 b
   3308 c

Ref: https://www.gnu.org/software/coreutils/manual/html_node/shuf-invocation.html

Dr. Jan-Philip Gehrcke
  • 33,287
  • 14
  • 85
  • 130