Generating random number between 1 and 10 in Bash Shell Script [duplicate] - bash

This question already has answers here:
Random number from a range in a Bash Script
(19 answers)
Closed 7 years ago.
How would I generate an inclusive random number between 1 to 10 in Bash Shell Script?
Would it be $(RANDOM 1+10)?

$(( ( RANDOM % 10 ) + 1 ))
EDIT. Changed brackets into parenthesis according to the comment.
http://web.archive.org/web/20150206070451/http://islandlinux.org/howto/generate-random-numbers-bash-scripting

Simplest solution would be to use tool which allows you to directly specify ranges, like gnu shuf
shuf -i1-10 -n1
If you want to use $RANDOM, it would be more precise to throw out the last 8 numbers in 0...32767, and just treat it as 0...32759, since taking 0...32767 mod 10 you get the following distribution
0-8 each: 3277
8-9 each: 3276
So, slightly slower but more precise would be
while :; do ran=$RANDOM; ((ran < 32760)) && echo $(((ran%10)+1)) && break; done

To generate random numbers with bash use the $RANDOM internal Bash function. Note that $RANDOM should not be used to generate an encryption key. $RANDOM is generated by using your current process ID (PID) and the current time/date as defined by the number of seconds elapsed since 1970.
echo $RANDOM % 10 + 1 | bc

You can also use /dev/urandom:
grep -m1 -ao '[0-9]' /dev/urandom | sed s/0/10/ | head -n1

To generate in the range: {0,..,9}
r=$(( $RANDOM % 10 )); echo $r
To generate in the range: {40,..,49}
r=$(( $RANDOM % 10 + 40 )); echo $r

Here is example of pseudo-random generator when neither $RANDOM nor /dev/urandom is available
echo $(date +%S) | grep -o .$ | sed s/0/10/

Related

Is there a way to change floating to whole number in for loop in bash

I have a bash loop that I run to copy 2 files from the hpc to my local drive recursively over the processors and all the timesteps. On the hpc the timesteps are saved as
1 2 3
whereas the bash loop interprets it as
1.0 2.0 3.0
probably because of the 0.5 increment. Is there a way to get the $j to be changed to whole number (without the decimal) when running the script?
Script I use:
for i in $(seq 0 1 23)
do
mkdir Run1/processor$i
for j in $(seq 0 0.5 10);
do
mkdir Run1/processor$i/$j
scp -r xx#login.hpc.xx.xx:/scratch/Run1/processor$i/$j/p Run1/processor$i/$j/
scp -r xx#login.hpc.xx.xx:/scratch/Run1/processor$i/$j/U Run1/processor$i/$j/
done
done
Result:
scp: /scratch/Run1/processor0/1.0/p: No such file or directory
The correct directory that exists is
/scratch/Run1/processor0/1
Thanks!
well, yes!
but: Depending on what the end result is.
I will assume you want to floor the decimal number. I can think of 2 options:
pipe the number to cut
do a little bit of perl
for i in $(seq 0 1 23); do
for j in $(seq 0 0.5 10); do
# pipe to cut
echo /scratch/Run1/processor$i/$(echo $j | cut -f1 -d".")/U Run1/processor"$i/$j"/
# pipe to perl
echo /scratch/Run1/processor$i/$(echo $j | perl -nl -MPOSIX -e 'print floor($_);')/U Run1/processor"$i/$j"/
done
done
result:
...
/scratch/Run1/processor23/9/U Run1/processor23/9/
/scratch/Run1/processor23/9/U Run1/processor23/9.5/
/scratch/Run1/processor23/9/U Run1/processor23/9.5/
/scratch/Run1/processor23/10/U Run1/processor23/10/
/scratch/Run1/processor23/10/U Run1/processor23/10/
edit :
Experimented a litle, found another way:
echo /scratch/Run1/processor$i/${j%%.[[:digit:]]}/U Run1/processor"$i/$j"/

If RANDOM only goes up to 32767, how can I generate a 9-digit random number?

How to generate 9 digit random number in shell?
I am trying something like this but it only gave numbers below 32768.
#!/bin/bash
mo=$((RANDOM%999999999))
echo "********Random"$mo
Please help
output should be ********Random453351111
In Linux with /dev/urandom:
$ rnd=$(tr -cd "[:digit:]" < /dev/urandom | head -c 9) && echo $rnd
463559879
I think this should make it
shuf -i 99999999-999999999 -n 1
As a work around, we could just simply ask for 1 random integer, for n times:
rand=''
for i in {1..9}; do
rand="${rand}$(( $RANDOM % 10 ))"
done
echo $rand
Try it online!
Note [1]: Since RANDOM's upper limit has a final digit of 7, there's a slightly lesser change for the 'generated' number to contain 8 or 9's.
Because of RANDOM's limited range, it can only be used to retrieve four base-10 digits at a time. Thus, to retrieve 9 digits, you need to call it three times.
If we don't care much about performance (are willing to pay process substitution costs), this may look like:
#!/usr/bin/env bash
get4() {
local newVal=32768
while (( newVal > 29999 )); do # avoid bias because of remainder
newVal=$RANDOM
done
printf '%04d' "$((newVal % 10000))"
}
result="$(get4)$(get4)$(get4)"
result=$(( result % 1000000000 ))
printf '%09d\n' "$result"
If we do care about performance, it may instead look like:
#!/usr/bin/env bash
get4() {
local newVal=32768 outVar=$1
while (( newVal > 29999 )); do # avoid bias because of remainder
newVal=$RANDOM
done
printf -v "$outVar" '%04d' "$((newVal % 10000))"
}
get4 out1; get4 out2; get4 out3
result="${out1}${out2}${out3}"
result=$(( result % 1000000000 ))
printf '%09d\n' "$result"
Use perl, as follows :
perl -e print\ rand | cut -c 3-11
Or
perl -MPOSIX -e 'print floor rand 10**9'

