开发者

How to sleep a random fraction of a second in POSIX shell?

The following won't work:

/bin/sleep $(printf ".%02ds" $(( $RANDOM % 100 )))
  1. POSIX sleep supports only integral seconds
  2. there is no $RANDOM

I could emul开发者_开发问答ate random by:

RAND255=$(od -An -N1 -t u1 /dev/urandom)

Another option is to write a small C program that utilizes usleep() and *rand*() as suggested by @dmckee and @Keith Thompson. Deploying such program might not be always possible.

Is there a better way i.e., is there an alternative for sleep in POSIX that accept fractions of a second other than a hand-written C program and is there a better way to emulate $RANDOM other than od?


In your first command, if $RANDOM % 100 is 6, for example, it will invoke /bin/sleep .6s; you want /bin/sleep .06s.

In the second command, od -An -N1 -t u1 /dev/random seems to print a number in the range 0..255 -- and the command itself can delay for a long time if /dev/random runs out of entropy. Use /dev/urandom instead.

I'd write a small C program that calls usleep() (assuming that compiling it and deploying the executable is feasible).

EDIT:

As far as I can tell, the answer to your (updated) question is no.

POSIX doesn't guarantee /dev/urandom, so your od command isn't portable to all POSIX systems. I don't believe POSIX specifies any command that can sleep for fractional seconds. It does specify the nanosleep() function, but if you can't necessarily deploy a C program that doesn't help. POSIX awk has no sleep function. Perl is not POSIX.

Your options are: (1) sleep only for whole seconds, or (2) use a non-portable method.

What environment(s) do you need this for?


Perl has usleep but on a loaded system, load times probably dominate over short sleeps.


The Cliff random number generator is a very simple random number generator that “passes the noise sphere test for randomness by showing no structure.” It is easily programmed, in less than 10 lines of awk code:

 # cliff_rand.awk --- generate Cliff random numbers



 BEGIN { _cliff_seed = 0.1 }

 function cliff_rand()
 {
     _cliff_seed = (100 * log(_cliff_seed)) % 1
     if (_cliff_seed < 0)
         _cliff_seed = - _cliff_seed
     return _cliff_seed
 }

This algorithm requires an initial “seed” of 0.1. Each new value uses the current seed as input for the calculation. If the built-in rand() function (see Numeric Functions) isn't random enough, you might try using this function instead.

Taken from here


this solution works on linux by polling the monotonic counter /proc/uptime - it works even on slow systems for 1/100 of a second exact:

#!/bin/sh

WAIT=567        # 5.67 sec

get_up()
{
        read -r UP REST </proc/uptime
        export UP=${UP%.*}${UP#*.}
}

get_up; START=$UP
while :; do get_up; test $((UP-START)) -ge $WAIT && break; done

A quick and dirty oneliner (copy/paste!) is here:

W=567;x(){ read U R </proc/uptime;U=${U%.*}${U#*.};};x;S=$U;while :;do x;test $((U-S)) -ge $W && break;done
0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