シェルで2つの日付をどのように比較できますか?
そのままでは機能しませんが、これをどのように使用したいかの例を次に示します。
todate=2013-07-18
cond=2013-07-15
if [ $todate -ge $cond ];
then
break
fi
望ましい結果を得るにはどうすればよいですか?
シェルで2つの日付をどのように比較できますか?
そのままでは機能しませんが、これをどのように使用したいかの例を次に示します。
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では、カーネル値を設定しようとします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
。
文字列をunix-timestamps(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")
これにより、1つのフォークのみを使用$todate
して$cond
、両方の変数とが再入力され、1つの日付を1行ずつ読み取るdate -f -
ためにstdioが使用されます。
最後に、ループを壊すことができます
((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
ウィッヒすることで、日付時刻をレンダリングすることができエポックからの秒見る(man bash
;-)
このスクリプトは1つのフォークのみを使用します。
これにより、専用のサブプロセス(1つのフォークのみ)が作成されます。
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