Như câu hỏi này đã được hỏi 4 năm trước, phần đầu tiên này liên quan đến cũ phiên bản bash:
Chỉnh sửa lần cuối: Thứ 4 ngày 22 tháng 4 năm 2020, khoảng từ 10:30 đến 10h: 55 (Quan trọng đối với việc đọc mẫu)
Phương pháp chung (Tránh các ngã ba vô dụng!)
(Nota: đây sử dụng phương pháp date -f
! Mà là không POSIX và không làm việc theo hệ điều hành MacOS Nếu dưới Mac, goto tôi tinh khiếtbấu víuchức năng )
Để giảm forks
, thay vì chạy date
hai lần, tôi thích sử dụng điều này:
Mẫu bắt đầu đơn giản
sleep $(($(date -f - +%s- <<< $'tomorrow 21:30\nnow')0))
nơi tomorrow 21:30
có thể được thay thế bằng bất kỳ loại ngày tháng và định dạng nào được công nhận date
trong tương lai.
Với độ chính xác cao (nanosec)
Gần giống nhau:
sleep $(bc <<<s$(date -f - +'t=%s.%N;' <<<$'07:00 tomorrow\nnow')'st-t')
Tiếp cận lần sau
Để đạt được ý nghĩa tiếp theoHH:MM
ngày hôm nay nếu có thể, ngày mai nếu quá muộn:
sleep $((($(date -f - +%s- <<<$'21:30 tomorrow\nnow')0)%86400))
Điều này hoạt động dưới bấu víu, ksh và các shell hiện đại khác, nhưng bạn phải sử dụng:
sleep $(( ( $(printf 'tomorrow 21:30\nnow\n' | date -f - +%s-)0 )%86400 ))
dưới lớp vỏ nhẹ hơn nhưtro hoặc là gạch ngang.
Nguyên chất bấu víu cách, không có ngã ba !!
Đã thử nghiệm trên MacOS!
Tôi đã viết một trong hai hàm nhỏ: sleepUntil
và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)
Vì các phiên bản mới của bash cung cấp một printf
tùy chọn để truy xuất ngày, đối với cách mới này để ngủ cho đến khi HH: MM sử dụng date
hoặc bất kỳ ngã ba nào khác, tôi đã xây dựng một chútbấu víuchức năng. Nó đây:
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
}
Sau đó:
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
Nếu mục tiêu nằm trước mục tiêu này sẽ ngủ cho đến ngày mai:
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 thời gian với bấu víu theo GNU / Linux
Gần đây bấu víu, từ phiên bản 5.0 thêm $EPOCHREALTIME
biến mới với micro giây. Từ đó có một sleepUntilHires
chức năng.
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
}
Xin lưu ý: công cụ sử dụng read -t
này được tích hợp sẵn, thay vì sleep
. Thật không may, điều này sẽ không hoạt động khi chạy trong nền, không có TTY thực. Vui lòng thay thế read -t
bằng sleep
nếu bạn định chạy điều này trong các tập lệnh nền ... (Nhưng đối với quy trình nền, hãy cân nhắc sử dụng cron
và / hoặc at
thay vì tất cả điều này)
Bỏ qua đoạn tiếp theo để kiểm tra và cảnh báo về $ËPOCHSECONDS
!
Kernel gần đây tránh /proc/timer_list
được người dùng sử dụng !!
Trong nhân Linux gần đây, bạn sẽ tìm thấy một tệp biến có tên `/ proc / timer_list`, nơi bạn có thể đọc một biến` offset` và một biến `now`, trong ** nano giây **. Vì vậy, chúng tôi có thể tính toán thời gian ngủ để đạt được thời gian * rất cao nhất * mong muốn.
(Tôi đã viết điều này để tạo và theo dõi các sự kiện cụ thể trên các tệp nhật ký rất lớn, chứa hàng nghìn dòng trong một giây).
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
}
Sau khi xác định hai biến chỉ đọcTIMER_LIST_OFFSET
và TIMER_LIST_SKIP
, hàm sẽ truy cập rất nhanh vào tệp biến /proc/timer_list
để tính toán thời gian ngủ:
Chức năng kiểm tra nhỏ
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
}
Có thể hiển thị một cái gì đó như:
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
- Vào đầu giây tiếp theo,
- thời gian in, sau đó
- đợi 0,92 giây, sau đó
- thời gian in, sau đó
- tính 0,07 giây còn lại, sang giây tiếp theo
- ngủ 0,07 giây, sau đó
- thời gian in.
Cẩn thận để không trộn lẫn $EPOCHSECOND
và $EPOCHREALTIME
!
Đọc cảnh báo của tôi về sự khác biệt giữa $EPOCHSECOND
và$EPOCHREALTIME
Chức năng này sử dụng $EPOCHREALTIME
vì vậy không sử dụng $EPOCHSECOND
để thiết lập giây tiếp theo :
Vấn đề mẫu: Đang cố gắng in thời gian làm tròn 2 giây tiếp theo:
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
Có thể sản xuất:
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