Ponieważ to pytanie zadano 4 lata temu, ta pierwsza część dotyczy starych wersji basha:
Ostatnia edycja: środa, 22 kwietnia 2020 r., Między 10:30 a 10: 55 (ważne przy czytaniu próbek)
Metoda ogólna (unikaj bezużytecznych wideł!)
(Uwaga: ta metoda date -f
nie jest POSIX i nie działa pod MacOS! Jeśli pod Mac, przejdź do mojego czystegogrzmotnąćfunkcja )
Aby zmniejszyć forks
, zamiast biegać date
dwa razy, wolę używać tego:
Prosta próbka początkowa
sleep $(($(date -f - +%s- <<< $'tomorrow 21:30\nnow')0))
gdzie w przyszłości tomorrow 21:30
może zostać zastąpiona dowolną datą i formatem rozpoznawanym przez date
.
Z wysoką precyzją (nanosec)
Prawie to samo:
sleep $(bc <<<s$(date -f - +'t=%s.%N;' <<<$'07:00 tomorrow\nnow')'st-t')
Sięgam następnym razem
Aby osiągnąć następnyHH:MM
sens dzisiaj, jeśli to możliwe, jutro, jeśli jest za późno:
sleep $((($(date -f - +%s- <<<$'21:30 tomorrow\nnow')0)%86400))
To działa pod grzmotnąć, ksh i inne nowoczesne muszle, ale musisz użyć:
sleep $(( ( $(printf 'tomorrow 21:30\nnow\n' | date -f - +%s-)0 )%86400 ))
pod lżejszymi muszlami, jakpopiół lub dziarskość.
Czysty grzmotnąć sposób, bez widelca !!
Przetestowane pod MacOS!
Napisałem jeden dwa małe funkcje: sleepUntil
isleepUntilHires
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)
Ponieważ nowe wersje basha oferują printf
opcję pobierania daty, dla tego nowego sposobu spania do GG: MM bez użycia date
lub jakiegokolwiek innego widelca, zbudowałem trochęgrzmotnąćfunkcjonować. Oto ona:
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
}
Następnie:
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
Jeśli cel jest wcześniej, będzie spał do jutra:
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
Czas HiRes z grzmotnąć pod GNU / Linux
Niedawny grzmotnąć, od wersji 5.0 dodaje nową $EPOCHREALTIME
zmienną z mikrosekundami. Z tego wynika sleepUntilHires
funkcja.
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
}
Uwaga: to użycie, read -t
które jest wbudowane, zamiast sleep
. Niestety, to nie zadziała, gdy działa w tle, bez prawdziwego TTY. Zapraszam do zastąpienia read -t
przez sleep
jeśli masz zamiar uruchomić to w skryptach tle ... (Ale za proces w tle, należy rozważyć użycie cron
i / lub at
zamiast to wszystko)
Pomiń następny akapit, aby zobaczyć testy i ostrzeżenie $ËPOCHSECONDS
!
Najnowsze jądro unika używania /proc/timer_list
przez użytkownika !!
W ostatnim jądrze Linuksa znajdziesz plik zmiennych o nazwie `/ proc / timer_list`, w którym możesz odczytać` offset` i `now` zmienną, w ciągu ** nanosekund **. Możemy więc obliczyć czas snu, aby osiągnąć * najwyższy * pożądany czas.
(Napisałem to, aby generować i śledzić określone zdarzenia w bardzo dużych plikach dziennika, zawierających tysiące wierszy przez jedną sekundę).
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
}
Po zdefiniowaniu dwóch zmiennych tylko do odczytuTIMER_LIST_OFFSET
i TIMER_LIST_SKIP
, funkcja bardzo szybko uzyska dostęp do pliku zmiennej w /proc/timer_list
celu obliczenia czasu uśpienia:
Mała funkcja testowa
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
}
Może renderować coś takiego:
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
- Na początku następnej sekundy
- czas drukowania
- poczekaj 0,92 sekundy
- czas drukowania
- oblicz pozostało 0,07 sekundy do następnej sekundy
- spać 0,07 sekundy
- czas druku.
Uważaj, aby nie mieszać $EPOCHSECOND
i $EPOCHREALTIME
!
Przeczytaj moje ostrzeżenie dotyczące różnicy między $EPOCHSECOND
a$EPOCHREALTIME
Ta funkcja jest używana, $EPOCHREALTIME
więc nie używaj $EPOCHSECOND
do ustalenia następnej sekundy :
Przykładowy problem: Następna próba wydrukowania czasu zaokrąglonego o 2 sekundy:
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
Może produkować:
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