ในฐานะที่เป็นคำถามนี้ถูกถาม 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))
ทำงานภายใต้ ทุบตี, ksh และเปลือกหอยสมัยใหม่อื่น ๆ แต่คุณต้องใช้:
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() {
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 () {
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
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