如何在POSIX shell中让程序休眠一个随机小数秒?

3
以下内容无法正常工作:
/bin/sleep $(printf ".%02ds" $(( $RANDOM % 100 )))
  1. POSIX sleep仅支持整数秒
  2. 没有$RANDOM

我可以通过以下方式模拟随机数:

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

另一种选择是编写一个小的C程序,利用usleep()*rand*(),正如@dmckee@Keith Thompson所建议的那样。部署这样的程序可能并不总是可行的。 是否有更好的方法,即除了手写C程序之外,是否有接受小数秒的POSIX中的其他休眠替代方案,以及是否有更好的模拟$RANDOM的方法,而不是使用od

嗯,考虑到从/dev/random读取可能会阻塞任意时间,我不确定那是否可行。或者也许只是对于您的需求来说,读取已足够随机 :) - Mat
这个问题在Unix.SE上得到了解决,链接为轻量级实用程序/程序,在随机延迟后运行命令,我提供了一个编程答案 - dmckee --- ex-moderator kitten
4个回答

4
在你的第一条命令中,如果$RANDOM % 100是6,那么它将调用 /bin/sleep .6s,你需要/bin/sleep .06s
在第二个命令中,od -An -N1 -t u1 /dev/random似乎会打印0到255范围内的数字, 如果/dev/random没有足够的熵,则命令本身可能会延迟很长时间。请改用/dev/urandom
我会编写一个小的C程序来调用usleep()(假设编译它并部署可执行文件是可行的)。
编辑:
就我所知,对于您更新后的问题的答案是否定的。
POSIX不保证/dev/urandom,因此您的od命令不适用于所有POSIX系统。我不认为POSIX指定任何可以睡眠小数秒的命令。它确实指定了nanosleep()函数,但如果您不能部署一个C程序,则没有帮助。 POSIX的awk没有sleep函数。 Perl不是POSIX。
您的选择是:(1)仅睡整秒,或者(2)使用非便携式方法。
您需要这个环境是什么?

如果0.6和0.06没有区别,那么你并没有真正地睡眠一个随机的一小段时间。您能否澄清您的要求? - Keith Thompson
我使用了 printf 来避免 0.60.06 的问题。问题仍然存在,即在 POSIX 中是否有接受小数秒的替代 sleep 函数,以及是否有比 od 更好的模拟 $RANDOM 的方法。 - jfs
我的建议是写一个小的C程序,解决了你的问题吗?(它可以在srand(time(NULL))之后调用rand())。 - Keith Thompson
1
@J.F. Sebastian:如果您快速连续调用上面的awk解决方案,它将打印相同的数字。看起来srand()每秒只更改一次。 - arielf
@arielf:只有time(NULL)每秒才会改变。 - Keith Thompson
显示剩余4条评论

2
Cliff随机数生成器是一种非常简单的随机数生成器,它通过“不显示任何结构”来“通过噪声球测试的随机性”。它可以很容易地编程,在不到10行的awk代码中:
 # 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
 }

这个算法需要一个初始值为0.1的“种子”。每个新值都使用当前种子作为计算输入。如果内置的rand()函数(请参阅数字函数)不够随机,你可以尝试使用这个函数。

摘自这里


1
这正是我正在寻找的 awk 'BEGIN { srand(); sleep(rand()) }'。但 POSIX 的 awk 没有 sleep() 函数。 - jfs
所以随机数生成部分没问题,对吧?只有 sleep 是个问题? - Lelouch Lamperouge
你不能用system()来睡眠吗?这只是我脑海中的一个想法。 - Lelouch Lamperouge
/bin/sleep $(awk 'BEGIN { srand(); print rand() }')s 运行良好,但 POSIX sleep 仅支持整数秒。 - jfs

2

Perl有usleep函数,但在一个繁忙的系统上,短暂的睡眠时间可能被加载时间所占据。


1
不能保证 Perl 可用。 - jfs

2

这个解决方案在Linux上通过轮询单调计数器/proc/uptime工作 - 即使在慢系统上也可以精确到1/100秒:

最初的回答

#!/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

这里有一个快速而简单的一行代码(复制/粘贴!):

最初的回答:

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

这很不错,但/proc是Linux的一部分,不能在其他系统如BSD上移植。 - Adam Katz
你是对的:所以你必须走 Python 或 Perl 的路线:https://dev59.com/oW435IYBdhLWcg3w1z4t - Bastian Bittorf

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接