Bu soru 4 yıl önce sorulduğu için, bu ilk bölüm eski bash sürümleriyle ilgilidir :
Son düzenleme: 22 Nisan 2020, Çar, 10:30 ile 10:00 saatleri arasında: 55 (Örnekleri okumak için önemlidir)
Genel yöntem (Yararsız çatallardan kaçının!)
(Nota: Bu yöntem kullanılırken date -f
! Hayır POSIX ve Mac altında MacOS If altında işlerine yok wich benim goto, safbashişlevi )
Azaltmak için iki kez forks
çalıştırmak yerine şunu date
kullanmayı tercih ediyorum:
Basit başlangıç örneği
sleep $(($(date -f - +%s- <<< $'tomorrow 21:30\nnow')0))
Nerede tomorrow 21:30
tarafından tanınan tarih ve biçimi her türlü yerini olabilir date
gelecekte.
Yüksek hassasiyetle (nanosec)
Hemen hemen aynı:
sleep $(bc <<<s$(date -f - +'t=%s.%N;' <<<$'07:00 tomorrow\nnow')'st-t')
Bir dahaki sefere ulaşıyorum
Mümkünse bugün, çok geç ise yarın sonrakiHH:MM
anlama ulaşmak için :
sleep $((($(date -f - +%s- <<<$'21:30 tomorrow\nnow')0)%86400))
Bu altında çalışır bash, ksh ve diğer modern mermiler, ancak kullanmanız gerekir:
sleep $(( ( $(printf 'tomorrow 21:30\nnow\n' | date -f - +%s-)0 )%86400 ))
gibi daha hafif kabukların altındakül veya kısa çizgi.
Saf bash yol, çatal yok !!
MacOS altında test edildi!
Bir iki küçük işlev yazdım : sleepUntil
vesleepUntilHires
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'in yeni sürümleri, printf
tarihi alma seçeneği sunduğundan , HH: MM'ye kadar uykunun bu yeni yolu için, kullanmadan date
veya başka bir çatal kullanmadan, biraz geliştirdimbashişlevi. İşte burada:
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
}
Sonra:
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
Hedef ise daha önce yarına kadar bu irade uyku:
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 ile zaman bash GNU / Linux altında
Son bash5.0 sürümünden itibaren $EPOCHREALTIME
mikrosaniye ile yeni değişken ekleyin . Bundan bir sleepUntilHires
işlev var.
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
}
Lütfen unutmayın: bu kullanım read -t
yerleşiktir, yerine yerleşiktir sleep
. Maalesef, gerçek TTY olmadan arka planda çalışırken bu işe yaramaz. Yerine çekinmeyin read -t
tarafından sleep
size ... (Ama arka plan süreci için kullanarak düşünün arkaplan script içindeki çalıştırmayı planlıyorsanız cron
ve / veya at
yerine bütün bunların)
Testler ve uyarılar için sonraki paragrafı atlayın $ËPOCHSECONDS
!
Son çekirdek /proc/timer_list
kullanıcı tarafından kullanmaktan kaçının !!
En son Linux çekirdeği altında, ** nanosaniye ** içinde bir "offset" ve "now" değişkenini okuyabileceğiniz "/ proc / timer_list" adlı bir değişken dosyası bulacaksınız. Böylece, istenen * en üst * zamana ulaşmak için uyku süresini hesaplayabiliriz.
(Bunu, bir saniye için bin satır içeren çok büyük günlük dosyalarında belirli olayları oluşturmak ve izlemek için yazdım).
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
}
İki salt okunur değişkeni tanımladıktan sonra TIMER_LIST_OFFSET
ve TIMER_LIST_SKIP
işlev, /proc/timer_list
uyku süresini hesaplamak için değişken dosyasına çok hızlı bir şekilde erişecektir :
Küçük test işlevi
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
}
Şunun gibi bir şey oluşturabilir:
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
- Sonraki saniyenin başında,
- baskı zamanı, sonra
- 0,92 saniye bekleyin, sonra
- baskı zamanı, sonra
- 0.07 saniye kaldı, sonraki saniyeye hesapla
- 0,07 saniye uyu, sonra
- baskı süresi.
Karıştırmamaya özen gösterin $EPOCHSECOND
ve $EPOCHREALTIME
!
Ve arasındaki fark hakkındaki uyarımı oku$EPOCHSECOND
$EPOCHREALTIME
Bu işlev kullanılır, $EPOCHREALTIME
bu nedenle sonraki saniyeyi$EPOCHSECOND
oluşturmak için kullanmayın :
Örnek sorun: Sonraki 2 saniyeye yuvarlanan süreyi yazdırmaya çalışma:
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
Üretebilir:
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