当前位置:  开发笔记 > 编程语言 > 正文

Bash:睡到特定的时间/日期

如何解决《Bash:睡到特定的时间/日期》经验,为你挑选了8个好方法。

我希望我的bash脚本睡到特定时间.所以,我想要一个像"睡眠"这样的命令,它不需要间隔但是结束时间,直到那时才睡觉.

"at"-daemon不是解决方案,因为我需要阻止正在运行的脚本直到某个日期/时间.

有这样的命令吗?



1> SpoonMeiser..:

正如Outlaw Programmer所提到的,我认为解决方案只是睡眠正确的秒数.

要在bash中执行此操作,请执行以下操作:

current_epoch=$(date +%s)
target_epoch=$(date -d '01/01/2010 12:00' +%s)

sleep_seconds=$(( $target_epoch - $current_epoch ))

sleep $sleep_seconds

要将精度降低到纳秒(实际上大约几毫秒),请使用以下语法:

current_epoch=$(date +%s.%N)
target_epoch=$(date -d "20:25:00.12345" +%s.%N)

sleep_seconds=$(echo "$target_epoch - $current_epoch"|bc)

sleep $sleep_seconds

需要注意的是MACOS/OS X不支持低于秒的精度,你将需要使用coreutilsbrew代替→ 请参阅这些说明


谢谢你,我写了一个小的shell脚本来获得一个"sleepuntil"命令.
如果你想在明天凌晨3点停止,你可以使用`target_epoch = $(明天-d'明天03:00'+%s)`.

2> John Feminel..:

使用sleep,但使用计算时间date.你会想要用date -d它.例如,假设你想要等到下周:

expr `date -d "next week" +%s` - `date -d "now" +%s`

只需将"下周"替换为您想要等待的日期,然后将此表达式赋值给一个值,然后休眠这么多秒:

startTime=$(date +%s)
endTime=$(date -d "next week" +%s)
timeToWait=$(($endTime- $startTime))
sleep $timeToWait

全部完成!



3> F. Hauri..:

正如4年前提出这个问题,第一部分涉及旧的 bash版本:

一般方法

为了减少forks而不是运行date两次,我更喜欢使用它:

sleep $(($(date -f - +%s- <<< $'tomorrow 21:30\nnow')0))

tomorrow 21:30将来可以用任何类型的日期和格式替换date.

或者更好,如果可能的话今天达到下一个HH:MM意义,明天如果为时已晚:

sleep $((($(date -f - +%s- <<<$'21:30 tomorrow\nnow')0)%86400))

这适用于bash,ksh和其他现代shell,但你必须使用:

sleep $(( ( $(printf 'tomorrow 21:30\nnow\n' | date -f - +%s-)0 )%86400 ))

较轻的外壳下如灰烬或破折号.

新的bash方式(没有叉子)

至于我需要这种工具从未exceded 24小时,下面将只关心HH,HH:MMHH:MM:SS语法意味着在接下来的24小时.(无论如何,如果你需要更多,你甚至可以使用fork来返回旧方法date.试图在运行多天的脚本中消除一个fork是过度的.)

由于新版本的bash确实提供了一个printf检索日期的选项,对于这种新的睡眠方式直到HH:MM无需使用date或任何其他分叉,我构建了一个小的bash函数.这里是:

