【実践!CSVデータ検索スクリプト作成編】CSV形式で与えてある検索条件ファイルから検索結果を出力するスクリプト


2021/04/11

CSVデータの検索に特化したエクセルでいうところのVLOOKUP関数のような機能をもつスクリプトツールを作成してみる特集の第2回目です。

EXCEL業務に携わっている人なら大抵一度は、データシートから入力した条件に一致したデータの検索や抽出を行う作業を経験していると思います。

今回は
前回のスクリプトツールを少し修正して、検索するキーワードリストを引数で与えるのではなく、入力ファイルで予め書き込んだデータから検索&抽出するスクリプトツールをAwkベースで作ってみようと思います。


はじめに

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

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

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


スクリプトツールの概要

前回のツールスクリプトでは、以下のように引数-lから検索したいキーワードのリストを直接与えて、データベースから該当の行全てを抽出していました。

            
            $ ./simple_finder.sh -l 山田,佐藤,モフ雄 employee.csv
山田の項目...
佐藤の項目...
モフ雄の項目...
        
機能的にはこれでも良いのですが、何度も繰り返し利用するとなると、オプションに毎回文字列を直書きするのも面倒に感じてくると思います。

そこで今回は予め用意していた検索用csvテキストを例えば、

            
            山田
佐藤
モフ雄
        
のように行で仕込んで置いて、この検索用csvをコマンドで入力し、

            
            $ ./simple_finder.sh -i search_list.csv employee.csv
山田の項目...
佐藤の項目...
モフ雄の項目...
        
というように検索できるように前回のツールスクリプトを拡張してみたいと思います。


ツールスクリプトの拡張

まずテストとして検索用csv(search_list.csv)とデータベースの中身(employee.csv)を以下のようなコマンドで生成しておきます。

            
            $ cat <<EOF > search_list.csv
山田
佐藤
モフ雄
EOF

$ cat << EOF > employee.csv
山下モゲ雄,営業部,本社,3年
島田フガ子,経理部,名古屋支部,15年
岡田ピポ太,製造部,山口工場,8年
佐藤ゴバ文,製造部,山口工場,11年
沢口モフ代,人事部,本社,4年
銭形ガメ吉,海外部,メキシコ支部,11年
上岡ムメ美,営業部,本社,23年
京谷マハ次,製造部,山口工場,3年
園田フマ由,人事部,本社,17年
山田ケム紀,営業部,本社,15年
田川ポゥ子,製造部,ベトナム工場,12年
満田クタ郎,営業部,本社,2年
島寺ルン大,営業部,本社,18年
香下ウル蔵,製造部,山口工場,5年
田頭モフ雄,営業部,名古屋支部,16年
蒲田ウオ奈,海外部,メキシコ支部,9年
郷田ポポ生,営業部,名古屋支部,4年
梅岡ボル伍,経理部,本社,25年
亀川ヲル士,製造部,山口工場,14年
EOF
        
ではいきなりですが、前回作成しておいたツールスクリプト(simple_finder.sh)の完成バージョンを以下のように拡張してみましょう。

            
            #!/bin/bash

usage_exit() {
    echo "USAGE: $(basename $0) [-l key_list] [-h help] [input_file]" 1>&2
    exit 1
}

noarg_err() {
    echo "ERROR: must provide key_list!" 1>&2
    exit 1
}

selecteither_err() {
    echo "ERROR: should select an option from -l/-i!" 1>&2
    exit 1
}

noinputfile_err() {
    echo "ERROR: not allowed input file to be empty!" 1>&2
    exit 1
}

while getopts l:i: OPT; do
    case $OPT in
        l ) KEY_LIST="$OPTARG"
            ;;
        i ) KEY_LIST_FILE="$OPTARG"
            ;;
        \? ) usage_exit
            ;;
    esac
done

shift $((OPTIND - 1))

if [ -z "$KEY_LIST" ] && [ -z "$KEY_LIST_FILE" ]; then
    noarg_err
elif [ -n "$KEY_LIST" ] && [ -n "$KEY_LIST_FILE" ]; then
    selecteither_err
elif [ -z "$1" ]; then
    noinputfile_err
fi

echo "FILE: $1, KEY_LIST: ${KEY_LIST}, KEY_LIST(FILE): ${KEY_LIST_FILE}"

if [ -n "$KEY_LIST" ]; then
    #👇①...☆前回のスクリプト
    PARR=($(echo "${KEY_LIST}" | tr ',' ' '))
    for p in "${PARR[@]}"; do
        awk -F"," '
            $1 ~ /'"$p"'/ { last_macthed = $0; }
            END { print last_macthed ? last_macthed : "'"$p"'?,#N/A,#N/A,#N/A"; }
        ' $1
    done
elif [ -n "$KEY_LIST_FILE" ] && [ -f "$KEY_LIST_FILE" ]; then
    #👇②...☆今回拡張するスクリプト
    cat "$KEY_LIST_FILE" | while read KEY || [ -n "${KEY}" ]; do
        awk -F"," '
            $1 ~ /'"$KEY"'/ { last_macthed = $0; }
            END { print last_macthed ? last_macthed : "'"$KEY"'?,#N/A,#N/A,#N/A"; }
        ' $1
    done
fi
        
前回は上のスクリプトの①の部分を詳しく解説していましたが、今回は②の部分が入力ファイルからキーを抽出してループ処理させている部分になります。

search_list.csvでは改行で検索ワードを並べているので、シンプルに
while readでリストファイル読み込みのテクニックを利用しました。


動作の確認

これを実行してみると、

            
            $ chmod +x simple_finder.sh
$ ./simple_finder.sh -i ./search_list.csv employee.csv
FILE: employee.csv, KEY_LIST: , KEY_LIST(FILE): ./search_list.csv
山田ケム紀,営業部,本社,15年
佐藤ゴバ文,製造部,山口工場,11年
田頭モフ雄,営業部,名古屋支部,16年
        
で前回同様に検索と抽出を正しくおこなっていることが分かります。

また入力ファイルを編集してわざと検索用データを間違えてみると、

            
            $ chmod +x simple_finder.sh
$ ./simple_finder.sh -i ./search_list.csv employee.csv
FILE: employee.csv, KEY_LIST: , KEY_LIST(FILE): ./search_list.csv
山岡?,#N/A,#N/A,#N/A
谷藤?,#N/A,#N/A,#N/A
田頭モフ雄,営業部,名古屋支部,16年
        
のように探すことの出来なかったときのレスポンスもちゃんと返ってきています。


まとめ

今回は前回に引き続いて検索用のスクリプトを検索ワードリストをファイル入力できるように機能拡張してみました。

場合によっては検索キーの直接入力よりも、利便性が高いツールスクリプトに仕上がっていると思います。
記事を書いた人

記事の担当:taconocat

ナンデモ系エンジニア

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