views:

380

answers:

6

Hi,

I need to generate a random port number between 2000-65000 from a shell script. The problem is $RANDOM is only a 16bit number, so im stuck!

PORT=$(($RANDOM%63000+2001)) would work nicely if it wasn't for the size limitation.

Does anyone have an example of how I can do this, maybe by extracting something from /dev/urandom and getting it within a range?

Thanks.

+1  A: 

The simplest general way that comes to mind is a perl one-liner:

perl -e 'print int(rand(65000-2000)) + 2000'

You could always just use two numbers:

PORT=$(($RANDOM + ($RANDOM % 2) * 32768))

You still have to clip to your range. It's not a general n-bit random number method, but it'll work for your case, and it's all inside bash.

If you want to be really cute and read from /dev/urandom, you could do this:

od -A n -N 2 -t u2 /dev/urandom

That'll read two bytes and print them as an unsigned int; you still have to do your clipping.

Jefromi
+1  A: 
shuf -i 2000-65000 -n 1

Enjoy!

Edit: The range is inclusive.

dave
I think `shuf` is relatively recent - I've seen it on Ubuntu systems in the last couple years but not the current RHEL/CentOS.
Jefromi
Also, it's probably fine for this use, but I believe `shuf` does actually permute the entire input. This makes it a bad choice if you're generating the random numbers very frequently.
Jefromi
@Jefromi: On my system, using this test `time for i in {1..1000}; do shuf -i 0-$end -n 1000 > /dev/null; done` and comparing `end=1` to `end=65535` showed about a 25% improvement for the shorter range which amounted to about 4 seconds difference over a million iterations. And it's **lots** faster than performing the OP's Bash calculation a million times.
Dennis Williamson
@Dennis Williamson: Thanks for the benchmark. I was on the CentOS system at the time and couldn't test for sure; I figured it couldn't be that bad since it was within the C code. I really just wanted to point out that it's not actually just generating a single random number.
Jefromi
@Dennis Williamson: Running your test with `-n 1` showed negligible time differences, even with `end=4000000000`. Good to know `shuf` works smart, not hard :-)
dave
A: 

and here's one with Python

randport=$(python -S -c "import random; print random.randrange(2000,63000)")

and one with awk

awk 'BEGIN{srand();print int(rand()*(63000-2000))+2000 }'
ghostdog74
A: 

On Mac OS X and FreeBSD you may also use jot:

jot -r 1  2000 65000
errno
A: 

Here's another one. I thought it would work on just about anything, but sort's random option isn't available on my centos box at work.

 seq 2000 65000 | sort -R | head -n 1
valadil
A: 

You can do this

cat /dev/urandom|od -N2 -An -i|awk -v f=2000 -v r=65000 '{printf "%i\n", f + r * $1 / 65536}'

If you need more details see Shell Script Random Number Generator.

New Exit