2023年の新年早々、ふとしたことから こんな図が必要になりました。
ledger-cli のアカウント(勘定科目)構造を 樹状図 にしたいということです。
もしかしたらledger-cliに備え付けのコマンドとかオプションがあるかもしれないと思い検索してみましたが見当たりません。
そこで急いで自前で用意することにしました。基本的な方針はつぎのとおりです。
- Ledger-cliの
accounts
コマンドを使ってアカウント(勘定科目)一覧を表示します。出力(抜粋)は下のような感じです。: Expenses:Cars:Gasoline Expenses:Cars:Parking Expenses:Cars:Toll Expenses:Cars:保険:任意保険 Expenses:Cars:保険:自賠責 :
- この出力を1行ずつ読み込んでコロンをスラッシュに変換します。
: Expenses/Cars/Gasoline Expenses/Cars/Parking Expenses/Cars/Toll Expenses/Cars/保険/任意保険 Expenses/Cars/保険/自賠責 :
- これを
mkdir -p
に読ませて、ディレクトリ・サブディレクトリ構造を作ります - それを
tree
コマンド1 を使って表示します
コード
具体的な方法はつぎのとおりです。
- 任意の場所に ACCOUNT という親ディレクトリを作る
- 樹状図に書き出す範囲(期間、アカウントなど)は原則としてledger-cliにビルトインされているオプションを使って絞り込む
- ディレクトリ階層=アカウントの深度だけはledger-cliの
--depth
ではなくてtree
コマンドの-L
オプションで指定する(なぜそうするかは「(補)アカウント深度だけtreeを使うわけ」節を参照してください)。
#!/bin/bash
# LedgerのA/C構造を樹状図にするスクリプト
# Ledgerのパラメータがそのまま使える
base_dir="/home/yamagami/local-ledger-directory/test-arena/tree-diagram-drawing"
## 引数文字列受け
if [ $# = 0 ]; then
echo "WARNING: Ledgerのオプションが使えます"
echo " 引数なしだと樹状図が長大になります"
read -n 1 -r -p "引数で絞りこみますか? [y/n] : " yn
case "${yn}" in
Y|y) echo -e
read -r -p "ledger --acounts オプション : " param ;;
*) : ;;
esac
else
param=$*
fi
## 入力された引数に"--depth n"がある場合
# それを削除して、nをtree表示時の tree -L に食わせる
if [[ -n $(echo "${param}" | grep '\--depth') ]]; then
depth_level=$(echo ${param}\
| sed -e "s/.*--depth \([0-9]*\).*/\1/")
str_to_delete="--depth ${depth_level}"
param=$(echo "${param}" | sed -e "s/${str_to_delete}//g" )
else
depth_level="0"
fi
## accounts.dat を作る
ledger accounts ${param} --count\
> ${base_dir}/accounts.dat
awk -i inplace -F" " '{print $2}' ${base_dir}/accounts.dat
## ここから本体
# リセット ACCOUNT
cd ${base_dir} || exit 0
rm -rf ACCOUNT/
mkdir -p ACCOUNT
cd ACCOUNT || exit 0
# ディレクトリ、サブディレクトリを作る
while read -r line ; do
dir_path=$(echo $line | sed -e 's/:/\//g')
mkdir -p "${dir_path[@]}"
done < ${base_dir}/accounts.dat
## Tree 出力
cd ${base_dir} || exit 0
if [[ "${depth_level}" = 0 ]]; then
tree -d ACCOUNT
else
tree -d ACCOUNT -L ${depth_level}
fi
exit 0
サンプル出力
1. 引数なしで起動したとき
$ tree-it.sh
ここで n を選んで 絞り込み無し にすると、全期間にわたって全アカウントが全深度について表示されます。情報量が多すぎてとても使い物になりません。
したがって基本的には、次の例のように起動時に引数で 絞りこみ をする使い方になります。
2. 引数つきで起動した例1
期間を2022/12/01からに指定し、アカウント深度2で「支出 or 資産 or 負債」で絞り込んだ例:
$ tree-it.sh ^assets or ^liab -b 2022/12/01 --depth 2
3. 引数つきで起動した例2
期間を2022/06/01からに指定し、支出の中で外食(Meals) と 食料品(Grocery)をアカウント深度5で絞り込んだ例:
$ tree-it.sh ^Expenses and \( meals or grocery \) --depth 5 -b 2022/06/01
今後の展望など
tree-it.sh では、Ledgerの accounts
コマンドで --count
オプションをつけています。これを使うと、クエリされたアカウントの出現頻度が得られますので、出現頻度で絞りこんでアカウントの樹状図を書くことができます。
このスクリプトでは、 --depth
を除いてほとんどの機能はledger-cliに おんぶに抱っこ 状態です。使えば使うほど、ledger-cliの適用範囲の広さと奥深さを感じます。
(補)アカウント深度だけtreeを使うわけ
ledger accounts の引数における –depth の挙動
ledger accounts
に引数をつけて起動するときに、引数に --depth
をつけ加えると、ちょっと考えていたのとちがう結果になります。
たとえば ledger accounts
で Assets を2023年1月1日以降についてクエリすると次のようになります:
$ ledger accounts ^assets -b 2023/01/10
Assets:Bank:boy:chk
Assets:Bank:yucho:sogo:hinako
Assets:Cash
Assets:Cash:hinako
Assets:Cash:小銭
Assets:Reimbursement
Assets:e-money:REG_coupon
Assets:e-money:nanaco:card_em:hinako
Assets:e-money:nanaco:card_pts:hinako
これはOKですよね。1月10日から当日までに使った Assests アカウントがリストアップされています。ところがこれに --depth 2
を足したクエリ:
$ led accounts ^assets -b 2023/01/10 --depth 2
これをやると結果は次の2行だけになります。
Assets:Cash
Assets:Reimbursement
あらら!ですよね。 これはまずい 😅
つまり、1月10日以降 今日までに使用した Assets (資産)アカウントの内、アカウントの深さ(depth)が ちょうど2のアカウントだけ リストされたということ。深さが3以上のアカウントはリストされません2。
期待していたのは、次のような結果です。
Assets:Bank
Assets:Cash
Assets:Reimbursement
Assets:e-money
対応策
そこで
--depth
オプションが指定されたときには、そのまま使うのではなく、自分の期待に合った動きをしてくれるようにスクリプトに手をいれました。具体的には:
--depth n
が引数に含まれていたら、それを削除するn
は変数($depth_ledvel)に保存しておいて、tree コマンドの引数として-L ${depth_level}
のようにして使う3
これで外見上は --depth
でアカウント階層の深さが指定されたとおりに見えます。