web-dev-qa-db-ja.com

Bashでの日付の解析

別々のフィールド(年、月、日、時間、分、秒)を使用して、bashの日付をさまざまな変数にどのように解析しますか?

日付形式は次のとおりです。YYYY-MM-DD hh:mm:ss

54
Steve

それはbashでなければなりませんか? GNU coreutils /bin/date多くの変換のバイナリ:

 $ date --date="2009-01-02 03:04:05" "+%d %B of %Y at %H:%M and %S seconds"
 02 January of 2009 at 03:04 and 05 seconds

これにより、指定された日付が解析され、選択した形式で表示されます。それをあなたのニーズに自由に適応させることができます。

63

これは簡単です。ダッシュとコロンをスペースに変換するだけで(IFSを変更する必要はありません)、「読み取り」をすべて1行で使用します。

read Y M D h m s <<< ${date//[-:]/ }

例えば:

$ date=$(date +'%Y-%m-%d %H:%M:%S')
$ read Y M D h m s <<< ${date//[-: ]/ }
$ echo "Y=$Y, m=$m"
Y=2009, m=57
29
NVRAM

入力時間の形式が異なっていたため、より柔軟なソリューションを紹介します。

BSD/macOSで日付を変換する

date -jf in_format [+out_format] in_date

ここで、形式はstrftimeを使用します( man strftime を参照)。

指定された入力形式YYYY-MM-DD hh:mm:ssの場合:

$ date -jf '%Y-%m-%d %H:%M:%S' '2017-05-10 13:40:01'
Wed May 10 13:40:01 PDT 2017

それらを別々の変数に読み込むために、NVRAMのアイデアを取り入れていますが、任意のstrftime形式を使用できます。

$ date_in='2017-05-10 13:40:01'

$ format='%Y-%m-%d %H:%M:%S'

$ read -r y m d H M S <<< "$(date -jf "$format" '+%Y %m %d %H %M %S' "$date_in")"

$ for var in y m d H M S; do echo "$var=${!var}"; done
y=2017
m=05
d=10
H=13
M=40
S=01

スクリプトでは、 常にread -r を使用します。

私の場合、タイムゾーン間で変換したかった(ゾーン名については/usr/share/zoneinfoディレクトリを参照):

$ format=%Y-%m-%dT%H:%M:%S%z

$ TZ=UTC date -jf $format +$format 2017-05-10T02:40:01+0200
2017-05-10T00:40:01+0000

$ TZ=America/Los_Angeles date -jf $format +$format 2017-05-10T02:40:01+0200
2017-05-09T17:40:01-0700

GNU/Linuxで日付を変換する

Macでは、GNUバージョンのdatebrew install coreutilsgdateとしてインストールできます。

date [+out_format] -d in_date

out_formatはstrftimeを使用します( man strftime を参照)。

GNU coreutils 'dateコマンドでは、入力フォーマット自体を把握しようとするため、入力フォーマットを明示的に設定する方法はありません。詳細については、 coreutils:日付入力形式 でマニュアルを読むことができます。

例えば:

$ date '+%Y %m %d %H %M %S' -d '2017-05-10 13:40:01'
2017 05 10 13 40 01

それらを別々の変数に読み込むには、括弧内のコマンドをGNUバージョンに置き換えて、Macセクションのコマンドを変更します。

タイムゾーン間で変換するには(ゾーン名については/usr/share/zoneinfoディレクトリを参照)、入力文字列でTZ="America/Los_Angeles"を指定できます。ゾーン名を囲むリテラル"文字、およびin_dateの前のスペース文字に注意してください。

TZ=out_tz date [+out_format] 'TZ="in_tz" 'in_date

例えば:

$ format='%Y-%m-%d %H:%M:%S%z'

$ TZ=America/Los_Angeles date +"$format" -d 'TZ="UTC" 2017-05-10 02:40:01'
2017-05-09 19:40:01-0700

$ TZ=UTC date +"$format" -d 'TZ="America/Los_Angeles" 2017-05-09 19:40:01'
2017-05-10 02:40:01+0000

GNU日付は、タイムゾーンの時間オフセットも理解します。

$ TZ=UTC date +"$format" -d '2017-05-09 19:40:01-0700'
2017-05-10 02:40:01+0000
16
$ t='2009-12-03 12:38:15'
$ a=(`echo $t | sed -e 's/[:-]/ /g'`)
$ echo ${a[*]}
2009 12 03 12 38 15
$ echo ${a[3]}
12
7
DigitalRoss

おそらく配列メソッドの方が優れていますが、これはあなたが特に求めていたものです。

IFS=" :-"
read year month day hour minute second < <(echo "YYYY-MM-DD hh:mm:ss")
5
Steve Baker

純粋なバッシュ:

date="2009-12-03 15:35:11"
saveIFS="$IFS"
IFS="- :"
date=($date)
IFS="$saveIFS"
for field in "${date[@]}"
do
    echo $field
done

2009
12
03
15
35
11
3

シェルスクリプトを使用する代わりに、必要に応じて次のようにスクリプト自体に組み込みます。

a=date +%Y 
b=date +%S
c=date +%H

aは年、bは秒、cは時間です。等々。

2
Vijay

OPの問題の別の解決策:

IFS=' -:' read y m d h m s<<<'2014-03-26 16:36:41'

BSD dateおよびGNU date:を使用した日付の別の形式への変換

$ LC_ALL=C date -jf '%a %b %e %H:%M:%S %Z %Y' 'Wed Mar 26 16:36:41 EET 2014' +%F\ %T
2014-03-26 16:36:41
$ gdate -d 'Wed Mar 26 16:36:41 EET 2014' +%F\ %T
2014-03-26 16:36:41

GNU dateは、英語以外のロケールでもWedおよびMarを認識しますが、BSD dateは認識しません。

GNU日付とBSD日付を使用して、エポックからの秒数を日付と時刻に変換します。

$ gdate -d @1234567890 '+%F %T'
2009-02-14 01:31:30
$ date -r 1234567890 '+%F %T'
2009-02-14 01:31:30

POSIXシェル、POSIX awk、GNU date、およびBSD date:を使用して秒を時間、分、および秒に変換します。

$ s=12345;printf '%02d:%02d:%02d\n' $((s/3600)) $((s%3600/60)) $((s%60))
05:25:45
$ echo 12345|awk '{printf "%02d:%02d:%02d\n",$0/3600,$0%3600/60,$0%60}'
05:25:45
$ gdate -d @12345 +%T
05:25:45
$ date -r 12345 +%T
05:25:45

秒を日、時間、分、および秒に変換する:

$ t=12345678
$ printf '%d:%02d:%02d:%02d\n' $((t/86400)) $((t/3600%24)) $((t/60%60)) $((t%60))
142:21:21:18
2
Lri

別の純粋なバッシュ

$ d="2009-12-03 15:35:11"
$ d=${d//[- :]/|}
$ IFS="|"
$ set -- $d
$ echo $1
2009
$ echo $2
12
$ echo $@
2009 12 03 15 35 11
1
ghostdog74

カットを使ってみましたか?次のようなもの:dayofweek = date|cut -d" " -f1

0
Jay