Generate uniform random number in range of floats in bash [duplicate]

This question already has answers here:
Random numbers generation with awk in BASH shell
(3 answers)
Closed 2 years ago.
[SOLVED]
I want to generate a uniform random float number in the range of float numbers in the bash script. range e.g. [3.556,6.563]
basically, I am creating LSH(Latin hypercube sampling) function in bash. There I would like to generate an array as one can do with this python command line.
p = np.random.uniform(low=l_lim, high=u_lim, size=[n]).
sample code :
lhs(){
l_lim=($(seq $1 $2 $(echo $3 - $dif | bc)))
h_lim=($(seq $(echo $1 + $dif | bc) $2 $3))
points=()
for ((i=0;i<$n;i++)) ; do
di=${l_lim[i]}
dj=${h_lim[i]}
echo $di, $dj
p=$(awk -v min=6.50 -v max=8.45 -v seed=$RANDOM 'BEGIN{srand(seed);print min+rand()*int(1000*(max-min)+1)/1000}')
points+=("${p}")
done
}
n=5
a=(3 5)
b=(1 3)
dif=$(div $(echo ${a[1]} - ${a[0]} | bc) $n)
lhs ${a[0]} 0.45 ${a[1]}
echo ${points[#]}
I have tried $RANDOM, awk but it did not work for me. I do not want to use python -c.
Most common rand() implementations at least generate a number in the range [0...1), which is really all you need. You can scale a random number in one range to a number in another using the techniques outlined in the answers to this question, eg:
NewValue = (((OldValue - OldMin) * (NewMax - NewMin)) / (OldMax - OldMin)) + NewMin
For bash you have two choices: integer arithmetic or use a different tool.
Some of your choices for tools that support float arithmetic from the command-line include:
a different shell (eg, zsh)
perl: my $x = $minimum + rand($maximum - $minimum);
ruby: x = min + rand * (max-min)
awk: awk -v min=3 -v max=17 'BEGIN{srand(); print min+rand()*int(1000*(max-min)+1)/1000}'
note: The original answer this was copied from is broken; the above is a slight modification to help correct the problem.
bc: printf '%s\n' $(echo "scale=8; $RANDOM/32768" | bc )
... to name a few.

How to sum reciprocals in bash? [duplicate]

This question already has answers here:
How do I use floating-point arithmetic in bash?
(23 answers)
Closed 4 years ago.
I am attempting to find the sum of a list of numbers' reciprocals. To illustrate what I am trying to do, here's a basic example:
With the file:
1
2
3
4
I would be trying to find the sum of 1/1, 1/2, 1/3 and 1/4. Is there a simple bash one-liner to do this? (I am new to bash, so explanations would be welcome!)
You could do something like this:
sed 's|^|1/|' file | paste -sd+ | bc -l
sed 's|^|1/|' prepends 1/ to every line
paste -sd+ joins all lines with a plus sign creating an arithmetic expression 1/1+1/2+1/3+1/4
bc -l evaluates that arithmetic expression and outputs the result
If you're looking for an arithmetical progression, you can use this bash one-liner using the bc command
d=0; for c in {1..4}; do d=`echo "$d + 1/$c" | bc -l`; done; echo "$d"
Its output is 1 + 0.5 + 0.3333 + 0.25 =
2.08333333333333333333
It works by
Setting a variable named d to 0
Creating a for loop that counts from 1 to 4
In the for loop it sets the d variable to the new value $d + 1/$c passed to the bc -l command executing the arithmetic
And outputs the value with an echo command

rounding off in bash [duplicate]

This question already has answers here:
How do I use floating-point arithmetic in bash?
(23 answers)
Closed 4 years ago.
I was taking a challenge on hackerrank .
The aim is:
read (int) N; then read N integers and print their avg to three decimal places.
Here's the code:
#!/bin/bash
#file name:rdlp.sh
read N
s=0
i=1
while (($i<=$N))
do
read a
s=$((s+a))
i=$((i+1))
done
s=$s/$N
echo "scale=3;$s"|bc -l
fi
When I run the code for some inputs:
3 #(value of N)
4 #(N = 3 integers)
4
3
Then the output is 3.666, but it should be 3.667.
So the QUESTION is that is there anyway to get it right (correct rounding off), or does it work like that only?
(the question came off when the above code was run for Testcase2 of the challenge at hackerrank)
bc rounds down with scale=x.
You can printf:
$ printf "%.3f\n" $(echo "scale=1000; 11/3"|bc -l)
3.667
or some tricky bc by adding 0.0005:
$ echo "scale=1000; v=11/3; v=v+0.0005; scale=3; v/1" | bc -l
3.667

Resources