LinuxQuestions.org
Visit Jeremy's Blog.
Home Forums Tutorials Articles Register
Go Back   LinuxQuestions.org > Forums > Non-*NIX Forums > Programming
User Name
Password
Programming This forum is for all programming questions.
The question does not have to be directly related to Linux and any language is fair game.

Notices


Reply
  Search this Thread
Old 06-03-2009, 04:34 AM   #1
w1k0
Senior Member
 
Registered: May 2008
Location: Poland
Distribution: Slackware (personalized Window Maker), Mint (customized MATE)
Posts: 1,309

Rep: Reputation: 234Reputation: 234Reputation: 234
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?
 
Old 06-03-2009, 05:36 AM   #2
druuna
LQ Veteran
 
Registered: Sep 2003
Posts: 10,532
Blog Entries: 7

Rep: Reputation: 2405Reputation: 2405Reputation: 2405Reputation: 2405Reputation: 2405Reputation: 2405Reputation: 2405Reputation: 2405Reputation: 2405Reputation: 2405Reputation: 2405
Hi,

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.
 
Old 06-03-2009, 05:54 AM   #3
ghostdog74
Senior Member
 
Registered: Aug 2006
Posts: 2,697
Blog Entries: 5

Rep: Reputation: 244Reputation: 244Reputation: 244
don't need bash to do that...one good tool is all you need, awk
Code:
awk 'BEGIN {
  srand()
  for (i=1;i<=1000;i++){
    print int(1 + rand() * 100)
  }
}'
 
Old 06-03-2009, 05:55 AM   #4
ghostdog74
Senior Member
 
Registered: Aug 2006
Posts: 2,697
Blog Entries: 5

Rep: Reputation: 244Reputation: 244Reputation: 244
deleted by ghost

Last edited by ghostdog74; 06-03-2009 at 05:55 AM. Reason: double post
 
Old 06-03-2009, 05:59 AM   #5
druuna
LQ Veteran
 
Registered: Sep 2003
Posts: 10,532
Blog Entries: 7

Rep: Reputation: 2405Reputation: 2405Reputation: 2405Reputation: 2405Reputation: 2405Reputation: 2405Reputation: 2405Reputation: 2405Reputation: 2405Reputation: 2405Reputation: 2405
Hi,

@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.
 
Old 06-03-2009, 06:10 AM   #6
ghostdog74
Senior Member
 
Registered: Aug 2006
Posts: 2,697
Blog Entries: 5

Rep: Reputation: 244Reputation: 244Reputation: 244
Quote:
Originally Posted by druuna View Post
Hi,

@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.
 
Old 06-03-2009, 06:22 AM   #7
druuna
LQ Veteran
 
Registered: Sep 2003
Posts: 10,532
Blog Entries: 7

Rep: Reputation: 2405Reputation: 2405Reputation: 2405Reputation: 2405Reputation: 2405Reputation: 2405Reputation: 2405Reputation: 2405Reputation: 2405Reputation: 2405Reputation: 2405
@ghostdog74: Personally I agree with you, no discussion there

awk or perl would be my choice, depending on what else needs to be done.
 
Old 06-03-2009, 09:13 AM   #8
H_TeXMeX_H
LQ Guru
 
Registered: Oct 2005
Location: $RANDOM
Distribution: slackware64
Posts: 12,928
Blog Entries: 2

Rep: Reputation: 1301Reputation: 1301Reputation: 1301Reputation: 1301Reputation: 1301Reputation: 1301Reputation: 1301Reputation: 1301Reputation: 1301Reputation: 1301
Quote:
Originally Posted by druuna View Post
Hi,

@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
 
Old 06-03-2009, 11:51 AM   #9
w1k0
Senior Member
 
Registered: May 2008
Location: Poland
Distribution: Slackware (personalized Window Maker), Mint (customized MATE)
Posts: 1,309

Original Poster
Rep: Reputation: 234Reputation: 234Reputation: 234
@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!

Last edited by w1k0; 06-03-2009 at 12:15 PM.
 
