นอนหลับจนถึงเวลา / วันที่ที่กำหนด


92

ฉันต้องการให้สคริปต์ทุบตีของฉันเข้าสู่โหมดสลีปจนกว่าจะถึงเวลาที่กำหนด ดังนั้นฉันต้องการคำสั่งเช่น "sleep" ซึ่งไม่มีช่วงเวลาใด ๆ แต่มีเวลาสิ้นสุดและหลับไปจนถึงตอนนั้น

"at" -daemon ไม่ใช่วิธีแก้ปัญหาเนื่องจากฉันต้องบล็อกสคริปต์ที่กำลังทำงานอยู่จนกว่าจะถึงวันที่ / เวลาที่แน่นอน

มีคำสั่งดังกล่าวหรือไม่?


1
โปรดทราบว่าวิธีแก้ปัญหาที่ใช้การนอนหลับเป็นเวลานานนำหน้าด้วยการคำนวณอาจนอนหลับนานเกินไปอาจนานเกินไปโดยเฉพาะอย่างยิ่งหากคุณมีเครื่องที่สามารถจำศีลได้ คำสั่ง posix sleep ไม่มีคำสัญญาว่าจะไม่นอนหลับนานเกินไป การแก้ปัญหาโดย @Camusensei ตอบสนองความกังวลได้เป็นอย่างดี
GregD

คำตอบ:


101

ดังที่กล่าวโดย 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 ไม่รองรับความแม่นยำที่ต่ำกว่าไม่กี่วินาทีคุณจะต้องใช้coreutilsจากbrewดูคำแนะนำเหล่านี้แทน


8
ขอบคุณสำหรับสิ่งนั้นฉันเขียนเชลล์สคริปต์ขนาดเล็กเพื่อรับคำสั่ง "sleepuntil"
theomega

1
@enigmaticPhysicist: มีคำสั่งที่คล้ายกันเรียก "at" ซึ่งเรียกใช้ async
voidlogic

8
หากคุณต้องการหยุดพรุ่งนี้เวลา 3:00 น. คุณสามารถใช้target_epoch=$(date -d 'tomorrow 03:00' +%s)แทนได้
Yajo

คุณสามารถทำได้โดยใช้ส้อมหนึ่งdateแทนสอง! ดูส่วนที่ 1 ของคำตอบของฉัน
F. Hauri

1
โปรดทราบว่าโซลูชันนี้อาจเข้าสู่โหมดสลีปนานเกินไปและหากเครื่องของคุณอยู่ในโหมดไฮเบอร์เนตเล็กน้อยก็อาจใช้เวลานานเกินไป
GregD

26

ในฐานะที่เป็นคำถามนี้ถูกถาม 4 ปีที่ผ่านมานี้ส่วนแรกกังวลเก่ารุ่นทุบตี:

แก้ไขล่าสุด: พ. 22 เม.ย. 2020 บางช่วงระหว่าง 10:30 น. ถึง 10 น. 55 (สำคัญสำหรับการอ่านตัวอย่าง)

วิธีการทั่วไป (หลีกเลี่ยงส้อมที่ไร้ประโยชน์!)

(หมายเหตุ: วิธีนี้ใช้date -fซึ่งไม่ใช่ POSIX และไม่ทำงานภายใต้ MacOS! หากอยู่ภายใต้ Mac ให้ไปที่ my pureฟังก์ชัน )

เพื่อลดforksแทนที่จะวิ่งdateสองครั้งฉันชอบใช้สิ่งนี้:

ตัวอย่างเริ่มต้นง่ายๆ

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

ซึ่งtomorrow 21:30สามารถแทนที่ด้วยวันที่และรูปแบบใดก็ได้ที่รู้จักdateในอนาคต

ด้วยความแม่นยำสูง (นาโนวินาที)

ใกล้เคียงกัน:

sleep $(bc <<<s$(date -f - +'t=%s.%N;' <<<$'07:00 tomorrow\nnow')'st-t')

