Comme cette question a été posée il y a 4 ans, cette première partie concerne les anciennes versions de bash:
Dernière édition: mercredi 22 avril 2020, quelque chose entre 10h30 et 10h: 55 (Important pour la lecture d'échantillons)
Méthode générale (évitez les fourches inutiles!)
(Nota: cette méthode utilise date -fqui n'est pas POSIX et ne fonctionne pas sous MacOS! Si sous Mac, allez à mon purfrapperfonction )
Afin de réduire forks, au lieu de courir datedeux fois, je préfère utiliser ceci:
Échantillon de départ simple
sleep $(($(date -f - +%s- <<< $'tomorrow 21:30\nnow')0))
où tomorrow 21:30pourrait être remplacé par tout type de date et de format reconnu par date, à l'avenir.
Avec haute précision (nanosec)
Presque pareil:
sleep $(bc <<<s$(date -f - +'t=%s.%N;' <<<$'07:00 tomorrow\nnow')'st-t')
Atteindre prochaine fois
Pour atteindre le prochainHH:MM sens aujourd'hui si possible, demain si trop tard:
sleep $((($(date -f - +%s- <<<$'21:30 tomorrow\nnow')0)%86400))
Cela fonctionne sous frapper, ksh et d'autres shells modernes, mais vous devez utiliser:
sleep $(( ( $(printf 'tomorrow 21:30\nnow\n' | date -f - +%s-)0 )%86400 ))
sous plus léger coques commecendre ou tiret.
Pur frapper façon, pas de fourchette !!
Testé sous MacOS!
J'ai écrit une deux petites fonctions: sleepUntiletsleepUntilHires
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)
Comme les nouvelles versions de bash offrent une printfoption pour récupérer la date, pour cette nouvelle façon de dormir jusqu'à HH: MM sans utiliser dateou tout autre fork, j'ai construit un peufrapperfonction. C'est ici:
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
}
Ensuite:
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
Si l'objectif est avant, cela dormira jusqu'à demain:
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
Temps HiRes avec frapper sous GNU / Linux
Récent frapper, à partir de la version 5.0, ajoutez une nouvelle $EPOCHREALTIMEvariable en microsecondes. De là, il y a une sleepUntilHiresfonction.
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
}
Remarque: cette utilisation read -test intégrée à la place de sleep. Malheureusement, cela ne fonctionnera pas lors de l'exécution en arrière-plan, sans vrai TTY. N'hésitez pas à remplacer read -tpar sleepsi vous prévoyez d'exécuter ceci dans des scripts d'arrière-plan ... (Mais pour le processus d'arrière-plan, envisagez d'utiliser cronet / ou à la atplace de tout cela)
Passer le paragraphe suivant pour les tests et les avertissements sur $ËPOCHSECONDS!
Le noyau récent évite d'utiliser /proc/timer_listpar l'utilisateur !!
Sous le noyau Linux récent, vous trouverez un fichier de variables nommé `/ proc / timer_list` où vous pourrez lire un` offset` et une variable `now`, en ** nanosecondes **. Nous pouvons donc calculer le temps de sommeil pour atteindre le temps * très haut * souhaité.
(J'ai écrit ceci pour générer et suivre des événements spécifiques sur de très gros fichiers journaux, contenant mille lignes pendant une seconde).
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
}
Après avoir défini deux variables en lecture seule , TIMER_LIST_OFFSETet TIMER_LIST_SKIP, la fonction accédera très rapidement au fichier de variables /proc/timer_listpour le calcul du temps de sommeil:
Petite fonction de 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
}
Peut rendre quelque chose comme:
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
- Au début de la seconde suivante,
- temps d'impression, puis
- attendez 0,92 seconde, puis
- temps d'impression, puis
- calculer 0,07 seconde à la seconde suivante
- dormir 0,07 seconde, puis
- temps d'impression.
Attention à ne pas mélanger $EPOCHSECONDet $EPOCHREALTIME!
Lisez mon avertissement sur la différence entre $EPOCHSECONDet$EPOCHREALTIME
Cette fonction est utilisée, $EPOCHREALTIMEdonc ne l'utilisez pas $EPOCHSECONDpour établir la seconde suivante :
Exemple de problème: tentative d'impression de l'heure suivante arrondie de 2 secondes:
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
Peut produire:
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