Old 06-03-2009, 04:25 PM   #10
bigearsbilly
Senior Member
 
Registered: Mar 2004
Location: england
Distribution: Mint, Armbian, NetBSD, Puppy, Raspbian
Posts: 3,515

Rep: Reputation: 239Reputation: 239Reputation: 239
you could also use $RANDOM in a bash shell script
 
Old 06-03-2009, 07:39 PM   #11
ghostdog74
Senior Member
 
Registered: Aug 2006
Posts: 2,697
Blog Entries: 5

Rep: Reputation: 244Reputation: 244Reputation: 244
Quote:
Originally Posted by w1k0 View Post

@ghostdog74 (first post)
I don’t see the difference between your script and my script.
i already explained. if you fail to see it, too bad.
 
Old 06-03-2009, 07:52 PM   #12
w1k0
Senior Member
 
Registered: May 2008
Location: Poland
Distribution: Slackware (personalized Window Maker), Mint (customized MATE)
Posts: 1,309

Original Poster
Rep: Reputation: 234Reputation: 234Reputation: 234
Quote:
Originally Posted by bigearsbilly View Post
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.
 
Old 06-03-2009, 07:57 PM   #13
w1k0
Senior Member
 
Registered: May 2008
Location: Poland
Distribution: Slackware (personalized Window Maker), Mint (customized MATE)
Posts: 1,309

Original Poster
Rep: Reputation: 234Reputation: 234Reputation: 234
Quote:
Originally Posted by ghostdog74 View Post
i already explained. if you fail to see it, too bad.
My script from #1 post:

Code:
#!/usr/bin/awk -f

BEGIN {
srand()
for ( i = 1; i <= 1000; i++ )
print int ( rand() * 2 + 1 )
}
Your script from #3 post:

Code:
awk 'BEGIN {
  srand()
  for (i=1;i<=1000;i++){
    print int(1 + rand() * 100)
  }
}'
Now I see the difference. I tried it for two numbers and you tried it for one hundred of numbers.
 
Old 06-03-2009, 08:17 PM   #14
ghostdog74
Senior Member
 
Registered: Aug 2006
Posts: 2,697
Blog Entries: 5

Rep: Reputation: 244Reputation: 244Reputation: 244
Quote:
Originally Posted by w1k0 View Post
My script from #1 post:

Code:
#!/usr/bin/awk -f

BEGIN {
srand()
for ( i = 1; i <= 1000; i++ )
print int ( rand() * 2 + 1 )
}
Your script from #3 post:

Code:
awk 'BEGIN {
  srand()
  for (i=1;i<=1000;i++){
    print int(1 + rand() * 100)
  }
}'
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.
 
Old 06-03-2009, 09:12 PM   #15
w1k0
Senior Member
 
Registered: May 2008
Location: Poland
Distribution: Slackware (personalized Window Maker), Mint (customized MATE)
Posts: 1,309

Original Poster
Rep: Reputation: 234Reputation: 234Reputation: 234
Quote:
Originally Posted by ghostdog74 View Post
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.
 
  


Reply



Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is Off
HTML code is Off



Similar Threads
Thread Thread Starter Forum Replies Last Post
need help with bash and awk stympman Programming 3 11-01-2008 06:12 PM
Tossing in the towel on Epson raylhm SUSE / openSUSE 2 02-27-2008 05:32 PM
Help with Bash (grep/awk/etc) piercey Programming 12 02-27-2008 10:21 AM
Our USD coins and money colinstu General 25 10-10-2007 04:39 PM
Tossing up whether to install Kubuntu on laptop nardz Ubuntu 2 05-29-2007 04:39 AM

LinuxQuestions.org > Forums > Non-*NIX Forums > Programming

All times are GMT -5. The time now is 04:43 PM.

Main Menu
Advertisement
My LQ
Write for LQ
LinuxQuestions.org is looking for people interested in writing Editorials, Articles, Reviews, and more. If you'd like to contribute content, let us know.
Main Menu
Syndicate
RSS1  Latest Threads
RSS1  LQ News
Twitter: @linuxquestions
Open Source Consulting | Domain Registration