ถึงในครั้งต่อไป

สำหรับการเข้าถึงต่อไปHH:MMความหมายในวันนี้ถ้าเป็นไปได้ในวันพรุ่งนี้ถ้าสายเกินไป:

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

ทำงานภายใต้ , และเปลือกหอยสมัยใหม่อื่น ๆ แต่คุณต้องใช้:

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

ภายใต้เปลือกที่มีน้ำหนักเบาเช่น หรือ .

บริสุทธิ์ ทางแยก !!

ทดสอบภายใต้ MacOS!

ฉันเขียนหนึ่งสองฟังก์ชันเล็ก ๆ : sleepUntilและsleepUntilHires

 Syntax:
 sleepUntil [-q] <HH[:MM[:SS]]> [more days]
     -q Quiet: don't print sleep computed argument
     HH          Hours (minimal required argument)
     MM          Minutes (00 if not set)
     SS          Seconds (00 if not set)
     more days   multiplied by 86400 (0 by default)

เนื่องจาก bash เวอร์ชันใหม่มีprintfตัวเลือกในการดึงข้อมูลวันที่สำหรับวิธีใหม่ในการนอนหลับจนถึง HH: MMโดยไม่ต้องใช้dateหรือทางแยกอื่น ๆ ฉันได้สร้างขึ้นเล็กน้อยฟังก์ชัน นี่คือ:

sleepUntil() { # args [-q] <HH[:MM[:SS]]> [more days]
    local slp tzoff now quiet=false
    [ "$1" = "-q" ] && shift && quiet=true
    local -a 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 + ${2:-0}*86400
    ))
    $quiet || printf 'sleep %ss, -> %(%c)T\n' $slp $((now+slp))
    sleep $slp
}

จากนั้น:

sleepUntil 10:37 ; date +"Now, it is: %T"
sleep 49s, -> Wed Apr 22 10:37:00 2020
Now, it is: 10:37:00

sleepUntil -q 10:37:44 ; date +"Now, it is: %T"
Now, it is: 10:37:44

sleepUntil 10:50 1 ; date +"Now, it is: %T"
sleep 86675s, -> Thu Apr 23 10:50:00 2020
^C

หากเป้าหมายอยู่ก่อนหน้านี้จะเข้าสู่โหมดสลีปจนถึงพรุ่งนี้:

sleepUntil 10:30 ; date +"Now, it is: %T"
sleep 85417s, -> Thu Apr 23 10:30:00 2020
^C

sleepUntil 10:30 1 ; date +"Now, it is: %T"
sleep 171825s, -> Fri Apr 24 10:30:00 2020
^C

HiRes เวลากับ ภายใต้ GNU / Linux

ล่าสุด จากเวอร์ชัน 5.0 เพิ่ม$EPOCHREALTIMEตัวแปรใหม่ด้วยไมโครวินาที จากนี้มีsleepUntilHiresฟังก์ชั่น

sleepUntilHires () { # args [-q] <HH[:MM[:SS]]> [more days]
    local slp tzoff now quiet=false musec musleep;
    [ "$1" = "-q" ] && shift && quiet=true;
    local -a hms=(${1//:/ });
    printf -v now '%(%s)T' -1;
    IFS=. read now musec <<< $EPOCHREALTIME;
    musleep=$[2000000-10#$musec];
    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+10#${hms[2]} -
            tzoff - now - 1
            ) % 86400 ) + ${2:-0} * 86400
          )).${musleep:1};
    $quiet || printf 'sleep %ss, -> %(%c)T\n' $slp $((now+${slp%.*}+1));
    read -t $slp foo
}

