基本コマンド編:項目間演算(xtcal)

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


四則演算

まず、先に作成したスクリプトxtcut.shを再利用することにする。xtcut.shをxtcal.shの名前でコピーしておこう。

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

#!/bin/bash
xtcut -f 数量,金額 -i /mnt/h00/tutorial/dat.xt |
xtcal -c '$金額/$数量' -a 単価 |
xtcut -f 単価 |
xtuniq -k 単価 |
xtsort -k 単価%n |
xtheader -l "チュートリアル" -c "xtcal" -o xtcal.xt

スクリプトの編集が終れば保存して、実行する。結果データは以下のようになっているはずである。

$ more xtcal.xt
<?xml version="1.0" encoding="euc-jp"?>
<xmltbl version="1.1">
<header>
<title>チュートリアル</title>
<comment>xtcal</comment>
<field no="1" name="単価" sort="1" numeric="1"></field>
</header>
<body><![CDATA[
59
63
64
65
66
69
70
72
74
75
78
79
81
82
--More--(9%)

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

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

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

日付関数

xtcalは日付と時間を扱う関数を多数用意している。ここでは二つの日付の日数を計算するday関数について説明する。
まず、先に作成したスクリプトxtuniq.shを再利用することにする。xtuniq.shをxtcalday.shの名前でコピーしておこう。

新しくコピーされたファイル"xtcalday.sh"を編集する。
すでにxtuniqの章で、日付の一覧を作成しているが、その日付からある固定日付(2002/06/01)までの日数を計算する。xtcalが提供する関数は、「関数名(引数1,引数2,....)」という書式で指定する。day関数は二つの引数をとり、「第一引数の日付−第二引数の日付」を計算する。そこでxtuniqコマンドの行の下に「xtcal -c 'day("20020601",$日付)' -a 日数」を挿入する。
さて、これらの処理を実現するスクリプトは以下のようになる(そして最後に、出力ファイル名(xtcalday.xt)、およびコメントの変更も忘れずに)。

#!/bin/bash
xtcut -f 日付 -i /mnt/h00/tutorial/dat.xt |
xtuniq -k 日付 |
xtcal -c 'day(20020601,$日付)' -a 日数 |
xtheader -l "チュートリアル" -c "xtcalday" -o xtcalday.xt

スクリプトの編集が終れば保存して、実行する。結果データを見れば各日付から2002/06/01までの日数(2002/06/01を超えるとマイナスの日数になる)が計算されていることが確認できるであろう。

$ more xtcalday.xt
<?xml version="1.0" encoding="euc-jp"?>
<xmltbl version="1.1">
<header>
<title>チュートリアル</title>
<comment>xtcalday</comment>
<field no="1" name="日付" sort="1"></field>
<field no="2" name="日数"></field>
</header>
<body><![CDATA[
20020101 151
20020102 150
20020103 149
20020104 148
20020105 147
20020106 146
20020107 145
20020108 144
20020109 143
20020110 142
20020111 141
20020112 140
20020113 139
--More--(8%)

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

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

数値を扱う関数

xtcalは数値を扱う関数を多数用意している。ここでは数値の四捨五入を可能とするround関数について説明する。
まず、先に作成したスクリプトxtshare.shを再利用することにする。xtshare.shをxtcal45.shの名前でコピーしておこう。

新しくコピーされたファイル"xtcal45.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」を付け加える。同じく金額シェアについても同様のコマンドを付け加える。
さて、これらの処理を実現するスクリプトは以下のようになる(そして最後に、出力ファイル名(xtcal45.xt)、およびコメントの変更も忘れずに)。

#!/bin/bash
xtcut -f 中分類,小分類,数量,金額 -i /mnt/h00/tutorial/dat.xt |
xtagg -k 中分類,小分類 -f 数量,金額 -c sum |
xtshare -k 中分類 -f 数量:数量シェア,金額:金額シェア |
xtcal -c 'round($数量シェア*100,0.01)' -a 数量シェアPCNT |
xtheader -l "チュートリアル" -c "xtcal45" -o xtcal45.xt

スクリプトの編集が終れば保存して、実行する。結果データは以下のようになっているはずである。

$ more xtcal45.xt
<?xml version="1.0" encoding="euc-jp"?>
<xmltbl version="1.1">
<header>
<title>チュートリアル</title>
<comment>xtcal45</comment>
<field no="1" name="中分類" sort="1"></field>
<field no="2" name="小分類" sort="2"></field>
<field no="3" name="数量"></field>
<field no="4" name="金額"></field>
<field no="5" name="数量シェア"></field>
<field no="6" name="金額シェア"></field>
<field no="7" name="数量シェアPCNT"></field>
</header>
<body><![CDATA[
11 1101 6247 2388930 0.182431 0.179297 18.24
11 1102 1515 546193 0.044243 0.040994 4.42
11 1103 365 145373 0.010659 0.010911 1.07
11 1104 2173 849791 0.063458 0.06378 6.35
11 1105 2249 860320 0.065678 0.06457 6.57
11 1106 1277 487220 0.037292 0.036568 3.73
11 1107 2087 913009 0.060947 0.068524 6.09
11 1108 1855 621047 0.054172 0.046612 5.42
--More--(43%)

さて、ここでxtcalコマンドが提供する他の数値関連の関数の一部を以下に示しておく。各関数がどのように動作するかについては、各自で確認しておいてもらいたい。詳しくは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() 現在処理中のキーの連番
prvField(項目名) 指定のキー内において、前行の指定項目の値を返す
topField(項目名) 指定のキー内において、先頭行の指定項目の値を返す
prvResult() 指定のキー内において、前行の演算結果を返す
topResult() 指定のキー内において、先頭行の演算結果を返す

練習課題

次のようなデータを作成しよう。スクリプト名及び結果ファイル名は表に示されたものを使おう。

帳票名 スクリプト名 結果ファイル(xt) 結果ファイル(html)
小数点以下を切り捨てた日別数量金額平均 xtcal1.sh xtcal1.xt xtcal1.html
消費税(5%)を考慮した日別金額合計(ただし小数点以下は切り捨て) xtcal2.sh xtcal2.xt xtcal2.html
本章で求めた日付リストの各日付から45日後の日付 xtcal3.sh xtcal3.xt xtcal3.html
本章で求めた日付リストの各日付から本日までの日数 xtcal4.sh xtcal4.xt xtcal4.html