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 datekullanmayı tercih ediyorum:
Basit başlangıç örneği
sleep $(($(date -f - +%s- <<< $'tomorrow 21:30\nnow')0))
Nerede tomorrow 21:30tarafından tanınan tarih ve biçimi her türlü yerini olabilir dategelecekte.
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 : sleepUntilvesleepUntilHires
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, printftarihi alma seçeneği sunduğundan , HH: MM'ye kadar uykunun bu yeni yolu için, kullanmadan dateveya 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 $EPOCHREALTIMEmikrosaniye ile yeni değişken ekleyin . Bundan bir sleepUntilHiresiş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 -tyerleşiktir, yerine yerleşiktir sleep. Maalesef, gerçek TTY olmadan arka planda çalışırken bu işe yaramaz. Yerine çekinmeyin read -ttarafından sleepsize ... (Ama arka plan süreci için kullanarak düşünün arkaplan script içindeki çalıştırmayı planlıyorsanız cronve / veya atyerine bütün bunların)
Testler ve uyarılar için sonraki paragrafı atlayın $ËPOCHSECONDS!
Son çekirdek /proc/timer_listkullanı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_OFFSETve TIMER_LIST_SKIPişlev, /proc/timer_listuyku 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 $EPOCHSECONDve $EPOCHREALTIME!
Ve arasındaki fark hakkındaki uyarımı oku$EPOCHSECOND$EPOCHREALTIME
Bu işlev kullanılır, $EPOCHREALTIMEbu 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