Bash命令等到下一个完整秒

时间:2015-10-19 00:26:07

标签: bash datetime wait milliseconds

我要求如何等待下一秒?我不是说睡1! 例如,我们有时间07:45:06.729。 最后的729表示毫秒。 那我们怎么能说等到下一整秒?这将是07:45:07.000

谢谢;)

6 个答案:

答案 0 :(得分:2)

这就像马特的回答,但没有忙碌等待试图提前醒来。这简化了 lot 的事情,因为除了当前时间的小数部分之外,我们从不关心任何事情。

使用GNU date +%N获取当前时间的纳秒部分,使用sleep获得1 - 。

sleep_to_next_second(){
    sleep 0.$(printf '%04d' $((10000 - 10#$(date +%4N))))
}

技巧是:

  • 带有前导零的数字在bash算术上下文中被视为八进制,因此请使用10#$dateforce base10

  • 由于bash只能进行整数数学运算,显而易见的是使用定点千分之一秒或者其他东西,然后使用前导小数点。这使得前导零必不可少,因此您可以睡眠0.092秒,而不是0.92。我使用printf '%04d'来格式化我的数字。

实验测试:

# echo instead of sleep to see what numbers we generate
while true;do echo 0.$(printf '%04d' $((10000 - 10#$(date +%4N))));done

...
0.0049
0.0035
0.0015
0.10000    ##### minor bug: sleeps for 0.1 sec if the time was bang-on a ten-thousandth
0.9987
0.9973
0.9960

while true;do date +"%s %N"; sleep 0.$(printf '%04d' $((10000 - 10#$(date +%4N))));done
1445301422 583340443
1445301423 003697512
1445301424 003506054
1445301425 003266620
1445301426 003776955
1445301427 003921242
1445301428 003018890
1445301429 002652820
# So typical accuracy is 0.003 secs after the rollover to the next second, on a near-idle desktop

Ubuntu 15.04:GNU bash / date / sleep on Linux 3.19 on Intel i5-2500k,空闲时间为1.6GHz,turbo 3.8GHz。

答案 1 :(得分:1)

GNU sleep命令接受浮点参数。 因此,您可以计算等待的确切时间并使用结果调用睡眠。

请参阅https://superuser.com/questions/222301/unix-sleep-until-the-specified-time

https://serverfault.com/questions/469247/how-do-i-sleep-for-a-millisecond-in-bash-or-ksh

答案 2 :(得分:1)

这更像是一个计时器解决方案。

它需要GNU date,它可以用%Nsleep做纳秒,可以做小数,这是GNU做的,有些是做的。

您的里程数会因负载很重的系统而异。如果必须,这将跳过秒。

如果加载系统的准确性不那么重要,那么safety可以更低(或者只使用Peter更简单的解决方案)。您使用的处理器时间越长,但它在高负载系统上准时的可能性略高。过了一点,你只是在浪费cpu时间。即使这样,如果你的系统有更好的安排,这将等待。

# ms to spend busy waiting * 10
safety=100

while true; do
  if [ "$(date +%s)" != "$last_sec" ]; then

    # Do whatever you need to here
    date +"%S.%N"

    # Then figure out how much to sleep until just 
    # before the next second. 
    sec_ns="$(date +"%s %4N")"
    sec=${sec_ns:0:-5}
    ms=${sec_ns:11}
    last_sec=$sec
    let sleep=10000-10#$ms-$safety
    sleep 0.$(printf '%04d' $sleep)
  fi
done

datesleep的调用是外部二进制文件,因此执行它们会有一些开销。正如评论中所提到的,bash可能不是这项工作的最佳工具。

另请注意,由于使用了子串,这将在11月20日星期六17:46:39 UTC 2286之后失败。希望我们的计算机领主在那时已经从他们的操作系统中删除了bash。谢谢你毁了我的笑话彼得=)

同时运行

[vagrant@localhost ~]$ /tmp/wait_seconds.sh 
32.376187825
33.002727030
34.001005707
35.001850686
36.002232134
37.001802235
^C
[vagrant@localhost ~]$ while sleep 0.$(printf '%04d' $((10000 - 10#$(date +%4N) - 1))); do date +"%S.%N"; done
41.006809812
42.005389515
43.005793726
44.004930099
45.004829293
46.005988337

答案 3 :(得分:0)

使用bash

sleep echo "scale=3; $((1000 -$(echo $(cut -d '.' -f2 <<< "07:45:06.729"))))/1000"|bc

让我分解一下,因为它令人困惑

$(cut -d '.' -f2 <<< "07:45:06.729")#这将获得毫秒部分

在上面的命令行上构建

echo "scale=3; $((1000 -$(echo $(cut -d '.' -f2 <<< "07:45:06.729"))))/1000"|bc#这会给你分数

此后将剩余部分传递给sleep 编辑:使用较短的bash代码

答案 4 :(得分:0)

上面的答案是非常聪明的BASH,但最终我一直遇到奇怪的边缘问题试图只在BASH中这样做,所以我写了一个简单的C程序,而不是每次都很完美,并且非常简单易懂。

// Wait until the next second rolls over
// Use sleep rather than polling


#include <unistd.h>
#include <sys/time.h>



int main(void) {

    unsigned int microseconds;

    struct timeval  tv;
    gettimeofday(&tv, NULL);


    // Calculate time until next round second...

    microseconds = 1000000 - (tv.tv_usec);

    usleep(microseconds);

    return(0);
}

https://github.com/bigjosh/De-Harak-Clock-Controller/blob/master/nextsecond.c

使用命令构建实用程序...

gcc nextsecond.c
chmod +x nextsecond

您可以通过运行来测试它的工作原理......

./nextsecond; date "+%N"

它将打印自上一轮秒以来的纳秒数,该值应始终小于010000000,即10,000,000ns,即10ms。

答案 5 :(得分:0)

一个简单的功能,没有任何魔法

function sleepUntilTheNextSecond() {
    local currentTimeMilliseconds
    currentTimeMilliseconds=$(date +%s%3N)
    local currentTimeSeconds=$(( currentTimeMilliseconds / 1000 ))
    local targetTimeMilliseconds=$(( (currentTimeSeconds + 1) * 1000 ))
    local sleepMilliseconds=$(( targetTimeMilliseconds - currentTimeMilliseconds ))
    if (( sleepMilliseconds > 1000 )); then
        echo "Invalid sleepMilliseconds (> 1000): $sleepMilliseconds"
        exit 1
    fi
    sleep "0.$sleepMilliseconds"
}

经过GNU bash, version 4.1.2(2)-release (x86_64-redhat-linux-gnu)

的测试