Bash : 특정 시간 / 날짜까지 잠자기
내 bash 스크립트가 특정 시간까지 잠자기를 원합니다. 그래서 저는 "sleep"과 같은 명령을 원합니다.이 명령은 간격이 걸리지 않고 종료 시간이 걸리고 그때까지 잠을 잔다.
특정 날짜 / 시간까지 실행중인 스크립트를 차단해야하므로 "at"-daemon은 해결책이 아닙니다.
그런 명령이 있습니까?
Outlaw Programmer가 언급했듯이 해결책은 정확한 시간 (초) 동안 잠자는 것입니다.
bash에서이를 수행하려면 다음을 수행하십시오.
current_epoch=$(date +%s)
target_epoch=$(date -d '01/01/2010 12:00' +%s)
sleep_seconds=$(( $target_epoch - $current_epoch ))
sleep $sleep_seconds
정밀도를 나노초 (효과적으로 약 밀리 초 정도)까지 추가하려면 다음 구문을 사용하십시오.
current_epoch=$(date +%s.%N)
target_epoch=$(date -d "20:25:00.12345" +%s.%N)
sleep_seconds=$(echo "$target_epoch - $current_epoch"|bc)
sleep $sleep_seconds
참고 맥 OS / OS X 초 이하의 정밀도를 지원하지 않습니다, 당신은 사용해야합니다 coreutils
에서 brew
→ 대신에 이 지침을 참조하십시오
를 사용 sleep
하되를 사용하여 시간을 계산합니다 date
. date -d
이것을 사용하고 싶을 것 입니다. 예를 들어 다음 주까지 기다렸다 고 가정 해 보겠습니다.
expr `date -d "next week" +%s` - `date -d "now" +%s`
"다음 주"를 기다릴 날짜로 대체 한 다음이 표현식을 값에 할당하고 몇 초 동안 잠자기 만하면됩니다.
startTime=$(date +%s)
endTime=$(date -d "next week" +%s)
timeToWait=$(($endTime- $startTime))
sleep $timeToWait
다 했어요!
이 질문은 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 방식 (포크 없음)
도구의 이런 종류의 내 필요가 24 시간 내에 있다면 제한은 없다 바와 같이, 다음은 유일한 관심사 것 HH
, HH:MM
또는 HH:MM:SS
구문 의미를 24 시간에 . (어쨌든 더 필요한 경우에는 fork to를 사용하여 이전 방법으로 돌아갈 수도 date
있습니다. 며칠 동안 실행되는 스크립트에서 하나의 포크를 제거하려는 것은 과잉입니다.)
새로운 버전의 bash는 printf
날짜를 검색 하는 옵션을 제공하므로 HH : MM까지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
GNU / Linux 에서 bash 를 사용한 HiRes 시간
최근 Linux 커널에서는 나노초 단위로 및 변수를 /proc/timer_list
읽을 수있는 변수 파일을 찾을 수 있습니다. 그래서 우리는 가장 원하는 시간 에 도달하기 위해 수면 시간을 계산할 수 있습니다 .offset
now
(1 초 동안 수천 줄을 포함하는 매우 큰 로그 파일에서 특정 이벤트를 생성하고 추적하기 위해 이것을 작성했습니다.)
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
(내 데스크톱에서)
SIGSTOP 신호를 보내 프로세스 실행을 중지 한 다음 SIGCONT 신호를 보내 실행을 재개 할 수 있습니다.
따라서 SIGSTOP을 전송하여 스크립트를 중지 할 수 있습니다.
kill -SIGSTOP <pid>
그런 다음 at deamon을 사용하여 동일한 방식으로 SIGCONT를 전송하여 깨우십시오.
아마도 스크립트는 잠자기 전에 깨어나기를 원할 때 알려줄 것입니다.
Ubuntu 12.04.4 LTS에서 작동하는 간단한 bash 입력은 다음과 같습니다.
sleep $(expr `date -d "03/21/2014 12:30" +%s` - `date +%s`)
SpoonMeiser의 답변을 따르기 위해 다음은 구체적인 예입니다.
$cat ./reviveself
#!/bin/bash
# save my process ID
rspid=$$
# schedule my own resuscitation
# /bin/sh seems to dislike the SIGCONT form, so I use CONT
# at can accept specific dates and times as well as relative ones
# you can even do something like "at thursday" which would occur on a
# multiple of 24 hours rather than the beginning of the day
echo "kill -CONT $rspid"|at now + 2 minutes
# knock myself unconscious
# bash is happy with symbolic signals
kill -SIGSTOP $rspid
# do something to prove I'm alive
date>>reviveself.out
$
매일 같은 매개 변수로 스크립트를 실행할 수 있도록 시간과 분만 확인하는 스크립트를 원했습니다. 내일이 어느 날이 될지 걱정하고 싶지 않습니다. 그래서 저는 다른 접근 방식을 사용했습니다.
target="$1.$2"
cur=$(date '+%H.%M')
while test $target != $cur; do
sleep 59
cur=$(date '+%H.%M')
done
스크립트의 매개 변수는 시간과 분이므로 다음과 같이 작성할 수 있습니다.
til 7 45 && mplayer song.ogg
(til은 스크립트의 이름입니다)
직장에서 더 이상 늦게까지 일을 잘못 입력하지 않습니다. 건배!
다음은 작업을 수행하고 사용자에게 남은 시간을 알려주는 솔루션입니다. 나는 밤에 스크립트를 실행하기 위해 거의 매일 사용합니다 ( cron
창에서 작업 할 수 없었기 때문에 cygwin 사용 )
풍모
- 초까지 정밀함
- 시스템 시간 변화를 감지하고 적응
- 남은 시간을 알려주는 지능형 출력
- 24 시간 입력 형식
- 연결할 수 있도록 true를 반환합니다.
&&
샘플 실행
$ til 13:00 && date
1 hour and 18 minutes and 26 seconds left...
1 hour and 18 minutes left...
1 hour and 17 minutes left...
1 hour and 16 minutes left...
1 hour and 15 minutes left...
1 hour and 14 minutes left...
1 hour and 10 minutes left...
1 hour and 5 minutes left...
1 hour and 0 minutes left...
55 minutes left...
50 minutes left...
45 minutes left...
40 minutes left...
35 minutes left...
30 minutes left...
25 minutes left...
20 minutes left...
15 minutes left...
10 minutes left...
5 minutes left...
4 minutes left...
3 minutes left...
2 minutes left...
1 minute left...
Mon, May 18, 2015 1:00:00 PM
(마지막 날짜는 함수의 일부가 아니지만 && date
)
암호
til(){
local hour mins target now left initial sleft correction m sec h hm hs ms ss showSeconds toSleep
showSeconds=true
[[ $1 =~ ([0-9][0-9]):([0-9][0-9]) ]] || { echo >&2 "USAGE: til HH:MM"; return 1; }
hour=${BASH_REMATCH[1]} mins=${BASH_REMATCH[2]}
target=$(date +%s -d "$hour:$mins") || return 1
now=$(date +%s)
(( target > now )) || target=$(date +%s -d "tomorrow $hour:$mins")
left=$((target - now))
initial=$left
while (( left > 0 )); do
if (( initial - left < 300 )) || (( left < 300 )) || [[ ${left: -2} == 00 ]]; then
# We enter this condition:
# - once every 5 minutes
# - every minute for 5 minutes after the start
# - every minute for 5 minutes before the end
# Here, we will print how much time is left, and re-synchronize the clock
hs= ms= ss=
m=$((left/60)) sec=$((left%60)) # minutes and seconds left
h=$((m/60)) hm=$((m%60)) # hours and minutes left
# Re-synchronise
now=$(date +%s) sleft=$((target - now)) # recalculate time left, multiple 60s sleeps and date calls have some overhead.
correction=$((sleft-left))
if (( ${correction#-} > 59 )); then
echo "System time change detected..."
(( sleft <= 0 )) && return # terminating as the desired time passed already
til "$1" && return # resuming the timer anew with the new time
fi
# plural calculations
(( sec > 1 )) && ss=s
(( hm != 1 )) && ms=s
(( h > 1 )) && hs=s
(( h > 0 )) && printf %s "$h hour$hs and "
(( h > 0 || hm > 0 )) && printf '%2d %s' "$hm" "minute$ms"
if [[ $showSeconds ]]; then
showSeconds=
(( h > 0 || hm > 0 )) && (( sec > 0 )) && printf %s " and "
(( sec > 0 )) && printf %s "$sec second$ss"
echo " left..."
(( sec > 0 )) && sleep "$sec" && left=$((left-sec)) && continue
else
echo " left..."
fi
fi
left=$((left-60))
sleep "$((60+correction))"
correction=0
done
}
timeToWait = $ (($ end-$ start))
"timeToWait"는 음수 일 수 있습니다. (예를 들어, "15:57"까지 절전 모드로 지정하고 지금은 "15:58"로 지정하는 경우). 따라서 이상한 메시지 오류를 방지하기 위해 확인해야합니다.
#!/bin/bash
set -o nounset
### // Sleep until some date/time.
# // Example: sleepuntil 15:57; kdialog --msgbox "Backup needs to be done."
error() {
echo "$@" >&2
exit 1;
}
NAME_PROGRAM=$(basename "$0")
if [[ $# != 1 ]]; then
error "ERROR: program \"$NAME_PROGRAM\" needs 1 parameter and it has received: $#."
fi
current=$(date +%s.%N)
target=$(date -d "$1" +%s.%N)
seconds=$(echo "scale=9; $target - $current" | bc)
signchar=${seconds:0:1}
if [ "$signchar" = "-" ]; then
error "You need to specify in a different way the moment in which this program has to finish, probably indicating the day and the hour like in this example: $NAME_PROGRAM \"2009/12/30 10:57\"."
fi
sleep "$seconds"
# // End of file
지금부터 깨우기 시간까지의 시간 (초)을 계산하고 기존 'sleep'명령을 사용할 수 있습니다.
아마도 'at'를 사용하여 신호를 기다리는 스크립트에 신호를 보낼 수 있습니다.
function sleepuntil() {
local target_time="$1"
today=$(date +"%m/%d/%Y")
current_epoch=$(date +%s)
target_epoch=$(date -d "$today $target_time" +%s)
sleep_seconds=$(( $target_epoch - $current_epoch ))
sleep $sleep_seconds
}
target_time="11:59"; sleepuntil $target_time
이를 위해 Hypnos 라는 작은 유틸리티 를 구성했습니다. crontab 구문을 사용하여 구성되고 그 때까지 차단됩니다.
#!/bin/bash
while [ 1 ]; do
hypnos "0 * * * *"
echo "running some tasks..."
# ...
done
Here's something I wrote just now to synchronise multiple test clients:
#!/usr/bin/python
import time
import sys
now = time.time()
mod = float(sys.argv[1])
until = now - now % mod + mod
print "sleeping until", until
while True:
delta = until - time.time()
if delta <= 0:
print "done sleeping ", time.time()
break
time.sleep(delta / 2)
This script sleeps until next "rounded" or "sharp" time.
A simple use case is to run ./sleep.py 10; ./test_client1.py
in one terminal and ./sleep.py 10; ./test_client2.py
in another.
On OpenBSD, the following could be used to compact a */5
5-minute crontab(5)
job into an 00
hourly one (to make sure fewer emails are generated, all whilst performing the same task at exact intervals):
#!/bin/sh -x
for k in $(jot 12 00 55)
do
echo $(date) doing stuff
sleep $(expr $(date -j +%s $(printf %02d $(expr $k + 5))) - $(date -j +%s))
done
Note that the date(1)
would also break the sleep(1)
by design on the final iteration, as 60
minutes is not a valid time (unless it is!), thus we won't have to wait any extra time prior to getting our email report.
Also note that should one of the iterations take more than 5 minutes allotted to it, the sleep
would likewise graciously fail by design by not sleeping at all (due to what is a negative number interpreted as a command-line option, instead of wrapping around to the next hour or even eternity), thus making sure your job could still complete within the hour allotted (e.g., if only one of the iterations takes a little bit more than 5 minutes, then we would still have the time to catch up, without anything wrapping around to the next hour).
The printf(1)
is needed because date
expects exactly two digits for the minute specification.
이 정확한 목적을 위해 실제로 https://tamentis.com/projects/sleepuntil/ 썼습니다 . 대부분의 코드는 BSD 'at'에서 온 것이므로 상당히 표준을 준수합니다.
$ sleepuntil noon && sendmail something
참고 URL : https://stackoverflow.com/questions/645992/bash-sleep-until-a-specific-time-date
'IT TIP' 카테고리의 다른 글
이름으로 수업 받기 (0) | 2020.10.23 |
---|---|
$ (document) .on ( "click"… 작동하지 않습니까? (0) | 2020.10.23 |
이동 중에 변수를 유지하는 방법이 있습니까? (0) | 2020.10.23 |
내용을 기반으로 문자열 목록 필터링 (0) | 2020.10.23 |
':'문자, 16 진수 값 0x3A는 이름에 포함될 수 없습니다. (0) | 2020.10.23 |