โปรดทราบ: การใช้งานนี้ชในตัวแทนread -t sleepโชคไม่ดีที่สิ่งนี้ใช้ไม่ได้เมื่อทำงานในพื้นหลังโดยไม่มี TTY จริง อย่าลังเลที่จะแทนที่read -tโดยsleepหากคุณวางแผนที่จะเรียกใช้สิ่งนี้ในสคริปต์พื้นหลัง ... (แต่สำหรับกระบวนการเบื้องหลังให้พิจารณาใช้cronและ / หรือatแทนทั้งหมดนี้)

ข้ามย่อหน้าถัดไปสำหรับการทดสอบและคำเตือนเกี่ยวกับ$ËPOCHSECONDS!

เคอร์เนลล่าสุดหลีกเลี่ยงการใช้/proc/timer_listโดยผู้ใช้ !!

ภายใต้เคอร์เนล Linux ล่าสุดคุณจะพบไฟล์ตัวแปรชื่อ "/ proc / timer_list" ซึ่งคุณสามารถอ่านตัวแปร "offset" และ "now" ได้ใน ** นาโนวินาที ** ดังนั้นเราอาจคำนวณเวลานอนเพื่อให้ถึงเวลาที่ต้องการ * สูงสุด *

(ฉันเขียนสิ่งนี้เพื่อสร้างและติดตามเหตุการณ์ที่เฉพาะเจาะจงในไฟล์บันทึกขนาดใหญ่ที่มีพันบรรทัดเป็นเวลาหนึ่งวินาที)

