本連載でさまざまなコマンドの使い方について説明する際、たまに登場しているコマンド「date」は、その名前から想像される通り日付と時刻を表示するものだ。それ自体は単純な機能なのでこれまで特に説明してこなかったが、使い方次第で意外と便利に使えるケースがある。そこで今回は、このdateコマンドを取り上げよう。

dateコマンドの使い方

dateコマンドは、日付と時刻を表示する以外に「システムの時刻を設定する」という目的でも利用できる。しかし最近では、ntpdなどのデーモンで自動的に時刻を同期することが多いので、時刻を設定するためにdateコマンドを使うケースは少ないだろう(たまにしか起動しない仮想環境などでは、手っ取り早くdateコマンドで時刻を合わせることはあるかもしれない)。 CentOS 7やmacOSで実行した場合、以下のようになる。

●CentOS 7で実行した場合

[root@centos ~]# date
2017年  9月  4日 月曜日 20:44:18 JST
[root@centos ~]#

●macOSで実行した場合

/Users/daichi$ date
2017年 9月 4日 月曜日 20時44分09秒 JST
/Users/daichi$

dateコマンドには、いくつかの実装系がある。現在だと代表的なのは「GNU date」と「FreeBSD date」だろう。GNU dateはLinuxディストリビューションで使われていることが多く、FreeBSD dateはmacOSやFreeBSDで使われている。最低限の機能はどのコマンドでも実装されているが、細かい機能はそれぞれに異なっている。

例えば、あまり知られていない機能だが、現在時刻(または指定した時刻)から前後数分、数時間、数日、数カ月、数年といった期間を指定してずらした時刻を表示させるといったことができる。この機能はシンプルな実装のdateには存在しないが、GNU dateとFreeBSD dateには実装されている。利用方法は次のとおりだ。

●CentOS 7で時刻をずらして表示した場合

[root@centos ~]# date -d "1 month 10 day"
2017年 10月 14日 土曜日 20:45:17 JST
[root@centos ~]#

●macOSで時刻をずらして表示した場合

/Users/daichi$ date -v+1m -v+10d
2017年 10月14日 土曜日 20時45分25秒 JST
/Users/daichi$

「こんな機能、何に使うんだ」と思うかも知れない。だが、日付を利用するデータを扱う場合には結構頻繁に使う機会があるのだ。知っていると知っていないのとでは、いざ必要になったときの困り具合が違うので、こういった機能があるということだけは覚えておくとよいと思う。

macOSでも採用されているFreeBSD dateには、さらに時刻指定の際にフォーマットを指定できる機能がある。これがなかなか強力だ。

言葉で説明するだけだとわかりにくいので、実際に例を示しながら説明しよう。次のようなログファイルがあったとする。

192.168.185.1 - - [27/Oct/2016:11:45:09 +0900] "GET /mynavi/20161027-fossbytes-linux/typescript.html HTTP/1.1" 200 0 "-" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/55.0.2883.21 Safari/537.36"
192.168.185.1 - - [27/Oct/2016:11:45:09 +0900] "GET /mynavi/20161027-fossbytes-linux/typescript.yd HTTP/1.1" 200 0 "-" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/55.0.2883.21 Safari/537.36"
192.168.185.1 - - [27/Oct/2016:11:45:09 +0900] "GET /favicon.ico HTTP/1.1" 404 571 "http://192.168.185.50/mynavi/20161027-fossbytes-linux/typescript.html" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/55.0.2883.21 Safari/537.36"
192.168.185.1 - - [27/Oct/2016:11:52:39 +0900] "GET /mynavi/20161027-fossbytes-linux/typescript.html HTTP/1.1" 200 8153 "-" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/55.0.2883.21 Safari/537.36"
192.168.185.1 - - [27/Oct/2016:11:52:39 +0900] "GET /mynavi/20161027-fossbytes-linux/images/001raw.jpg HTTP/1.1" 200 23859 "http://192.168.185.50/mynavi/20161027-fossbytes-linux/typescript.html" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/55.0.2883.21 Safari/537.36"
192.168.185.1 - - [27/Oct/2016:11:52:40 +0900] "GET /mynavi/20161027-fossbytes-linux/typescript.yd HTTP/1.1" 200 3720 "-" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/55.0.2883.21 Safari/537.36"
192.168.185.1 - - [27/Oct/2016:11:52:42 +0900] "GET /mynavi/20161027-fossbytes-linux/typescript.html HTTP/1.1" 304 0 "-" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/55.0.2883.21 Safari/537.36"
192.168.185.1 - - [27/Oct/2016:11:53:21 +0900] "GET /mynavi/20161027-fossbytes-linux/typescript.html HTTP/1.1" 200 8714 "-" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/55.0.2883.21 Safari/537.36"
192.168.185.1 - - [27/Oct/2016:11:53:21 +0900] "GET /mynavi/20161027-fossbytes-linux/images/001raw.jpg HTTP/1.1" 304 0 "http://192.168.185.50/mynavi/20161027-fossbytes-linux/typescript.html" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/55.0.2883.21 Safari/537.36"
192.168.185.1 - - [27/Oct/2016:11:53:50 +0900] "GET /mynavi/20161027-fossbytes-linux/typescript.html HTTP/1.1" 200 8714 "-" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/55.0.2883.21 Safari/537.36"

