初級コマンド編 項目間演算(xtcal)

MUSASHIでは強力な項目間演算コマンドxtcalがある。xtcalコマンドでは、Excelが提供する演算子および関数と同等の機能を持つ。また項目間演算だけでなくレコード間演算も可能である(上級コマンド編で解説)。本章では、代表的なxtcalの利用方法を、「四則演算」、「日付関数」、「四捨五入」の三つについて紹介する。

四則演算

xtselの章でも簡単に触れたが、復習の意味も兼ねて、単価リストを求めるスクリプトを作成する。ここで単価リストとは、商品の単価にどのような種類があるかを示すリストのこととする。
まず、先に作成したスクリプトxtcut.shを再利用することにする。xtcut.shをxtcal1.shの名前でコピーしておこう。
新しくコピーされたファイル"xtcal1.sh"を編集する。
まずは、xtcutにて、で必要となる項目「金額」と「数量」を選択する。次に「単価=金額÷数量」なので、その計算式をxtcalコマンドで記述する。その時、計算式はxtcalと同様に、"-c"パラメータにて指定する。また、計算式にはシェルにとって特別な記号($など)が含まれるので、シングルクオーテーションで囲んでおく。計算式は'-c $金額/$数量'となる。さらに、xtcalは計算結果を新しい項目として出力するので、"-a"パラメータでその項目名を指定する。
これでxtcalの出番は終わりであるが、単価リストなので、単価の種類の一覧を出力する必要がある。そこで必要な項目単価だけをxtcutで抜き出し、行の単一化をすれば単価リストができあがる。最後に、数値昇順に並べ替えて仕上げとする。
さて、これらの処理を実現するスクリプトは以下のようになる(そして最後に、出力ファイル名(xtcal1.xt)、およびコメントの変更も忘れずに)。
スクリプトの編集が終れば保存して、実行する。結果データは各自で確認してもらいたい。単価が0円から昇順に数十種類ある表ができあがっているはずである。

#/bin/bash
#===============================================================
# MUSASHI bash script
#===============================================================

#---- タイトル
title="チュートリアル"

#---- コメント
comment="xtcal1"

#---- 各種変数(適宜修正すること)
inPath="/mnt/h00/prm/tutorial"

#---------------------------------------------------------------
# コマンド
#---------------------------------------------------------------
xtcut -f 数量,金額 -i $inPath/dat.xt.gz |
xtcal -c '$金額/$数量' -a 単価 |
xtcut -f 単価 |
xtuniq -k 単価 |
xtsort -k 単価%n |
xtheader -l "$title" -c "$comment" -o xtcal1.xt
#===============================================================

ここで下にxtcalで利用できる演算子のリストを示しておく。

算術演算子 + 足し算
- 引き算
* 掛け算
/ 割り算
% 剰余
比較演算子 == 左右の数値が等しい
< 左が右の数値より小さい
<= 左が右の数値以小
> 左が右の数値より大きい
>= 左が右の数値以上
<> 左右の数値が等しくない
-eq 左右の文字列が等しい
-gt 左が右の文字列より小さい
-ge 左が右の文字列以上
-lt 左が右の文字列より大きい
-le 左が右の文字列以下
-ne 左右の文字列が等しくない
=~ 正規表現によるパターンマッチ
論理演算子 || 左右の条件式の論理和
&& 左右の条件式の論理積

ここで、算術演算子は、左右に引数をとり、各演算の結果を返す。比較演算子も左右に引数をとり、条件に一致すれば1、一致しなければ0を返す。論理演算子は、左右に引数をとり、両方の演算結果の論理演算を行い、1もしくは0を返す。各演算子がどのように動作するかについては、各自で確認しておいてもらいたい。詳しくはxtcalのマニュアルにある例題を参照されたい。

