join コマンドでLEFT OUTER JOIN のNULL 付き的なことをやる
会議の出席の記録や、商品の売上のようなデータを横展開して表にしたい時がある。
このようなとき、join コマンドをぱぱっと実行すれば、データのOUTER JOIN的な事ができる。
出席と欠席を join コマンドで
join 2021-08-11.txt 2021-07-11.txt A100 出席 出席 A101 出席 出席 A102 出席 欠席 A103 出席 欠席 A104 出席 欠席 A105 出席 欠席
しかし、整理されてない場合や、存在しないデータ(NULL・EMPTY)はいちいち書かない。
次のように、出席だけを書く場合が多いと思う。
出席だけを書いている
cat 2021-07-11-出席者のみ.txt A100 出席 A101 出席
会議の出席者をメモったテキストがあるとする。
これをJOINするときに、NULLに相当する空文字を埋めてあげれば、データとして処理することができる。
出席や提出は出した人だけをメモっていることが多いですよね。まさか未提出を未提出、未払いを未払いとわざわざメモる人は少ないでしょう。
また、フォルダやファイルを探して見つかったものを集計することがおおく、未出現のIDはデータとして出てきません。
先に、欠席を補完する
そこで、未出現をEMPTYやNULLなど、データ欠損を埋めてデータ処理に適した形式にする。
join -a 1 -o auto -e '欠席' id.txt 2021-07-11-出席者のみ.txt A100 出席 A101 出席 A102 欠席 A103 欠席 A104 欠席 A105 欠席
または、わかりやすいように NULL の文字で埋めてあげる。
join -a 1 -o auto -e 'NULL' id.txt 2021-07-11-出席者のみ.txt A100 出席 A101 出席 A102 NULL A103 NULL A104 NULL A105 NULL
この処理を冒頭処理と同等に一回で行う
join -a 1 2021-08-11.txt <(join -a 1 -o auto -e '欠席' id.txt 2021-07-11-出席者のみ.txt)
join コマンドは、 join <( サブコマンド)
のカタチで複数回のネストをするこができる。
複数の処理
しかし実際には、サブコマンドでは不便で。
JOINを join *.txt
のような、引数を複数ファイルで行うことが出来ない。
事前処理をして、さらに関数を作ってあげれば、join *.txt
のような処理で複数ファイルを使うことで実現する。
function multijoin() { out=$1 shift 1 cat $1 | awk '{print $1}' > $out for f in $*; do join $out $f > tmp; mv tmp $out; done } multijoin 出席者一覧 *.txt cat 出席者一覧
NULLを入れてあげるちょっとした事前処理
このような、ちょっとした事前処理をしてあげるのがBashなどシェルコマンドを使うコツだと思うんですが。
失われた世界の知識になりつつありますよね。
この知識を使えば、繰り返しが出てくるデータを上手く集計することができそうな気がす。
たとえば、
- 授業の提出物ファイル(フォルダ)から、生徒が毎回提出しているか。
- チャットルームのログから、毎週の出席者を取り出したい
- 商品の売上データから日々の売上の有無の計算
- 会議室の、使用履歴とかを展開したり
フォルダごとやファイルごとに同じデータを繰り返し記録していたり、出現を数えてたりそのような古の知識はUNIX哲学だったのだろうが、たぶんもう忘れられた世界。