Poiché questa domanda è stata posta 4 anni fa, questa prima parte riguarda le vecchie versioni di bash:
Ultima modifica: mercoledì 22 aprile 2020, tra le 10:30 e le 10:55 (importante per la lettura di campioni)
Metodo generale (Evita fork inutili!)
(Nota: questo metodo usa date -f
che non è POSIX e non funziona con MacOS! Se sotto Mac, vai al mio purebashfunzione )
Per ridurre forks
, invece di correre date
due volte, preferisco usare questo:
Semplice esempio iniziale
sleep $(($(date -f - +%s- <<< $'tomorrow 21:30\nnow')0))
dove tomorrow 21:30
potrebbe essere sostituito da qualsiasi tipo di data e formato riconosciuto da date
, in futuro.
Con alta precisione (nanosec)
Quasi lo stesso:
sleep $(bc <<<s$(date -f - +'t=%s.%N;' <<<$'07:00 tomorrow\nnow')'st-t')
Raggiungere prossima volta
Per raggiungere il prossimoHH:MM
significato oggi se possibile, domani se troppo tardi:
sleep $((($(date -f - +%s- <<<$'21:30 tomorrow\nnow')0)%86400))
Questo funziona sotto bash, ksh e altre shell moderne, ma devi usare:
sleep $(( ( $(printf 'tomorrow 21:30\nnow\n' | date -f - +%s-)0 )%86400 ))
sotto accendino conchiglie comecenere o trattino.
Puro bash via, niente forchetta !!
Testato su MacOS!
Ho scritto una due piccole funzioni: sleepUntil
esleepUntilHires
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)
Poiché le nuove versioni di bash offrono printf
un'opzione per recuperare la data, per questo nuovo modo di dormire fino a HH: MM senza usare date
o qualsiasi altro fork, ho costruito un po 'bashfunzione. Ecco qui:
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
}
Poi:
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
Se l'obiettivo è prima , dormirà fino a domani:
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 tempo con bash sotto GNU / Linux
Recente bash, dalla versione 5.0 aggiungi una nuova $EPOCHREALTIME
variabile con microsecondi. Da questo c'è una sleepUntilHires
funzione.
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
}
Nota: questo uso read -t
che è integrato, invece di sleep
. Sfortunatamente, questo non funzionerà durante l'esecuzione in background, senza un vero TTY. Sentiti libero di sostituire read -t
con sleep
se prevedi di eseguirlo in script in background ... (Ma per il processo in background, considera l'utilizzo cron
e / o al at
posto di tutto questo)
Salta il paragrafo successivo per i test e le avvertenze $ËPOCHSECONDS
!
Il kernel recente evita l'utilizzo /proc/timer_list
da parte dell'utente !!
Sotto il recente kernel Linux, troverai un file di variabili chiamato `/ proc / timer_list` dove puoi leggere una variabile` offset` e una variabile `now`, in ** nanosecondi **. Quindi possiamo calcolare il tempo di sonno per raggiungere il tempo * massimo * desiderato.
(L'ho scritto per generare e tenere traccia di eventi specifici su file di registro molto grandi, contenenti migliaia di righe per un secondo).
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
}
Dopo aver definito due variabili di sola letturaTIMER_LIST_OFFSET
e TIMER_LIST_SKIP
, la funzione accederà molto rapidamente al file delle variabili /proc/timer_list
per il calcolo del tempo di sospensione:
Piccola funzione di test
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
}
Può rendere qualcosa come:
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
- All'inizio del secondo successivo,
- tempo di stampa, quindi
- aspetta 0,92 secondi, quindi
- tempo di stampa, quindi
- calcolare 0,07 secondi rimanenti, al secondo successivo
- dormire 0,07 secondi, quindi
- tempo di stampa.
Attenzione a non mescolare $EPOCHSECOND
e $EPOCHREALTIME
!
Leggi il mio avviso sulla differenza tra $EPOCHSECOND
e$EPOCHREALTIME
Questa funzione viene utilizzata $EPOCHREALTIME
quindi non utilizzare $EPOCHSECOND
per stabilire il secondo successivo :
Problema di esempio: tentativo di stampare l'ora successiva arrotondata di 2 secondi:
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
Può produrre:
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