OnePoint 定数の指定方法
演算子においても、次に示す各関数においても、扱う値の型が決められているものが多い。例えば上記の表で言えば、"-eq"は文字列比較のための演算子で、"=="は数値比較のための演算子である。項目については、演算子の種類によって内部的に変換が行われる。しかし定数の指定(例えば「金額」×100)については、数値か文字列かで指定の方法が異なる。数値に関しては数字をそのまま記述し、文字列はダブルクオーテーションで囲わなければならない。次の節にある日付型の定数は文字列として指定する。また論理型は内部的には0もしくは1のみをとる数値型として扱っている。

日付関数

xtcalは日付と時間を扱う関数を多数用意している。ここでは二つの日付の日数を計算するday関数について説明する。
まず、先に作成したスクリプトxtuniq.shを再利用することにする。xtuniq.shをxtcal2.shの名前でコピーしておこう。
新しくコピーされたファイル"xtcal2.sh"を編集する。
すでにxtuniqの章で、日付の一覧を作成しているが、その日付からある固定日付(1996/02/01)までの日数を計算する。xtcalが提供する関数は、「関数名(引数1,引数2,....)」という書式で表される。day関数は二つの引数をとり、「第一引数の日付−第二引数の日付」を計算する。そこでxtuniqコマンドの行の下に「xtcal -c 'date("19960201",$日付)' -a 日数」を挿入する。
さて、これらの処理を実現するスクリプトは以下のようになる(そして最後に、出力ファイル名(xtcal2.xt)、およびコメントの変更も忘れずに)。
スクリプトの編集が終れば保存して、実行する。結果データを見れば各日付から1996/02/01までの日数が計算されていることが確認できるであろう。

#/bin/bash
#===============================================================
# MUSASHI bash script
#===============================================================

#---- タイトル
title="チュートリアル"

#---- コメント
comment="xtcal2"

#---- 各種変数(適宜修正すること)
inPath="/mnt/h00/prm/tutorial"

#---------------------------------------------------------------
# コマンド
#---------------------------------------------------------------
xtcut -f 日付 -i $inPath/dat.xt.gz |
xtuniq -k 日付 |
xtcal -c 'day("19960201",$日付)' -a 日数 |
xtheader -l "$title" -c "$comment" -o xtcal2.xt
#===============================================================

スクリプトの編集が終れば保存して、実行する。結果データを確認すると1996年01月20日のデータが選択されていることを確認できるであろう。

さて、ここでxtcalコマンドが提供する他の日付時間関連の関数を以下に示しておく。各関数がどのように動作するかについては、各自で確認しておいてもらいたい。詳しくはxtcalのマニュアルにある例題を参照されたい。

日付時間関数 意味
age(基準日,誕生日) 年齢を計算する
datefmt(日付,書式) 日付をフォーマット変換する
dayadd(日付,日数) 日付に日数を足した日付を返す
day(日付1,日付2) 二つの日付間の日数を計算する
timefmt(時刻,書式) 時刻をフォーマット変換する
time(時刻1,時刻2) 二つの時刻間の秒数を計算する
now() 現在の時刻を求める
today() 現在の日付を求める

数値関連関数

xtcalは数値を扱う関数を多数用意している。ここでは数値の四捨五入を可能とするround関数について説明する。
まず、先に作成したスクリプトxtshare.shを再利用することにする。xtshare.shをxtcal3.shの名前でコピーしておこう。
新しくコピーされたファイル"xtcal3.sh"を編集する。
すでにxtshareの章で、日付別の数量金額シェアを作成しているが、シェアは0から1までの値で表されている。そこで、これらの数値をパーセントにし、小数点第3桁を四捨五入することを考える。
計算の手順は、まずシェア値に100を掛けてやり、小数点以下3桁目を四捨五入する。これはxtcalコマンド一行で記述することができる。round関数は、第一引数に四捨五入の対象となる数値を、第二引数に基準値を指定する。そして基準値の倍数の中で最も与えられた数値に近くなるような値に変換する。例えば「156.2841」という数値に対して基準値「10」を使うと、その基準値10の倍数の中で最も近くなる値「160」に変換される。また基準値を「0.1」にすると、0.1の倍数の中で最も近くなる値「156.3」に変換される。
ここでの課題は小数点第三桁目を四捨五入するので、基準値は「0.01」となる。そこで「xtcal -c 'round($数量シェア*100,0.01)' -a 数量シェアPCNT」を付け加える。同じく金額シェアについても同様のコマンドを付け加える。
さて、これらの処理を実現するスクリプトは以下のようになる(そして最後に、出力ファイル名(xtcal3.xt)、およびコメントの変更も忘れずに)。
スクリプトの編集が終れば保存して、実行する。結果データは各自で確認しておいてもらいたい。

