How to sleep a random fraction of a second in POSIX shell?
The following won't work:
/bin/sleep $(printf ".%02ds" $(( $RANDOM % 100 )))
- POSIX sleep supports only integral seconds
- 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
精彩评论