このログファイルでは、日付データが「27/Oct/2016:11:52:39 +0900」となっているが、これがExcelで扱うにしてもプログラム的に処理するとしても、なかなか面倒な形式なのはわかってもらえるだろう。もっとこう「20161027114509」のように「年月日時分秒」といった形式になっていてほしいところだ。

FreeBSD date(macOS date)を使えば、これを簡単に変換できる。まず、連載でこれまでに紹介してきたtrコマンドとcutコマンドを使って、先ほどのログファイルから必要な部分(日付とパス)だけを抜き出すスクリプトを次のように書いたとする。

#!/bin/sh

cat access.log                                  |
tr -d '['                                       |
tr -d ']'                                       |
cut -d ' ' -f 4,5,7

これに関しては特に説明はいらないだろう。trコマンドとcutコマンドについてよくわからない場合は、復習がてら連載の第81回の記事をお読みいただきたい。 このスクリプトを実行すると、次のように日付とパスのデータだけが表示されるようになる。

% ./log2data.sh
27/Oct/2016:11:45:09 +0900 /mynavi/20161027-fossbytes-linux/typescript.html
27/Oct/2016:11:45:09 +0900 /mynavi/20161027-fossbytes-linux/typescript.yd
27/Oct/2016:11:45:09 +0900 /favicon.ico
27/Oct/2016:11:52:39 +0900 /mynavi/20161027-fossbytes-linux/typescript.html
27/Oct/2016:11:52:39 +0900 /mynavi/20161027-fossbytes-linux/images/001raw.jpg
27/Oct/2016:11:52:40 +0900 /mynavi/20161027-fossbytes-linux/typescript.yd
27/Oct/2016:11:52:42 +0900 /mynavi/20161027-fossbytes-linux/typescript.html
27/Oct/2016:11:53:21 +0900 /mynavi/20161027-fossbytes-linux/typescript.html
27/Oct/2016:11:53:21 +0900 /mynavi/20161027-fossbytes-linux/images/001raw.jpg
27/Oct/2016:11:53:50 +0900 /mynavi/20161027-fossbytes-linux/typescript.html
%

FreeBSD dateの場合、-fオプションで入力する日付のフォーマットを指定できるので、そこに「27/Oct/2016:11:52:39 +0900」に相当するフォーマットを指定してあれば、そのまま変換対象とすることができる。コマンドとしては「date -j -f “入力フォーマット” “日付データ” +”出力フォーマット”」となる。なお、「-j」は日付を変更することなく処理するために必要なオプションだ。

また、日付コマンドの入出力はロケールによって変わってくるので、ここは処理前に「en_US.UTF-8」に固定しておく。ロケールは別にこれである必要はなく、ログファイルの日付に合わせたロケールを設定しておけばよい。変換するコマンドを先ほどのスクリプトに追加すると、次のような感じになる。

#!/bin/sh

export LANG=en_US.UTF-8                         # ロケール設定

infmt="%d/%b/%Y:%H:%M:%S %z"                    # 入力日付フォーマット
outfmt="%Y%m%d%H%M%S"                           # 出力日付フォーマット

cat access.log                                  |
tr -d '['                                       |
tr -d ']'                                       |
cut -d ' ' -f 4,5,7                             |
while read a b c; do
        date -j -f "$infmt" "$a $b" +"$outfmt $c"
done

実行すると次のようになる。

% ./log2data-bsd.sh
20161027114509 /mynavi/20161027-fossbytes-linux/typescript.html
20161027114509 /mynavi/20161027-fossbytes-linux/typescript.yd
20161027114509 /favicon.ico
20161027115239 /mynavi/20161027-fossbytes-linux/typescript.html
20161027115239 /mynavi/20161027-fossbytes-linux/images/001raw.jpg
20161027115240 /mynavi/20161027-fossbytes-linux/typescript.yd
20161027115242 /mynavi/20161027-fossbytes-linux/typescript.html
20161027115321 /mynavi/20161027-fossbytes-linux/typescript.html
20161027115321 /mynavi/20161027-fossbytes-linux/images/001raw.jpg
20161027115350 /mynavi/20161027-fossbytes-linux/typescript.html
%

こうした変換をするとなると、プログラミング言語かそれなりの汎用スクリプト言語を使う必要があるように思える。だが、macOSかFreeBSDを使っている場合には、こんな感じのスクリプトで変換できるというわけだ。プログラミング言語を使う場合でもやることは基本的にあまり変わらないので、こういったことが可能だということを知っておいてもらえればと思う。

多くのコマンドがいろんなUNIX系OSに移植されているものの、ものによっては特定のLinuxディストリビューションでしか動作しないとか、*BSDにしか存在していないとか、そういうコマンドもある。オープンソースソフトウェアなので自力で移植すればよいだけの話なのだが、「いかに楽に管理するか」というこの連載の趣旨からすれば「面倒くさい」の一言に尽きるだろう。そういった場合、仮想環境に複数のOSをインストールしておいて、必要になったらそっちを使うという方法をお薦めしたいと思う。なかなか便利な方法なのでぜひとも検討していただきたい。