Как этот вопрос был задан 4 года назад, эта первая часть касается старых версий bash:
Общий метод
Чтобы уменьшить forks
, вместо запуска date
два раза, я предпочитаю использовать это:
sleep $(($(date -f - +%s- <<< $'tomorrow 21:30\nnow')0))
, где tomorrow 21:30
может быть заменено датой и форматом любого типа, признанным date
, в будущем.
или лучше, для достижения следующий HH:MM
означает сегодня, если возможно, завтра, если слишком поздно:
sleep $((($(date -f - +%s- <<<$'21:30 tomorrow\nnow')0)%86400))
Это работает под bash , ksh и другими современными оболочками, но вы должны использовать:
sleep $(( ( $(printf 'tomorrow 21:30\nnow\n' | date -f - +%s-)0 )%86400 ))
под легче снаряды типа пепел или тире .
Новый bash way (без форка)
Поскольку моя потребность в таком инструменте никогда не превышала 24 часов, следующее касается только синтаксиса HH
, HH:MM
или HH:MM:SS
, означающего в следующие 24 часа . (В любом случае, если вам нужно больше, вы можете даже вернуться к старому методу, используя форк, к date
. Попытка исключить один форк в скрипте, работающем в течение многих дней, излишне.)
Поскольку новые версии bash действительно предлагают опцию printf
для получения даты, для этого нового способа сна до ЧЧ: ММ без использования date
или любого другого форка Я создал небольшую функцию bash . Вот оно:
sleepUntil() {
local slp tzoff now quiet=false
[ "$1" = "-q" ] && shift && quiet=true
local 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))
$quiet || printf 'sleep %ss, -> %(%c)T\n' $slp $((now+slp))
sleep $slp
}
Тогда:
sleepUntil 11:11 ; date +"Now, it is: %T"
sleep 3s, -> sam 28 sep 2013 11:11:00 CEST
Now, it is: 11:11:00
sleepUntil -q 11:11:5 ; date +"Now, it is: %T"
Now, it is: 11:11:05
Время HiRes с bash под GNU / Linux
В новейшем ядре Linux вы найдете файл переменных с именем /proc/timer_list
, в котором вы можете прочитать переменные offset
и now
, за наносекунд . Таким образом, мы можем вычислить время сна, чтобы достичь самого высокого желаемого времени.
(я написал это для генерации и отслеживания определенных событий в очень больших файлах журнала, содержащих тысячу строк в секунду).
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
}
После определения двух переменных только для чтения , TIMER_LIST_OFFSET
и TIMER_LIST_SKIP
, функция очень быстро получит доступ к файлу переменной /proc/timer_list
для вычисления времени ожидания:
sleepUntilHires 15:03 ;date +%F-%T.%N ;sleep .97;date +%F-%T.%N
sleep 19.632345552s, -> sam 28 sep 2013 15:03:00 CEST
2013-09-28-15:03:00.003471143
2013-09-28-15:03:00.976100517
sleepUntilHires -q 15:04;date -f - +%F-%T.%N < <(echo now;sleep .97;echo now)
2013-09-28-15:04:00.003608002
2013-09-28-15:04:00.974066555
И наконец
Маленькая тестовая функция
tstSleepUntilHires () {
local now next last
printf -v now "%(%s)T"
printf -v next "%(%H:%M:%S)T" $((now+1))
printf -v last "%(%H:%M:%S)T" $((now+2))
sleepUntilHires $next
date -f - +%F-%T.%N < <(echo now;sleep .92;echo now)
sleepUntilHires $last
date +%F-%T.%N
}
Может отображать что-то вроде:
sleep 0.155579469s, -> Mon Aug 20 20:42:51 2018
2018-08-20-20:42:51.005743047
2018-08-20-20:42:51.927112981
sleep 0.071764300s, -> Mon Aug 20 20:42:52 2018
2018-08-20-20:42:52.003165816
- В начале следующей секунды,
- время печати, затем
- подождите 0,92 секунды, затем
- время печати, затем
- вычислить 0,07 секунды до следующей секунды
- спать 0,07 секунды, затем
- время печати.
Примечание: .92 + 0.071 = .991
(на моем рабочем столе)