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 -f
qui 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 date
deux fois, je préfère utiliser ceci:
Échantillon de départ simple
sleep $(($(date -f - +%s- <<< $'tomorrow 21:30\nnow')0))
où tomorrow 21:30
pourrait ê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: sleepUntil
etsleepUntilHires
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 printf
option pour récupérer la date, pour cette nouvelle façon de dormir jusqu'à HH: MM sans utiliser date
ou 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 $EPOCHREALTIME
variable en microsecondes. De là, il y a une sleepUntilHires
fonction.
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 -t
est 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 -t
par sleep
si 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 cron
et / ou à la at
place de tout cela)
Passer le paragraphe suivant pour les tests et les avertissements sur $ËPOCHSECONDS
!
Le noyau récent évite d'utiliser /proc/timer_list
par 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_OFFSET
et TIMER_LIST_SKIP
, la fonction accédera très rapidement au fichier de variables /proc/timer_list
pour 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 $EPOCHSECOND
et $EPOCHREALTIME
!
Lisez mon avertissement sur la différence entre $EPOCHSECOND
et$EPOCHREALTIME
Cette fonction est utilisée, $EPOCHREALTIME
donc ne l'utilisez pas $EPOCHSECOND
pour é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