【シェル芸】bashのワンライナーでクロス集計(※sedもawkも使わないプレイ)
きっかけ
内容
仕様(やりたいこと)
こんなファイル
[sample.txt]
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
User Item Money | |
A Ice 130 | |
A Ice 180 | |
B Juice 120 | |
B Ice 130 | |
I OREO 210 | |
I OREO 210 | |
I OREO 210 |
を、集計して、こんな感じ
Ice | Juice | OREO | |
---|---|---|---|
A | 310 | 0 | 0 |
B | 130 | 120 | 0 |
I | 0 | 0 | 630 |
|
|
に変換します。※ここでは、CSV形式で出力
処理をシェルスクリプトで書くと
[cross_tabulation.sh]
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/bin/bash | |
# 入力ファイルをTSVからCSV形式に変換する。ついでにヘッダの除去も行う | |
cat "$1" | tr -s ' ' | tr '\n' ',' | cut -d, -f2- | tr , '\n' | tr ' ' , | grep -v "^$" > tmp.input | |
# 1列目の項目を抜出し、キー1とする | |
cat tmp.input | cut -d, -f1 | sort -u > tmp.key1 | |
# 2列目の項目を抽出し、キー2とする | |
cat tmp.input | cut -d, -f2 | sort -u > tmp.key2 | |
# キー1とキー2をCORSS JOINし、インデックスとする | |
cat tmp.key1 | xargs -I% bash -c 'cat tmp.key2 | xargs -I@ echo %,@' > tmp.index | |
# インデックスから、集計用の初期値レコード(Money = 0)の行を生成する | |
cat tmp.index | xargs -I% echo %,0 > tmp.init | |
# 入力ファイルと初期値レコードを縦に連結 | |
sort tmp.init tmp.input > tmp.trans | |
# 縦集計しサマリを作成 | |
cat tmp.index | xargs -I% bash -c 'echo %,`grep % tmp.trans | cut -d, -f3 | xargs | tr " " + | bc`' > tmp.sumy | |
# キー1とキー2とサマリからクロス表を出力 | |
echo " `cat tmp.key2 | xargs`" | tr ' ' , | |
cat tmp.key1 | xargs -I% bash -c 'echo % `grep "^%," tmp.sumy | cut -d, -f3 | xargs `' | tr ' ' , |
これをワンショットにすると
[cross_tabulation_1liner.sh]
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
tmp=tmp.$$_ \ | |
&& cat sample.txt | tr -s ' ' | tr '\n' ',' | cut -d, -f2- | tr , '\n' | tr ' ' , | grep -v "^$" > ${tmp}1 \ | |
&& key1="`cat ${tmp}1 | cut -d, -f1 | sort -u`" \ | |
&& key2="`cat ${tmp}1 | cut -d, -f2 | sort -u`" \ | |
&& index=`echo "$key1" | xargs -I% bash -c "echo \"$key2\" | xargs -I@ echo %,@"` \ | |
&& (cat ${tmp}1 && echo "$index" | xargs -I% echo %,0) > ${tmp}2 \ | |
&& (echo "$index" | xargs -I% bash -c "echo %,\`grep % ${tmp}2 | cut -d, -f3 | xargs | tr ' ' + | bc\`") > ${tmp}3 \ | |
&& (echo " `echo $key2 | xargs`" && echo "$key1" | xargs -I% bash -c "echo % \`grep '^%,' ${tmp}3 | cut -d, -f3 | xargs \`") | tr ' ' , \ | |
&& rm ${tmp}1 ${tmp}2 ${tmp}3 |
出力結果
|
|
使用したコマンド
- cat
- tr
- cut
- sort
- xargs
- bash
- grep
- bc
- echo
おつかれさまでした(´▽、`*)