sleepUntil() {
    local slp tzoff now quiet=false
    [ "$1" = "-q" ] && shift && quiet=true
    local hms=(${1//:/ })
    printf -v now '%(%s)T' -1
    printf -v tzoff '%(%z)T\n' $now
    tzoff=$((0${tzoff:0:1}(3600*${tzoff:1:2}+60*${tzoff:3:2})))
    slp=$(((86400+(now-now%86400)+10#$hms*3600+10#${hms[1]}*60+${hms[2]}-tzoff-now)%86400))
    $quiet || printf 'sleep %ss, -> %(%c)T\n' $slp $((now+slp))
    sleep $slp
}

然后:

sleepUntil 11:11 ; date +"Now, it is: %T"
sleep 3s, -> sam 28 sep 2013 11:11:00 CEST
Now, it is: 11:11:00

sleepUntil -q 11:11:5 ; date +"Now, it is: %T"
Now, it is: 11:11:05
HiRes 在GNU/Linux下使用bash的时间

在最近的Linux内核中,您将找到一个名为的变量文件/proc/timer_list,您可以在其中读取offsetnow变量,以纳秒为单位.因此,我们可以计算睡眠时间,以达到最佳时间.

(我写这个来生成和跟踪非常大的日志文件上的特定事件,包含一千秒的一行).

mapfile   %(%c)T\n' $slp $((now+${slp%.*}+1))
    sleep $slp
}

定义两个后只读变量,TIMER_LIST_OFFSET并且TIMER_LIST_SKIP,该功能将很快访问该变量文件/proc/timer_list计算睡眠时间:

sleepUntilHires 15:03 ;date +%F-%T.%N ;sleep .97;date +%F-%T.%N
sleep 19.632345552s, -> sam 28 sep 2013 15:03:00 CEST
2013-09-28-15:03:00.003471143
2013-09-28-15:03:00.976100517

sleepUntilHires -q 15:04;date -f - +%F-%T.%N < <(echo now;sleep .97;echo now)
2013-09-28-15:04:00.003608002
2013-09-28-15:04:00.974066555

最后

测试功能很少

tstSleepUntilHires () { 
    local now next last
    printf -v now "%(%s)T"
    printf -v next "%(%H:%M:%S)T" $((now+1))
    printf -v last "%(%H:%M:%S)T" $((now+2))
    sleepUntilHires $next
    date -f - +%F-%T.%N < <(echo now;sleep .92;echo now)
    sleepUntilHires $last
    date +%F-%T.%N
}

可能会呈现如下内容:

sleep 0.155579469s, -> Mon Aug 20 20:42:51 2018
2018-08-20-20:42:51.005743047
2018-08-20-20:42:51.927112981
sleep 0.071764300s, -> Mon Aug 20 20:42:52 2018
2018-08-20-20:42:52.003165816

在下一秒开始,

打印时间,然后

等等0.92秒

打印时间,然后

计算0.07秒,到下一秒

然后睡0.07秒

打印时间.

Nota :( .92 + 0.071 = .991在我的桌面上)



4> SpoonMeiser..:

您可以通过向其发送SIGSTOP信号来停止执行进程,然后通过向其发送SIGCONT信号使其继续执行.

所以你可以通过发送一个SIGSTOP来停止你的脚本:

kill -SIGSTOP 

然后使用at deamon通过以相同的方式发送SIGCONT来唤醒它.

据推测,你的脚本会告诉你什么时候想要在醒来之前被唤醒.



5> Anthony O...:

在Ubuntu 12.04.4 LTS上,这是可以正常工作的简单bash输入:

sleep $(expr `date -d "03/21/2014 12:30" +%s` - `date +%s`)



6> Paused until..:

接下来是SpoonMeiser的回答,这是一个具体的例子:

$cat ./reviveself

#!/bin/bash

# save my process ID
rspid=$$

# schedule my own resuscitation
# /bin/sh seems to dislike the SIGCONT form, so I use CONT
# at can accept specific dates and times as well as relative ones
# you can even do something like "at thursday" which would occur on a 
# multiple of 24 hours rather than the beginning of the day
echo "kill -CONT $rspid"|at now + 2 minutes

# knock myself unconscious
# bash is happy with symbolic signals
kill -SIGSTOP $rspid

# do something to prove I'm alive
date>>reviveself.out
$



7> 小智..:

我想要一个只检查小时和分钟的脚本,这样我每天都可以使用相同的参数运行该脚本。我不想担心明天是哪一天。因此,我使用了另一种方法。

target="$1.$2"
cur=$(date '+%H.%M')
while test $target != $cur; do
    sleep 59
    cur=$(date '+%H.%M')
done

脚本的参数是小时和分钟,所以我可以这样写:

til 7 45 && mplayer song.ogg

(直到是脚本的名称)

上班时间不再延迟,因为您输错了一天。干杯!



8> Camusensei..:

这是一个解决方案,可以完成工作并通知用户剩余时间。我几乎每天都在晚上使用它来运行脚本(使用cygwin,因为我无法cron在Windows上工作)

特征

精确到秒

检测系统时间变化并适应

智能输出告诉您还剩多少时间

24小时输入格式

返回true以能够与 &&

样品运行

$ til 13:00 && date
1 hour and 18 minutes and 26 seconds left...
1 hour and 18 minutes left...
1 hour and 17 minutes left...
1 hour and 16 minutes left...
1 hour and 15 minutes left...
1 hour and 14 minutes left...
1 hour and 10 minutes left...
1 hour and  5 minutes left...
1 hour and  0 minutes left...
55 minutes left...
50 minutes left...
45 minutes left...
40 minutes left...
35 minutes left...
30 minutes left...
25 minutes left...
20 minutes left...
15 minutes left...
10 minutes left...
 5 minutes left...
 4 minutes left...
 3 minutes left...
 2 minutes left...
 1 minute left...
Mon, May 18, 2015  1:00:00 PM

(结尾的日期不是函数的一部分,而是由于引起的&& date

til(){
  local hour mins target now left initial sleft correction m sec h hm hs ms ss showSeconds toSleep
  showSeconds=true
  [[ $1 =~ ([0-9][0-9]):([0-9][0-9]) ]] || { echo >&2 "USAGE: til HH:MM"; return 1; }
  hour=${BASH_REMATCH[1]} mins=${BASH_REMATCH[2]}
  target=$(date +%s -d "$hour:$mins") || return 1
  now=$(date +%s)
  (( target > now )) || target=$(date +%s -d "tomorrow $hour:$mins")
  left=$((target - now))
  initial=$left
  while (( left > 0 )); do
    if (( initial - left < 300 )) || (( left < 300 )) || [[ ${left: -2} == 00 ]]; then
      # We enter this condition:
      # - once every 5 minutes
      # - every minute for 5 minutes after the start
      # - every minute for 5 minutes before the end
      # Here, we will print how much time is left, and re-synchronize the clock

      hs= ms= ss=
      m=$((left/60)) sec=$((left%60)) # minutes and seconds left
      h=$((m/60)) hm=$((m%60)) # hours and minutes left

      # Re-synchronise
      now=$(date +%s) sleft=$((target - now)) # recalculate time left, multiple 60s sleeps and date calls have some overhead.
      correction=$((sleft-left))
      if (( ${correction#-} > 59 )); then
        echo "System time change detected..."
        (( sleft <= 0 )) && return # terminating as the desired time passed already
        til "$1" && return # resuming the timer anew with the new time
      fi

      # plural calculations
      (( sec > 1 )) && ss=s
      (( hm != 1 )) && ms=s
      (( h > 1 )) && hs=s

      (( h > 0 )) && printf %s "$h hour$hs and "
      (( h > 0 || hm > 0 )) && printf '%2d %s' "$hm" "minute$ms"
      if [[ $showSeconds ]]; then
        showSeconds=
        (( h > 0 || hm > 0 )) && (( sec > 0 )) && printf %s " and "
        (( sec > 0 )) && printf %s "$sec second$ss"
        echo " left..."
        (( sec > 0 )) && sleep "$sec" && left=$((left-sec)) && continue
      else
        echo " left..."
      fi
    fi
    left=$((left-60))
    sleep "$((60+correction))"
    correction=0
  done
}

推荐阅读
U友50081205_653
这个屌丝很懒,什么也没留下!
DevBox开发工具箱 | 专业的在线开发工具网站    京公网安备 11010802040832号  |  京ICP备19059560号-6
Copyright © 1998 - 2020 DevBox.CN. All Rights Reserved devBox.cn 开发工具箱 版权所有