【実践!CSVデータ集計スクリプト作成編】集計を対話的にするスクリプト作成の基礎


2021/04/15

Excelでの定番の業務テクニックとして要素検索と並んで良く利用されているのが集計操作です。

この回ではCSVデータから集計結果を出力するツールスクリプトを何回かに分けて作り込んでいきます。

実際の集計を行う前に、まずは集計モードを対話に選択できるようなツールスクリプトに仕立てる前段階の、ユーザーインタラクティブなシェルコマンドの実装方法の基礎を固めていきます。


はじめに

当サイトではオフィス業務のComputer-Aidedなハイブリッドな方法を模索し、より効率的なExcel業務を実現したい多忙なオフィスワーカー向けの主にAwkとSedを使うシェル講座です。

シェルスクリプトはどこでもどんなOSでも基本的に使えて、しかも一度使い方を覚えると、Excelと組み合わせて最高に効率の良いオフィスワークツールが作れることでしょう。

合同会社タコスキングダム|蛸壺の技術ブログ


集計操作をより対話的に操作するために

集計したい列を指定する際に、何列目だったかを思い出しながらいちいち列を番号指定するのは、データシートが横に長くなってくるほどめんどうになってくるのは避けられません。

また番号ではなく、項目名で指定したら、売上高の項目名を曖昧にしていると「売上」だったっけな?「営業実績」だったかな?と引き出すインデックス名も思い出せない...

できれば選択肢でユーザーが選べるようにツールを改良したい、というのはよくあるお話かと思います。

具体例を出していきましょう。

例えばとある飲食店の今年の会計帳簿的なデータと見立てて、以下のコマンドでCSVデータを作成しておきます。

            
            cat <<EOF > accounting.csv
2021年01月01日,51,98875
2021年01月02日,91,150457
2021年01月03日,77,134982
2021年01月04日,53,107022
2021年01月05日,48,95401
2021年01月06日,66,124309
2021年01月07日,81,143109
2021年01月08日,57,111326
2021年01月09日,93,179488
2021年01月10日,104,220456
2021年01月11日,87,182094
2021年01月12日,60,115022
2021年01月13日,71,130943
2021年01月14日,63,124072
2021年01月15日,50,110650
2021年01月16日,77,135557
2021年01月17日,81,140073
2021年01月18日,57,113078
2021年01月19日,62,146033
2021年01月20日,82,175592
2021年01月21日,99,174301
2021年01月22日,72,131045
2021年01月23日,60,120744
2021年01月24日,93,169973
2021年01月25日,100,194532
2021年01月26日,93,165395
2021年01月27日,70,128044
2021年01月28日,55,117064
2021年01月29日,86,149561
2021年01月30日,79,137043
2021年01月31日,65,148774
EOF
        
列のラベルヘッダは省略していますが、左から日時, 来店客数, 当日売上高を表しているとします。

なお、日付データを含む列データのあるエクセルファイルからのデータの抽出には取り扱う際の注意点を別の記事で特集していますので以下のリンクで確認してください。


対話型の入力の基本 ~ Readコマンド

対話型のシェルスクリプトを作成するためには、Readコマンドを使うととても簡単にシンプルな実装できます。

シェルスクリプトの途中で
readコマンドが実行されたときに、プロセスはそこで一時的に待機し、ユーザーからの入力用を待ち構えます。

そしてreadが入力された引数を受け取った後に、readの引数で指定されている変数にその受け取った値が代入される仕組みになっています。

以下のような簡単なシェルスクリプトで対話型の処理を説明しましょう。

            
            #!/bin/bash

function DoAScript() {
    echo "スクリプトA: $1が選択されました。"
}

function DoBScript() {
    echo "スクリプトB: $1が選択されました。"
}

function Addup() {
    printf "集計したい項目を 1 か 2 で選択してください\n"
    printf "\t1) 月間総来客数 \t2) 月間総売上\n"
    printf "※ 終了は q か c を入力!\n>>>"
    read OPT

    if [ $OPT == '1' ] ; then
        DoAScript "$OPT"
    elif [ $OPT == '2' ] ; then
        DoBScript "$OPT"
    elif [ $OPT == 'q' ] || [ $OPT == 'c' ] ; then
        echo "終了"
        exit 1
    else
        printf "ヒント...1 か 2 で入力!\n\n"
        Addup
    fi
}

Addup
        
ここでいうと、メイン処理にあたるAddup関数の中にあるreadコマンドによって、ユーザーからの入力があるまで待機し、入力を受け取った後で、その値がその後ろに指定されているOPTに渡されています。

これをinteractive_add_up.shで保存して以下のように実行すると、

            
            $ chmod +x interactive_add_up.sh
$ ./interactive_add_up.sh
集計したい項目を 1 か 2 で選択してください
        1) 月間総来客数         2) 月間総売上
※ 終了は q か c を入力!
>>>3
ヒント...1 か 2 で入力!

集計したい項目を 1 か 2 で選択してください
        1) 月間総来客数         2) 月間総売上
※ 終了は q か c を入力!
>>>2
スクリプトB: 2が選択されました。
        
のように入力値によって処理を切り替えることができます。


集計したい項目を切り替える

折角なので、先程のスクリプトの雛形を使って、集計を切り替えができるように修正してみます。

            
            #!/bin/bash

function TotalCustomer() {
    cat $1 | awk -F"," 'BEGIN{total=0}{total+=$2}END{print total}'
}

function TotalSales() {
    cat $1 | awk -F"," 'BEGIN{total=0}{total+=$3}END{print total}'
}

function Addup() {
    printf "集計したい項目を 1 か 2 で選択してください\n"
    printf "\t1) 月間総来客数 \t2) 月間総売上\n"
    printf "※ 終了は q か c を入力!\n>>>"
    read OPT

    if [ $OPT == '1' ] ; then
        TotalCustomer "$1"
    elif [ $OPT == '2' ] ; then
        TotalSales "$1"
    elif [ $OPT == 'q' ] || [ $OPT == 'c' ] ; then
        echo "終了"
        exit 1
    else
        printf "ヒント...1 か 2 で入力!\n\n"
        Addup $1
    fi
}

Addup $1
        
なお詳しい集計のスクリプトの作成方法の詳細は別の記事でじっくり特集する予定です。

実行してみますと、

            
            $./interactive_add_up.sh accounting.csv
集計したい項目を 1 か 2 で選択してください
        1) 月間総来客数         2) 月間総売上
※ 終了は q か c を入力!
>>>1
2283

$./interactive_add_up.sh accounting.csv
集計したい項目を 1 か 2 で選択してください
        1) 月間総来客数         2) 月間総売上
※ 終了は q か c を入力!
>>>2
4375015
        
以上、readコマンドを利用して割と簡単にインタラクティブな操作が可能なツールスクリプトに仕上げることができました。


参考サイト

【超カンタン解説】対話型シェルの作り方(条件分岐、繰り返しも)

記事を書いた人

記事の担当:taconocat

ナンデモ系エンジニア

主にAngularでフロントエンド開発することが多いです。 開発環境はLinuxメインで進めているので、シェルコマンドも多用しております。 コツコツとプログラミングするのが好きな人間です。