mapfile  </proc/timer_list _timer_list
for ((_i=0;_i<${#_timer_list[@]};_i++));do
    [[ ${_timer_list[_i]} =~ ^now ]] && TIMER_LIST_SKIP=$_i
    [[ ${_timer_list[_i]} =~ offset:.*[1-9] ]] && \
    TIMER_LIST_OFFSET=${_timer_list[_i]//[a-z.: ]} && \
     break
done
unset _i _timer_list
readonly TIMER_LIST_OFFSET TIMER_LIST_SKIP

sleepUntilHires() {
    local slp tzoff now quiet=false nsnow nsslp
    [ "$1" = "-q" ] && shift && quiet=true
    local hms=(${1//:/ })
    mapfile -n 1 -s $TIMER_LIST_SKIP nsnow </proc/timer_list
    printf -v now '%(%s)T' -1
    printf -v tzoff '%(%z)T\n' $now
    nsnow=$((${nsnow//[a-z ]}+TIMER_LIST_OFFSET))
    nsslp=$((2000000000-10#${nsnow:${#nsnow}-9}))
    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 - 1
        ) % 86400)).${nsslp:1}
    $quiet || printf 'sleep %ss, -> %(%c)T\n' $slp $((now+${slp%.*}+1))
    sleep $slp
}

หลังจากกำหนดตัวแปรแบบอ่านอย่างเดียวสองตัวแปรTIMER_LIST_OFFSETและTIMER_LIST_SKIPฟังก์ชันจะเข้าถึงไฟล์ตัวแปรอย่างรวดเร็ว/proc/timer_listสำหรับการคำนวณเวลาพักเครื่อง:

ฟังก์ชั่นการทดสอบเล็กน้อย

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

อาจแสดงผลเช่น:

sleep 0.244040s, -> Wed Apr 22 10:34:39 2020
2020-04-22-10:34:39.001685312
2020-04-22-10:34:39.922291769
sleep 0.077012s, -> Wed Apr 22 10:34:40 2020
2020-04-22-10:34:40.004264869
  • เริ่มต้นวินาทีถัดไป
  • เวลาพิมพ์แล้ว
  • รอ 0.92 วินาทีจากนั้น
  • เวลาพิมพ์แล้ว
  • คำนวณเหลือ 0.07 วินาทีเป็นวินาทีถัดไป
  • นอนหลับ 0.07 วินาทีจากนั้น
  • เวลาพิมพ์

ระวังอย่าผสม$EPOCHSECONDและ$EPOCHREALTIME!

อ่านคำเตือนของฉันเกี่ยวกับความแตกต่างระหว่าง$EPOCHSECONDและ$EPOCHREALTIME

ฟังก์ชันนี้ใช้$EPOCHREALTIMEจึงไม่ใช้$EPOCHSECONDเพื่อสร้างวินาทีถัดไป :

ปัญหาตัวอย่าง: การพยายามพิมพ์ครั้งต่อไปปัด 2 วินาที:

for i in 1 2;do
    printf -v nextH "%(%T)T" $(((EPOCHSECONDS/2)*2+2))
    sleepUntilHires $nextH
    IFS=. read now musec <<<$EPOCHREALTIME
    printf "%(%c)T.%s\n" $now $musec
done

อาจผลิต:

sleep 0.587936s, -> Wed Apr 22 10:51:26 2020
Wed Apr 22 10:51:26 2020.000630
sleep 86399.998797s, -> Thu Apr 23 10:51:26 2020
^C

1
ว้าว! การคำนวณนาโนวินาทีภายใต้การทุบตี !
F. Hauri

การคำนวณไมโครวินาทีภายใต้ Native bash v5 + !!
F. Hauri

หมายเหตุ Pedantic: %86400เคล็ดลับใช้ได้ผลก็ต่อเมื่อเวลาทั้งสองไม่ครอบคลุมช่วงการเปลี่ยนแปลงเวลาออมแสง
200_success

@ 200_success คุณสามารถใช้การชดเชยเวลา: ค้นหาtzoffในคำตอบของฉัน!
F. Hauri

21

ใช้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

ทุกอย่างเสร็จเรียบร้อย!


คุณควรขยายวิธีกำหนดค่าให้กับตัวแปรเนื่องจาก timeToWait = expr ... จะไม่ทำงานโดยตรงและคุณไม่สามารถใช้ backticks ได้เนื่องจากจะไม่ซ้อนกันดังนั้นคุณจะต้องใช้ $ () หรือตัวแปรชั่วคราว
SpoonMeiser

ข้อเสนอแนะที่ดี ฉันจะแก้ไขของฉันให้ชัดเจนขึ้นเพื่อไม่ให้คนเข้าใจผิด
John Feminella

หมายเหตุ-dเป็นส่วนขยายที่ไม่ใช่ POSIX จนถึงปัจจุบัน บน FreeBSD จะพยายามตั้งค่าของเคอร์เนลสำหรับเวลาออมแสง
Dave C

9

นี่คือวิธีแก้ปัญหาที่ทำงานและแจ้งให้ผู้ใช้ทราบว่าเหลือเวลาอีกเท่าไร ฉันใช้มันเกือบทุกวันเพื่อเรียกใช้สคริปต์ในตอนกลางคืน (โดยใช้ cygwin เนื่องจากฉันไม่cronสามารถทำงานบน windows ได้)

คุณสมบัติ

  • แม่นยำถึงวินาที
  • ตรวจจับการเปลี่ยนแปลงเวลาของระบบและปรับเปลี่ยน
  • เอาต์พุตอัจฉริยะบอกเวลาที่เหลือ
  • รูปแบบการป้อนข้อมูล 24 ชั่วโมง
  • คืนค่าจริงเพื่อให้สามารถเชื่อมโยงกับ &&

การเรียกใช้ตัวอย่าง

$ 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
}

8

คุณสามารถหยุดกระบวนการไม่ให้ดำเนินการได้โดยส่งสัญญาณ SIGSTOP จากนั้นให้ดำเนินการต่อโดยส่งสัญญาณ SIGCONT

ดังนั้นคุณสามารถหยุดสคริปต์ของคุณได้โดยการส่งคือ SIGSTOP:

kill -SIGSTOP <pid>

จากนั้นใช้ที่ deamon เพื่อปลุกโดยส่ง SIGCONT ในลักษณะเดียวกัน

สมมติว่าสคริปต์ของคุณจะแจ้งเมื่อต้องการให้ตื่นก่อนที่จะเข้านอน


8

บน Ubuntu 12.04.4 LTS นี่คืออินพุต bash ง่ายๆที่ใช้งานได้:

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

7

หากต้องการติดตามคำตอบของ 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
$

ฉันคิดว่าคุณต้องการกำหนดเวลา SIGCONT แทนที่จะเป็น SIGSTOP อื่นดังนั้นสัญญาณหรือความคิดเห็นไม่ถูกต้อง มิฉะนั้นยินดีที่ได้เห็นตัวอย่างที่เหมาะสม
SpoonMeiser

อ๊ะฉันพิมพ์ความคิดเห็นผิด แก้ไขแล้ว แต่คุณต้องดูโดยใช้สัญญาณตัวเลขเนื่องจากอาจแตกต่างกันได้
Dennis Williamson

ฉันพบว่าเส้นประดูเหมือนจะไม่เข้าใจ SIGCONT ดังนั้นในตอนแรกฉันใช้ -18 ซึ่งไม่ใช่แบบพกพาจากนั้นฉันพบว่ามันชอบ CONT ดังนั้นฉันจึงแก้ไขคำตอบด้านบนเพื่อแก้ไข
Dennis Williamson

6

ฉันต้องการสคริปต์ที่ตรวจสอบเฉพาะชั่วโมงและนาทีเพื่อให้ฉันสามารถเรียกใช้สคริปต์ด้วยพารามิเตอร์เดียวกันทุกวัน ฉันไม่อยากกังวลว่าพรุ่งนี้จะเป็นวันไหน ผมจึงใช้วิธีอื่น

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

(til เป็นชื่อของสคริปต์)

ไม่มีวันทำงานสายอีกต่อไปทำให้คุณพิมพ์ผิดวัน ไชโย!


4

timeToWait = $ (($ end - $ start))

ระวังว่า "timeToWait" อาจเป็นจำนวนลบ! (ตัวอย่างเช่นหากคุณระบุว่าจะเข้าสู่โหมดสลีปจนถึง "15:57" และตอนนี้เป็น "15:58") ดังนั้นคุณต้องตรวจสอบเพื่อหลีกเลี่ยงข้อผิดพลาดข้อความแปลก ๆ :

#!/bin/bash
set -o nounset

### // Sleep until some date/time. 
# // Example: sleepuntil 15:57; kdialog --msgbox "Backup needs to be done."


error() {
  echo "$@" >&2
  exit 1;
}

NAME_PROGRAM=$(basename "$0")

if [[ $# != 1 ]]; then
     error "ERROR: program \"$NAME_PROGRAM\" needs 1 parameter and it has received: $#." 
fi


current=$(date +%s.%N)
target=$(date -d "$1" +%s.%N)

seconds=$(echo "scale=9; $target - $current" | bc)

signchar=${seconds:0:1}
if [ "$signchar" = "-" ]; then
     error "You need to specify in a different way the moment in which this program has to finish, probably indicating the day and the hour like in this example: $NAME_PROGRAM \"2009/12/30 10:57\"."
fi

sleep "$seconds"

# // End of file

ทางออกที่ดี แต่ผมคิดว่า $ วินาทีคือสตริงเพื่อให้รหัสป้องกันควรจะเป็นสิ่งที่ต้องการได้รับ substring แรกเช่นดังนั้นแล้วSIGNCHAR=${SECONDS:0:1} if [ "$SIGNCHAR" = "-" ]ที่ควรทำ
H2ONaCl


1

คุณอาจใช้ 'at' เพื่อส่งสัญญาณไปยังสคริปต์ของคุณซึ่งนั่งรอสัญญาณนั้น


ฉันเพิ่งเขียนคำตอบอื่นสำหรับเอฟเฟกต์นี้
SpoonMeiser

ที่จริงแล้วไม่ของฉันแตกต่างกันเล็กน้อย
SpoonMeiser

1

ฉันเขียนhttps://tamentis.com/projects/sleepuntil/เพื่อจุดประสงค์นี้จริงๆ มันค่อนข้างฆ่ารหัสส่วนใหญ่มาจาก BSD 'at' ดังนั้นจึงเป็นไปตามมาตรฐาน:

$ sleepuntil noon && sendmail something


0

นี่คือสิ่งที่ฉันเขียนในตอนนี้เพื่อซิงโครไนซ์ไคลเอนต์ทดสอบหลายราย:

#!/usr/bin/python
import time
import sys

now = time.time()
mod = float(sys.argv[1])
until = now - now % mod + mod
print "sleeping until", until

while True:
    delta = until - time.time()
    if delta <= 0:
        print "done sleeping ", time.time()
        break
    time.sleep(delta / 2)

สคริปต์นี้จะนอนจนกว่าจะถึงเวลา "ปัด" หรือ "คม"

กรณีการใช้งานง่ายๆคือการรัน./sleep.py 10; ./test_client1.pyในเทอร์มินัลเดียวและ./sleep.py 10; ./test_client2.pyอีกเครื่อง


ความเชื่อมโยงกับคำถามของฉันอยู่ที่ไหน
theomega

มันง่ายที่จะขยายเพื่อให้untilกำหนดเป็นวันที่ / เวลาที่เฉพาะเจาะจง
Dima Tisnek

0
 function sleepuntil() {
  local target_time="$1"
  today=$(date +"%m/%d/%Y")
  current_epoch=$(date +%s)
  target_epoch=$(date -d "$today $target_time" +%s)
  sleep_seconds=$(( $target_epoch - $current_epoch ))

  sleep $sleep_seconds
}

target_time="11:59"; sleepuntil $target_time

คุณสามารถเพิ่มคำอธิบายบางประเภทลงในโซลูชันนี้ได้หรือไม่?
cdomination

นี่คือสคริปต์ทุบตี ฟังก์ชั่น sleepu จนกว่าจะใช้อาร์กิวเมนต์เดียว คุณตั้งค่าตัวแปร target_time = "11:59" หรือเวลาใดก็ตามที่คุณต้องการนอนจนถึง; จากนั้นคุณเรียกใช้ฟังก์ชันด้วยอาร์กิวเมนต์ target_time มันคำนวณว่าจะเหลือกี่วินาทีจนถึงเวลาเป้าหมายนั้นและหลับไปสำหรับวินาทีนั้น
นิคคอนสแตนติน

0

ฉันรวบรวมยูทิลิตี้ขนาดเล็กที่เรียกว่าHypnosเพื่อทำสิ่งนี้ ได้รับการกำหนดค่าโดยใช้ไวยากรณ์ crontab และบล็อกจนถึงเวลานั้น

#!/bin/bash
while [ 1 ]; do
  hypnos "0 * * * *"
  echo "running some tasks..."
  # ...
done

0

หากต้องการขยายคำตอบหลักนี่คือตัวอย่างที่ถูกต้องเกี่ยวกับการจัดการสตริงวันที่:

sleep $(($(date -f - +%s- <<< $'+3 seconds\nnow')0)) && ls

sleep $(($(date -f - +%s- <<< $'3 seconds\nnow')0)) && ls

sleep $(($(date -f - +%s- <<< $'3 second\nnow')0)) && ls

sleep $(($(date -f - +%s- <<< $'+2 minute\nnow')0)) && ls

sleep $(($(date -f - +%s- <<< $'tomorrow\nnow')0)) && ls

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

sleep $(($(date -f - +%s- <<< $'3 weeks\nnow')0)) && ls

sleep $(($(date -f - +%s- <<< $'3 week\nnow')0)) && ls

sleep $(($(date -f - +%s- <<< $'next Friday 09:00\nnow')0)) && ls

sleep $(($(date -f - +%s- <<< $'2027-01-01 00:00:01 UTC +5 hours\nnow')0)) && ls

-1

ในOpenBSDสามารถใช้สิ่งต่อไปนี้เพื่อกระชับงาน*/55 นาทีcrontab(5)ให้เป็น00หนึ่งชั่วโมง (เพื่อให้แน่ใจว่ามีการสร้างอีเมลน้อยลงในขณะที่ทำงานเดียวกันในช่วงเวลาที่แน่นอน):

#!/bin/sh -x
for k in $(jot 12 00 55)
  do
  echo $(date) doing stuff
  sleep $(expr $(date -j +%s $(printf %02d $(expr $k + 5))) - $(date -j +%s))
done

โปรดทราบว่าการออกแบบโดยการทำซ้ำครั้งสุดท้ายdate(1)จะเป็นการทำลายsleep(1)เนื่องจาก60นาทีไม่ใช่เวลาที่ถูกต้อง (เว้นแต่จะเป็น!) ดังนั้นเราจึงไม่ต้องรอเวลาเพิ่มเติมก่อนที่จะได้รับรายงานทางอีเมล

นอกจากนี้โปรดทราบว่าการทำซ้ำอย่างใดอย่างหนึ่งควรใช้เวลามากกว่า 5 นาทีที่กำหนดไว้การออกแบบก็sleepจะล้มเหลวในทำนองเดียวกันโดยการไม่นอนเลย (เนื่องจากตัวเลขเชิงลบที่ตีความว่าเป็นตัวเลือกบรรทัดคำสั่งคืออะไรแทนที่จะรวมเป็น ชั่วโมงถัดไปหรือแม้แต่ชั่วนิรันดร์) ดังนั้นให้แน่ใจว่างานของคุณยังคงสามารถดำเนินการให้เสร็จสิ้นภายในชั่วโมงที่กำหนด (เช่นหากการทำซ้ำเพียงครั้งเดียวใช้เวลานานกว่า 5 นาทีเล็กน้อยเราก็ยังมีเวลาที่จะติดตาม อะไรก็ตามที่ห่อหุ้มไว้ในชั่วโมงถัดไป)

printf(1)เป็นสิ่งจำเป็นเพราะdateคาดว่าตัวเลขสองหลักสำหรับสเปคนาที


-2

ใช้ tarry เป็นเครื่องมือที่ฉันเขียนขึ้นเพื่อทำสิ่งนี้โดยเฉพาะ

https://github.com/metaphyze/tarry/

นี่เป็นเครื่องมือบรรทัดคำสั่งง่ายๆสำหรับรอจนถึงเวลาที่กำหนด นี่ไม่เหมือนกับ "การนอนหลับ" ซึ่งจะรอเป็นระยะเวลาหนึ่ง สิ่งนี้มีประโยชน์หากคุณต้องการดำเนินการบางอย่างในเวลาที่กำหนดหรือมีแนวโน้มที่จะดำเนินการหลายอย่างในเวลาเดียวกันเช่นการทดสอบว่าเซิร์ฟเวอร์สามารถจัดการคำขอหลายรายการพร้อมกันได้หรือไม่ คุณสามารถใช้สิ่งนี้กับ "&&" บน Linux, Mac หรือ Windows:

   tarry -until=16:03:04 && someOtherCommand

ขั้นตอนนี้จะรอจนถึง 16:03:04 น. จากนั้นเรียกใช้ someOtherCommand นี่คือตัวอย่าง Linux / Mac ของวิธีการเรียกใช้คำขอหลายรายการที่กำหนดให้เริ่มต้นพร้อมกันทั้งหมด:

   for request in 1 2 3 4 5 6 7 8 9 10
   do
       tarry -until=16:03:04 && date > results.$request &
   done

ไบนารีของ Ubuntu, Linux และ Windows พร้อมใช้งานผ่านลิงก์ในหน้า

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.