在我的机器上,我需要执行一个迭代 1 个简单命令的循环,该命令必须具有以秒为单位表示的延迟。
假设我需要:
- 保存一个具有递增枚举的文件(file-0、file-1、file-2,...),对于本例来说,通过一些简单的事情生成,例如
time > file-$x
- 我需要每隔 1/70 秒执行一次此操作(作为示例),因为我想用秒的分数表示我的时间。
我怎样才能真正精确并用 bash 脚本表达所有内容?
分数可以产生不确定的数量,我需要精确,所以我需要至少 4-5 位小数。
答案1
要在 bash 中将分数转换为小数,请执行以下操作
myvar=$(echo "scale=4; 5/10" | bc)
然后,要对该值进行循环,
for i in $(seq 1 1000); do sleep $myvar; done
我在 Debian (GNU) 上的睡眠实现似乎接受十进制睡眠值。
很遗憾..
有了这种精度(4-5 位小数),您将需要像 Perl 脚本或编译的程序之类的东西;在循环内调用任何程序的开销都会增加很多抖动。调用 sleep 本身需要几毫秒的时间。
考虑以下情况,1/10,000 秒的睡眠,完成 1000 次:
time for i in $(seq 1 1000); do sleep 0.0001; done
real 0m2.099s
user 0m3.080s
sys 0m1.464s
预期结果是 1/10 秒。睡眠远没有达到你想要的耐受程度。
https://stackoverflow.com/questions/896904/how-do-i-sleep-for-a-millisecond-in-perl
使用perl的Time::HiRes,1000*1000微秒:
my $i=0;
for($i=0;$i<=1000;$i++) {
usleep(1000);
}
real 0m1.133s
user 0m0.024s
sys 0m0.012s
让我们更接近一秒。
答案2
也许你可以简单地运行
sleep 0.7
?
man 1 sleep
在我的archlinux
发行版上:
描述 暂停 NUMBER 秒。后缀可以是“s”表示秒(默认)、“m”表示分钟、“h”表示小时或“d”表示天。与大多数要求 NUMBER 为整数的实现不同,这里的 NUMBER 可以是任意浮点数。给定两个或多个参数,暂停由它们的值之和指定的时间。
答案3
生成一个进程并在其中加载一个新的可执行文件可能需要几毫秒的时间,因此这种精度实际上没有意义。另请注意,许多系统上的 CPU 时间按最多 10 毫秒的切片分配给进程。
话虽如此,某些sleep
实现需要小数秒,并且 zsh 和 ksh93 都可以使用 使其$SECONDS
特殊变量小数typeset -F SECONDS
。
示例(zsh):
$ typeset -F SECONDS=0; for ((i=1; i<=70; i++)); do sleep $((1./70)); date +%s.%N; done | { head -n3;echo ..;tail -n3; }; echo $SECONDS
1350076317.374870501
1350076317.391034397
1350076317.407278461
..
1350076318.464585550
1350076318.480887660
1350076318.497133050
1.1393780000
哎呀,飘了。您可以根据以下情况调整睡眠时间$SECONDS
:
$ typeset -F SECONDS=0; for ((i=1; i<=70; i++)); do sleep $((i/70. - SECONDS)); date +%s.%N; done | { head -n3;echo ...;tail -n3; }; echo $SECONDS
1350076420.262775654
1350076420.277012997
1350076420.291302750
../..
1350076421.219682227
1350076421.234134663
1350076421.248255685
1.0020580000
这额外的 2 毫秒可能是由于运行最后一个sleep
和date
命令而产生的。
另请注意,zsh 有一个zselect
内置超时,以百分之一秒表示。 ksh93 具有sleep
内置功能(并接受浮点),并且printf
可以打印日期/时间。
$ typeset -F SECONDS=0; for ((i=1; i<=70; i++)); do ((i<4 || i>67)) && printf '%(%S.%N)T\n' now; sleep $((i/70.-SECONDS)); done; echo $SECONDS
20.823349000
20.837510000
20.851663000
21.780099000
21.794254000
21.808405000
0.9992358685
如果您想要更精确的东西,您可能需要一个实时操作系统或具有实时功能的操作系统和当然不是使用外壳。
答案4
在下面阿尔卑斯Linux(Busybox)您可以循环微秒usleep 10
(相当于0.00001
一秒)
GNU sleep
支持几分之一秒:sleep 0.00001