ProgrammingThis forum is for all programming questions.
The question does not have to be directly related to Linux and any language is fair game.
Notices
Welcome to LinuxQuestions.org, a friendly and active Linux Community.
You are currently viewing LQ as a guest. By joining our community you will have the ability to post topics, receive our newsletter, use the advanced search, subscribe to threads and access many other special features. Registration is quick, simple and absolutely free. Join our community today!
Note that registered members see fewer ads, and ContentLink is completely disabled once you log in.
If you have any problems with the registration process or your account login, please contact us. If you need to reset your password, click here.
Having a problem logging in? Please visit this page to clear all LQ-related cookies.
Get a virtual cloud desktop with the Linux distro that you want in less than five minutes with Shells! With over 10 pre-installed distros to choose from, the worry-free installation life is here! Whether you are a digital nomad or just looking for flexibility, Shells can put your Linux machine on the device that you want to use.
Exclusive for LQ members, get up to 45% off per month. Click here for more info.
Distribution: Slackware (personalized Window Maker), Mint (customized MATE)
Posts: 1,309
Rep:
Tossing coins with Bash and awk
I'm writing Bash script and I'd like to generate some random numbers with it. Instead of using Bash mechanisms I'd like to embed in that script small sequence in awk. Awk offers better randomness than Bash.
With awk script everything works well:
$ cat coin.awk
Code:
#!/usr/bin/awk -f
BEGIN {
srand()
for ( i = 1; i <= 1000; i++ )
print int ( rand() * 2 + 1 )
}
When I embed the above awk command into Bash script it displays long sequences of the same numbers:
$ cat coin.sh
Code:
#!/bin/sh
for step in `seq 1000`
do
echo | awk "{ srand(); print int ( rand() * 2 + 1 ) }"
done
Is there any method to use awk randomness in Bash script?
srand uses the time/date to seed. The loop given is processed very quickly and I do believe the seed stays the same during the loop.
Here's an example:
Code:
#!/bin/sh
for step in `seq 10`
do
awk '
BEGIN {
srand()
print int(1 + rand() * 100)
}'
sleep 1
done
This will generate 10 random numbers every time it is run. Remove the sleep 1 and the same 'random' number is printed 10 times, but the next run it will be a different number (small chance it will be the same).
I'm not sure if this is a working solution if you need 1000 random numbers, but it does explain the behavior.
@ghostdog74: if the output is needed in the (bash) script I can see that a construct as mentioned by the OP is needed, or all should be done with awk (which could be a challenge for some).
Anyway, I have a workaround for the problem:
Code:
#!/bin/sh
for step in `seq 10`
do
nanosectime=`date '+%N'`
awk -v NST=$nanosectime '
BEGIN {
srand(NST)
print int(1 + rand() * 100)
}'
done
All that is needed is a more precise seed, which date can provide. The %N option print the nanoseconds.
@ghostdog74: if the output is needed in the (bash) script I can see that a construct as mentioned by the OP is needed, or all should be done with awk (which could be a challenge for some).
well, its a challenge to some in learning bash as well.. especially with its clumsy syntax for arrays, its non support for maths floating point, its difference between [[ and [ when using if/else, and a whole bunch of other little annoyances as well.
Quote:
Anyway, I have a workaround for the problem:
Code:
#!/bin/sh
for step in `seq 10`
do
nanosectime=`date '+%N'`
awk -v NST=$nanosectime '
BEGIN {
srand(NST)
print int(1 + rand() * 100)
}'
done
All that is needed is a more precise seed, which date can provide. The %N option print the nanoseconds.
Hope this helps.
the issue with this construct, is if you need more than 10 rand numbers eg 1000, then you are calling awk 1000 times...which is much slower than use awk itself. In this case, i would not do it in bash.
Last edited by ghostdog74; 06-03-2009 at 06:12 AM.
@ghostdog74: if the output is needed in the (bash) script I can see that a construct as mentioned by the OP is needed, or all should be done with awk (which could be a challenge for some).
Anyway, I have a workaround for the problem:
Code:
#!/bin/sh
for step in `seq 10`
do
nanosectime=`date '+%N'`
awk -v NST=$nanosectime '
BEGIN {
srand(NST)
print int(1 + rand() * 100)
}'
done
All that is needed is a more precise seed, which date can provide. The %N option print the nanoseconds.
Hope this helps.
Or you could use urandom for even more randomness:
Code:
for i in $(seq 1 10); do od -N1 -tu /dev/urandom | head -n1 | awk '{ srand($2); print int(1 + rand() * 100) }'; done
Distribution: Slackware (personalized Window Maker), Mint (customized MATE)
Posts: 1,309
Original Poster
Rep:
@druuna (first post)
Slowing down the script with sleep is useless in my case. I’m testing different methods of generating random numbers with Bash scripts and I’m comparing the time of the execution of these scripts.
@ghostdog74 (first post)
I don’t see the difference between your script and my script.
@druuna (second post)
Great idea! Thank you very much!
@ghostdog74 (third post)
In fact I’m learning now Bash. I’m aware of its weaknesses but I think it’s good to know basic scripting language in Linux.
@H_TeXMeX_H (first post)
Nice example! I tried to read /dev/urandom but I used wrong method. Thank you very much!
Distribution: Slackware (personalized Window Maker), Mint (customized MATE)
Posts: 1,309
Original Poster
Rep:
Quote:
Originally Posted by bigearsbilly
you could also use $RANDOM in a bash shell script
I used everything possible during testing these scripts and $RANDOM among the other constructions. I had problem with embedding awk command into Bash script. I resolved it thanks to druuna and H_TeXMeX_H.
Now I see the difference. I tried it for two numbers and you tried it for one hundred of numbers.
no, that's not what i meant.. i meant the code where you use a for loop with the seq and calling awk with it, remember??? That's the difference. you don't need to use bash and seq with what you are doing and calling awk 1000 times.... simply do it in awk. that's all.
Last edited by ghostdog74; 06-03-2009 at 08:19 PM.
Distribution: Slackware (personalized Window Maker), Mint (customized MATE)
Posts: 1,309
Original Poster
Rep:
Quote:
Originally Posted by ghostdog74
you don't need to use bash and seq with what you are doing and calling awk 1000 times.... simply do it in awk. that's all.
As you saw in my first post I knew that method. The problem which disturbed me was how to embed awk code in Bash script. Using awk code inside awk is simple.
LinuxQuestions.org is looking for people interested in writing
Editorials, Articles, Reviews, and more. If you'd like to contribute
content, let us know.