#/bin/bash
#===============================================================
# MUSASHI bash script
#===============================================================

#---- タイトル
title="チュートリアル"

#---- コメント
comment="xtshare"

#---- 各種変数(適宜修正すること)
inPath="/mnt/h00/prm/tutorial"

#---------------------------------------------------------------
# コマンド
#---------------------------------------------------------------
xtcut -f 日付,数量,金額 -i $inPath/dat.xt.gz |
xtagg -k 日付 -f 数量,金額 -c sum |
xtshare -f 数量:数量シェア,金額:金額シェア |
xtcal -c 'round($数量シェア*100,0.01)' -a 数量シェアPCNT |
xtcal -c 'round($金額シェア*100,0.01)' -a 金額シェアPCNT |
xtheader -l "$title" -c "$comment" -o xtcal3.xt
#===============================================================

さて、ここでxtselコマンドが提供する他の数値関連の関数を以下に示しておく。各関数がどのように動作するかについては、各自で確認しておいてもらいたい。詳しくはxtcalのマニュアルにある例題を参照されたい。

数値関連関数 意味
sum(数値,数値,...) 数値を合計する
sqrt(数値) 平方根を計算する
power(数値,指数) 数値の巾乗を求める
abs(数値) 数値の絶対値を求める
round(数値,基準値) 基準値の倍数のある範囲内での四捨五入
up(数値,基準値) 基準値の倍数のある範囲内での切り上げ
down(数値,基準値) 基準値の倍数のある範囲内での切り捨て
exp(数値) eを底とする数値のべき乗
ln(数値) 数値の自然対数
log(数値,底) 指定の数を底とする数値の対数
log2(数値) 2を底とする数値の対数
log10(数値) 10を底とする数値の対数
pi() πを求める

その他の関数

xtcalでは、その他にも驚くほど多様な処理をこなすことができる。それらの機能の具体的な利用方法については別の章で順次紹介していくが、ここでは以下に一覧を示しておく。特に、行項目関連の関数により、多様なレコード間演算が可能となる。

その他関数 意味
文字列関数 cat(文字列,文字列,...,トークン) 文字列をトークンでつなげる
regexStart(文字列,正規表現) 正規表現にマッチする開始位置
regexEnd(文字列,正規表現) 正規表現にマッチする終端位置
regexLen(文字列,正規表現) 規表現にマッチする文字数
論理関数 if(条件,文字列1,文字列2) 件が真のとき文字列1、偽の時文字列2を返す
not(論理値) 論理値の否定
行項目関数 line() 現在処理中の行番号
fldCnt() 項目数
keyLine() 現在処理中のキー内での行番号
keyCnt() 現在処理中のキーの行数
keyNo() 現在処理中のキーの連番
prvFldA(行番号,項目名) 指定のキー内絶対行番号の項目の値を返す
prvFldR(行番号,項目名) 指定のキー内相対行番号の項目の値を返す
prvRslA(行番号,項目名) 指定のキー内絶対行番号の演算結果を返す
prvRslR(行番号,項目名) 指定のキー内相対行番号の演算結果を返す

練習課題

次のようなデータを作成しよう。