[unix] dateコマンド違い

2017年7月3日月曜日

awk bash unix シェルスクリプト

ある月の土日の日付を列挙するスクリプトを作っている時に、dateコマンドの挙動がOSによってかなり違うことに気づいた。

Mac(BSD) date

最初にMac(BSD)で実行する例。
$ cal | tr -s ' ' '\n' | 
awk 'NR==2 { mm = $1 } NR==3 { yy = $1 } NR>10 { print mm,$1,yy }' | 
xargs -I{} date -j -f '%B %d %Y' {} '+%Y/%m/%d(%a)' | 
grep [土日]
2017/06/03(土)
2017/06/04(日)
2017/06/10(土)
2017/06/11(日)
2017/06/17(土)
2017/06/18(日)
2017/06/24(土)
2017/06/25(日)

GNU date

次にLinuxで同じことをしてみたところ、xargsと日付データの入力フォーマット指定がいらなくなった。
$ LC_TIME=POSIX cal | tr -s ' ' '\n' | 
awk 'NR==2 { mm=$1 } NR==3 { yy=$1 } NR>10 { print mm,$1,yy }' | 
date -f- '+%Y/%m/%d(%a)' | grep -e '[土日]'
2017/06/03(土)
2017/06/04(日)
2017/06/10(土)
2017/06/11(日)
2017/06/17(土)
2017/06/18(日)
2017/06/24(土)
2017/06/25(日)

GNU dateのいいところは以下の2点。
  1. -f オプションでファイルから日付データを受けつてくれる。-f-で標準入力から読める。
  2. 日付データの入力フォーマットを柔軟に解釈してくれる。
※ただし、どこまで頼りきれるかわからないため、上記の例ではLC_TIME=POSIXを指定して、calを実行している。

特に(1)の -f オプションは今回のように入力データが少ない場合はそれほど問題にならないけど、入力データが多くなってくると、パフォーマンスにも影響してくる。
$ date --version
date (GNU coreutils) 8.25
Copyright (C) 2016 Free Software Foundation, Inc.
ライセンス GPLv3+: GNU GPL version 3 or later .
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.

作者 David MacKenzie。

$ time LC_TIME=POSIX cal | tr -s ' ' '\n' | 
awk 'NR==2 { mm=$1 } NR==3 { yy=$1 } NR>10 { print mm,$1,yy }' | 
date -f- '+%Y/%m/%d(%a)' | grep -e '[土日]'
2017/06/03(土)
2017/06/04(日)
2017/06/10(土)
2017/06/11(日)
2017/06/17(土)
2017/06/18(日)
2017/06/24(土)
2017/06/25(日)

real    0m0.002s
user    0m0.007s
sys     0m0.000s
$ time LC_TIME=POSIX cal | tr -s ' ' '\n' | 
awk 'NR==2 { mm=$1 } NR==3 { yy=$1 } NR>10 { print mm,$1,yy }' | 
xargs -i date -d{} '+%Y/%m/%d(%a)' | grep -e '[土日]'
2017/06/03(土)
2017/06/04(日)
2017/06/10(土)
2017/06/11(日)
2017/06/17(土)
2017/06/18(日)
2017/06/24(土)
2017/06/25(日)

real    0m0.028s
user    0m0.028s
sys     0m0.008s

多くのUnixで動作させたい場合、どっちに合わせればいいんだろう。。。と思って、POSIXの仕様を調べてみたら、POSIXのdateはさらに違った。

http://pubs.opengroup.org/onlinepubs/009604599/utilities/date.html

というか、システム日時を変更せずにフォーマット変換のみする方法がない。

シェルで日付処理をどのUnixでも動くように作るのは難しそうだなぁ。。。

参考
https://linuxjm.osdn.jp/html/GNU_coreutils/man1/date.1.html
https://www.freebsd.org/cgi/man.cgi?date