쉘에서 두 날짜를 어떻게 비교할 수 있습니까?
다음은 그대로 사용하지 않지만 이것을 사용하고 싶은 방법의 예입니다.
todate=2013-07-18
cond=2013-07-15
if [ $todate -ge $cond ];
then
break
fi
원하는 결과를 얻으려면 어떻게해야합니까?
쉘에서 두 날짜를 어떻게 비교할 수 있습니까?
다음은 그대로 사용하지 않지만 이것을 사용하고 싶은 방법의 예입니다.
todate=2013-07-18
cond=2013-07-15
if [ $todate -ge $cond ];
then
break
fi
원하는 결과를 얻으려면 어떻게해야합니까?
답변:
정답은 여전히 없습니다.
todate=$(date -d 2013-07-18 +%s)
cond=$(date -d 2014-08-19 +%s)
if [ $todate -ge $cond ];
then
break
fi
여기에는 GNU 날짜가 필요합니다. date
BSD에 대한 동등한 구문 date
(기본적으로 OSX에 있음)은 다음과 같습니다.date -j -f "%F" 2014-08-19 +"%s"
timeout=$(`date +%Y%m%d%H%M%S` + 500)
)가 분명히 잘못되었습니다.
date -d 2013-07-18 +%s%N
비교를위한 날짜 형식이 누락되었습니다.
#!/bin/bash
todate=$(date -d 2013-07-18 +"%Y%m%d") # = 20130718
cond=$(date -d 2013-07-15 +"%Y%m%d") # = 20130715
if [ $todate -ge $cond ]; #put the loop where you need it
then
echo 'yes';
fi
루핑 구조가 누락되어 더 많은 날짜를 어떻게 계획하고 있습니까?
date
macOS와 함께 제공되는 제품 에서는 작동하지 않습니다 .
date -d
비표준이며 일반적인 UNIX에서는 작동하지 않습니다. BSD에서는 심지어 kenel 값을 설정하려고 시도합니다 DST
.
표준 문자열 비교를 사용하여 [연도, 월, 일 형식의 문자열 순서]를 비교할 수 있습니다.
date_a=2013-07-18
date_b=2013-07-15
if [[ "$date_a" > "$date_b" ]] ;
then
echo "break"
fi
고맙게도 [YYYY-MM-DD 형식을 사용하는 문자열]이 알파벳 순서로 정렬 * 될 때도 시간순으로 정렬 *됩니다.
(*-정렬 또는 비교)
이 경우에는 멋진 것이 필요하지 않습니다. 예!
if [ $(sed -e s/-//g <<< $todate) -ge $(sed -e s/-//g <<< $cond) ];
...이 날짜 형식은 표준 알파벳 숫자 정렬을 사용하여 정렬하거나 숫자 -
로 제거하고 정렬 하도록 설계되었습니다 .
이는 루프 구조의 문제가 아니라 데이터 형식의 문제입니다.
해당 날짜 ( todate
및 cond
)는 숫자가 아닌 문자열이므로의 "-ge"연산자를 사용할 수 없습니다 test
. (대괄호 표기법은 명령과 같습니다 test
.)
할 수있는 일은 날짜에 다른 표기법을 사용하여 정수가되도록하는 것입니다. 예를 들면 다음과 같습니다.
date +%Y%m%d
2013 년 7 월 15 일에 대해 20130715와 같은 정수를 생성합니다. 그런 다음 날짜를 "-ge"및 동등한 연산자와 비교할 수 있습니다.
업데이트 : 날짜가 제공되면 (예 : 2013-07-13 형식의 파일에서 날짜를 읽는 경우) tr을 사용하여 쉽게 전처리 할 수 있습니다.
$ echo "2013-07-15" | tr -d "-"
20130715
연산자 -ge
는 날짜가 아닌 정수로만 작동합니다.
스크립트가 bash 또는 ksh 또는 zsh 스크립트 인 경우 <
연산자를 대신 사용할 수 있습니다 . 이 연산자는 POSIX 표준을 크게 벗어나지 않는 대시 또는 다른 쉘에서는 사용할 수 없습니다.
if [[ $cond < $todate ]]; then break; fi
모든 셸에서 대시를 제거하여 날짜 순서를 준수하면서 문자열을 숫자로 변환 할 수 있습니다.
if [ "$(echo "$todate" | tr -d -)" -ge "$(echo "$cond" | tr -d -)" ]; then break; fi
또는 기존 방식으로 expr
유틸리티를 사용할 수 있습니다 .
if expr "$todate" ">=" "$cond" > /dev/null; then break; fi
루프에서 하위 프로세스 호출이 느릴 수 있으므로 셸 문자열 처리 구문을 사용하여 변환을 수행하는 것이 좋습니다.
todate_num=${todate%%-*}${todate#*-}; todate_num=${todate_num%%-*}${todate_num#*-}
cond_num=${cond%%-*}${cond#*-}; cond_num=${cond_num%%-*}${cond_num#*-}
if [ "$todate_num" -ge "$cond_num" ]; then break; fi
물론 처음에 하이픈없이 날짜를 검색 할 수 있으면 날짜를와 비교할 수 있습니다 -ge
.
문자열을 유닉스 타임 스탬프 (1.1.1970 0 : 0 : 0 이후의 초)로 변환합니다. 이들은 쉽게 비교할 수 있습니다
unix_todate=$(date -d "${todate}" "+%s")
unix_cond=$(date -d "${cond}" "+%s")
if [ ${unix_todate} -ge ${unix_cond} ]; then
echo "over condition"
fi
date
macOS와 함께 제공되는 제품 에서는 작동하지 않습니다 .
unix.com의 BASH 에서 간단한 날짜 및 시간 계산 이라는 제목의 기사 에서도이 방법이 있습니다.
이 함수는 해당 스레드 의 스크립트에서 발췌 한 것입니다 !
date2stamp () {
date --utc --date "$1" +%s
}
dateDiff (){
case $1 in
-s) sec=1; shift;;
-m) sec=60; shift;;
-h) sec=3600; shift;;
-d) sec=86400; shift;;
*) sec=86400;;
esac
dte1=$(date2stamp $1)
dte2=$(date2stamp $2)
diffSec=$((dte2-dte1))
if ((diffSec < 0)); then abs=-1; else abs=1; fi
echo $((diffSec/sec*abs))
}
# calculate the number of days between 2 dates
# -s in sec. | -m in min. | -h in hours | -d in days (default)
dateDiff -s "2006-10-01" "2006-10-31"
dateDiff -m "2006-10-01" "2006-10-31"
dateDiff -h "2006-10-01" "2006-10-31"
dateDiff -d "2006-10-01" "2006-10-31"
dateDiff "2006-10-01" "2006-10-31"
date
macOS와 함께 제공되는 제품 에서는 작동하지 않습니다 .
date
로 gdate
.
포크를 줄이고 bash 가 많은 트릭을 허용하기 때문에 내 목적이 있습니다.
todate=2013-07-18
cond=2013-07-15
물론 지금:
{ read todate; read cond ;} < <(date -f - +%s <<<"$todate"$'\n'"$cond")
이 두 변수를 다시 채울 $todate
와 $cond
의 ouptut으로, 하나의 포크를 사용하여, date -f -
느릅 나무 걸릴의 표준 입출력 라인으로 하나의 날짜를 읽는.
마지막으로 루프를 끊을 수 있습니다.
((todate>=cond))&&break
또는 기능으로 :
myfunc() {
local todate cond
{ read todate
read cond
} < <(
date -f - +%s <<<"$1"$'\n'"$2"
)
((todate>=cond))&&return
printf "%(%a %d %b %Y)T older than %(%a %d %b %Y)T...\n" $todate $cond
}
bash 의 내장 printf
wich를 사용하면 신기원에서 초 단위로 날짜 시간을 렌더링 할 수 있습니다 ( man bash
;- 참조)
이 스크립트는 하나의 포크 만 사용합니다.
전용 하위 프로세스가 생성됩니다 (단 하나의 포크).
mkfifo /tmp/fifo
exec 99> >(exec stdbuf -i 0 -o 0 date -f - +%s >/tmp/fifo 2>&1)
exec 98</tmp/fifo
rm /tmp/fifo
입력과 출력이 열려 있으면 fifo 항목이 삭제 될 수 있습니다.
함수:
myDate() {
local var="${@:$#}"
shift
echo >&99 "${@:1:$#-1}"
read -t .01 -u 98 $var
}
참고 : 와 같은 쓸모없는 포크를 방지하기 위해 todate=$(myDate 2013-07-18)
변수는 함수 자체에 의해 설정됩니다. 그리고 무료 구문 (날짜 문자열에 따옴표 포함 또는 제외)을 허용하려면 변수 이름 이 마지막 인수 여야합니다 .
그런 다음 날짜 비교 :
myDate 2013-07-18 todate
myDate Mon Jul 15 2013 cond
(( todate >= cond )) && {
printf "To: %(%c)T > Cond: %(%c)T\n" $todate $cond
break
}
렌더링 할 수 있습니다 :
To: Thu Jul 18 00:00:00 2013 > Cond: Mon Jul 15 00:00:00 2013
bash: break: only meaningful in a `for', `while', or `until' loop
루프 외부인 경우.
wget https://github.com/F-Hauri/Connector-bash/raw/master/shell_connector.bash
또는
wget https://f-hauri.ch/vrac/shell_connector.sh
(정확히 동일하지 않음 : .sh
소싱되지 않은 경우 전체 테스트 스크립트를 포함)
source shell_connector.sh
newConnector /bin/date '-f - +%s' @0 0
myDate 2013-07-18 todate
myDate "Mon Jul 15 2013" cond
(( todate >= cond )) && {
printf "To: %(%c)T > Cond: %(%c)T\n" $todate $cond
break
}
date -f -
리소스를 사용하여 리소스 요구 사항을 줄이는 방법에 대한 좋은 데모가 포함되어 있습니다 .
@Gilles 응답 에코 ( "연산자 -ge는 정수로만 작동")의 예는 다음과 같습니다.
curr_date=$(date +'%Y-%m-%d')
echo "$curr_date"
2019-06-20
old_date="2019-06-19"
echo "$old_date"
2019-06-19
datetime
https://stackoverflow.com/questions/10990949/convert-date-time-string-to-epoch-in-bashepoch
의 @ mike-q 답변에 따라 정수로 변환 :
curr_date_int=$(date -d "${curr_date}" +"%s")
echo "$curr_date_int"
1561014000
old_date_int=$(date -d "${old_date}" +"%s")
echo "$old_date_int"
1560927600
"$curr_date"
보다 큼 (보다 최신) "$old_date"
이지만이 표현식은 False
다음 과 같이 잘못 평가됩니다 .
if [[ "$curr_date" -ge "$old_date" ]]; then echo 'foo'; fi
... 여기에 명시 적으로 표시됩니다.
if [[ "$curr_date" -ge "$old_date" ]]; then echo 'foo'; else echo 'bar'; fi
bar
정수 비교 :
if [[ "$curr_date_int" -ge "$old_date_int" ]]; then echo 'foo'; fi
foo
if [[ "$curr_date_int" -gt "$old_date_int" ]]; then echo 'foo'; fi
foo
if [[ "$curr_date_int" -lt "$old_date_int" ]]; then echo 'foo'; fi
if [[ "$curr_date_int" -lt "$old_date_int" ]]; then echo 'foo'; else echo 'bar'; fi
bar
이 비교가 하이픈이있는 날짜 문자열에서 제대로 작동하지 않는 이유는 쉘에서 앞에 0이있는 숫자는 8 진수 (이 경우 "07") 인 것으로 가정하기 때문입니다. 제안 된 다양한 솔루션이 있지만 가장 빠르고 쉬운 방법은 하이픈을 제거하는 것입니다. Bash에는 문자열 대체 기능이있어이를 쉽고 빠르게 수행 할 수 있으며 산술 표현식으로 비교를 수행 할 수 있습니다.
todate=2013-07-18
cond=2013-07-15
if (( ${todate//-/} > ${cond//-/} ));
then
echo larger
fi