時刻・時間を取得する
GNU AWK(以下、gawk)は数多くのGNU拡張がなされており、その拡張の中で最初に導入されたのが時間・時刻に関する関数群です。今まではAWK 単独でUnix時間(1970年1月1日00:00からの経過秒数)をsrand()関数で裏ワザ的に取得するか、dateコマンドからパイプで受け取る方法しかありませんでした。
$ awk 'BEGIN{print srand() + srand()}' 1410325425 $ date +%s 1410325425 $ awk 'BEGIN{"date +%s" | getline; print $0}' 1410325425
最初のものは乱数の種であるsrand()関数を用いたもので、最初のsrand()関数で種を初期化し、次の srand()関数でUnix時間を返すものです。ただし、srand() 関数が必ずUnix時間を返すとは限らず、gawkがコンパイルされた環境に依存するという問題があります。
2番目のdateコマンドの"%s"というフォーマットはGNU拡張ですから、GNU拡張されていないdateコマンドでは期待した値を返さないでしょう。
また、3番目のgetlineを長いAWKプログラムで使う場合には、"date +%s"をclose()関数でクローズする必要がありますが、AWKが終了するタイミングでクローズするため、あえて明示的にクローズしていません。
ここで導入されたのがsystime()関数です。
$ gawk 'BEGIN{print systime()}' 1410325425
これによりUnix時間を簡単に取得することができるようになりました。
Unix時間が分かっても、人が理解できる時刻に変換できないと使い勝手が悪いため、導入されたのがstrftime()関数です。strftime()関数はフォーマットとUnix時間を引数として変換を行います。
$ gawk 'BEGIN{print strftime("%Y/%m/%d %H:%M:%S",1410325425)}' 2014/09/10 14:03:45
つまり、先ほどのsystime()関数と組み合わせれば、現在の時刻を人が理解できる形式で取得できます。
$ gawk 'BEGIN{print strftime("%Y/%m/%d %H:%M:%S",systime())}' 2014/09/10 14:03:45
次は逆算、つまり、人が理解できる時刻からUnix 時間に変換することが求められます。
しばらくの間、人が理解できる時刻からUnix時間への変換はAWKの関数を駆使すれば求められるため導入が遅れていましたが、現在はmktime()関数として導入されています。
$ gawk 'BEGIN{print mktime("2014 09 10 14 03 45")}' 1410325425
mktime()関数の引数は文字列として与えられ、"YYYY MM DD HH MM SS"という形式となっています。
他の言語と仕様が異なる点としては、例えば、秒に59以上の値を入れても認識してくれることが挙げられます。
$ gawk 'BEGIN{print mktime("2014 09 10 14 03 90")}' 1410325470
置換の拡張
次に拡張されたのが置換に関するものです。
置換を行う関数にはsub()関数とgsub()関数がありますが、共に戻り値が置換した個数であることや、元々の文字列を破壊的に置換することに対して、不便を感じていた人もいると思います。
加えて、従来のAWKには後方参照による置換が行えず、他の言語と比較しても便利なものとはいえませんでした。
特に、与えられた文字列を破壊せずに新たな変数に代入する場合には、次のようにいったん一時変数に代入する工夫が必要でした。
$ echo "sumomomomomomomomonouti" |\ > awk '{tmp=$0;gsub(/m/, "M", tmp);print tmp; print $0}' suMoMoMoMoMoMoMoMonouti sumomomomomomomomonouti
そこで拡張された関数がgensub()関数です。
gensub()関数は置換対象文字列を直接置換するのではなく、置換された文字列を返します。また、後方参照による置換も可能にしています。
$ echo "sumomomomomomomomonouti" |\ > gawk '{print gensub(/m/, "M", "g", $0); print $0}' suMoMoMoMoMoMoMoMonouti sumomomomomomomomonouti
gensub()関数は4つの引数をとります。最初の2つはsub()関数やgsub()関数と同じですが、3番目の引数は"1"であれば最初に出現した対象となる正規表現の置換を行い、"g"であれば全ての対象となる正規表現の置換を行います。
最後の引数は対象文字列を示しています。
なお、後方参照とは、正規表現による検索文字列のうち、丸括弧で括りグループとした部分にマッチした文字列を、置換文字列の中で\\1, \\2のようにして参照できる機能です。sedをはじめ他の言語でも似たような記述で後方参照ができます。参考のためにsedコマンドでの例も挙げておきます。
$ echo "sumomomomomomomomonouti" |\ > gawk '{print gensub(/(mo)(no)/, "\\1\"\\2\"", "g", $0)}' sumomomomomomomomo"no"uti $ echo "sumomomomomomomomonouti" |\ > sed 's/\(mo\)\(no\)/\1"\2"/g' sumomomomomomomomo"no"uti
グループにマッチした文字列を後方参照するには、\\(バックスラッシュ2文字)に数字を添えます。特にgensub()関数はシェル芸でも時々使われる関数の1つなので、覚えておくと良いでしょう。