BASHとPowerShellのフィルタ処理まとめ⑤

BASHとPowerShellのフィルタ処理例をまとめていきます。下記記事たちの続きですので、フィルタそのものの説明、目的、検証環境などの前置きは記事①をご参照ください。

[■BASHとPowerShellのフィルタ処理まとめ①](https://qiita.com/HOBO0222/items/377ae7f4f229f49c5475)
[■BASHとPowerShellのフィルタ処理まとめ②](https://qiita.com/HOBO0222/items/08a669f494ace4c6c7b8)
[■BASHとPowerShellのフィルタ処理まとめ③](https://qiita.com/HOBO0222/items/abaf25087de429e76c04)
[■BASHとPowerShellのフィルタ処理まとめ④](https://qiita.com/HOBO0222/items/456292b2adc7c62f3c80)

①と②は主に文字列のフィルタ処理についてまとめ、
③は主に行に関するフィルタ処理をまとめました。
④では主に列に関するフィルタ処理をまとめました。

本記事⑤では計算や集計について記載していきます。

テスト用のファイルは以下を使用します。

```personal_infomation06.csv
氏名,氏名（カタカナ）,性別,年齢,出身地,血液型,乱数,パスワード
須藤萌花,スドウモエカ,女,66,沖縄県,B,799,903
今田陽向,イマダヒナタ,女,38,徳島県,A,2,584
古川美雪,フルカワミユキ,女,14,神奈川県,O,686,483
海老原瑠美,エビハラルミ,女,14,大分県,A,812,501
沢田義美,サワダヨシミ,女,87,静岡県,B,453,614
金子里歌,カネコリカ,女,77,岡山県,A,311,609
梶田秀之,カジタヒデユキ,男,20,大阪府,A,560,793
諸星英晴,モロボシヒデハル,男,19,新潟県,O,203,133
野上柚,ノガミユズ,女,60,愛知県,O,66,792
佐竹晴久,サタケハルヒサ,男,74,岩手県,A,424,142
```

ではぽんぽんと紹介していきます。

##【四則演算】
###◆BASHの場合
整数計算はexprを使用します。掛け算(```*```)の時だけ```\```でエスケープしなければ構文エラーになるので気をつけてください。

```BASH:四則演算
[root@centos74 log]# expr 1 + 2
3
[root@centos74 log]# expr 2 - 1
1
[root@centos74 log]# expr 3 \* 3
9
[root@centos74 log]# expr 3 / 3
1
[root@centos74 log]# expr 5 % 3
2
```

###◆PowerShellの場合
式を入力するだけで結果が返ってきます。ただしPowerShellは型変換があるので暗黙の型変換には気をつけてください。

```PowerShell:四則演算
PS C:\Tools\logs> 1 + 2
3
PS C:\Tools\logs> 2 - 1
1
PS C:\Tools\logs> 3 * 3
9
PS C:\Tools\logs> 3 / 3
1
PS C:\Tools\logs> 5 % 3
2
```

##【結果を小数点にする】
割り算の結果を小数点にする場合の方法です。

###◆BASHの場合
echoとbcを使用して行います。桁数を制限したい時は```scale=桁数```で指定してから計算します。

```BASH:結果を小数点にする
[root@centos74 log]# echo "5/2" | bc
2
[root@centos74 log]# echo "5/2" | bc -l
2.50000000000000000000
[root@centos74 log]# echo "scale=2; 5/2" | bc
2.50
```

###◆PowerShellの場合
式を並べれば小数点の計算も通常通りしてくれます。桁数を指定したい場合はフォーマット演算子を使用します。

```PowerShell:結果を小数点にする。
PS C:\Tools\logs> 5 / 2
2.5
PS C:\Tools\logs> "{0:N4}" -f (5 / 2)
2.5000
```

##【パーセント値で表示】

###◆BASHの場合
BASHは各コマンドをうまく組み合わせてパーセント値計算するしかありません。

```BASH:パーセント値で表示
[root@centos74 log]# num=`echo "scale=2; 2/5" | bc`
[root@centos74 log]# num=`echo "$num * 100" | bc`
[root@centos74 log]# echo "$num%"
40.00%
```

###◆PowerShellの場合
フォーマット演算子で用意されているのでそれを使用します。この時に```"{0:Pn}"```のnの値で小数点の桁数表示も指定できます。

```PowerShell:パーセント値で表示
PS C:\Tools\logs> "{0:P2}" -f (2 / 5)
40.00%
```
##【10進数⇔16進数への変換】

###◆BASHの場合
echo+bcの組み合わせで行います。

```BASH:10進数から16進数への変換
[root@centos74 log]# echo "obase=16; 4517" | bc
11A5
```

```BASH:16進数から10進数への変換
[root@centos74 log]# echo "ibase=16; 11A5" | bc
4517
```

###◆PowerShellの場合
フォーマット演算子やToInt32を使用します。

```PowerShell:10進数から16進数への変換
PS C:\Tools\logs> "{0:X}" -f 4517
11A5
```

```PowerShell:16進数から10進数への変換
PS C:\Tools\logs> [System.Convert]::ToInt32("11A5",16)
4517
```




##【列の合計値算出】

###◆BASHの場合

BASHで簡単に計算や集計を行う場合はawkを使います。

```BASH:合計値算出
[root@centos74 log]# cat personal_infomation06.csv | awk -F "," '{sum+=$7} END{print sum;}'
4316
```
$7というのは7列目のことでここでは乱数列を指しています。-Fで各データの区切り文字(```,```)を指定しています。一つ目の```{}```内はいわゆるfor文のように内枠の処理を各データに対して繰り返すようになっています。```sum+=$7```で７列目の各データを足していく処理を行っています。そして二つ目の```END{print sum}```で合計が完了したsumを表示(print)させています。

###◆PowerShellの場合
PowerShellはMeasure-Objectコマンドレットで行います。

```PowerShell:合計値を算出
PS C:\Tools\logs> $DATA = Import-Csv .\personal_infomation06.csv
PS C:\Tools\logs> ($DATA.乱数 | Measure-Object -Sum).Sum
4316
```
いつものパターンですが対象ファイルの各データをオブジェクトに格納しています。その後、[Measure-Object](https://technet.microsoft.com/ja-jp/library/ee176900.aspx)を使用して算出しています。PowerShellはカウント、平均、合計、最小値、最大値の求め方はこの構文ひとつ覚えておけば算出できるようになります。

##【列の平均値の算出】
###◆BASHの場合

```BASH:平均値の算出
[root@centos74 log]# cat personal_infomation06.csv | sed -e'/氏名/d' | awk -F "," '{sum+=$7} END{print sum/NR}'
431.6
```
awkは[組み込み変数](http://www.kt.rim.or.jp/~kbk/gawk-30/gawk_11.html)があり、それぞれ特定の意味を持った値を格納しており、これを利用することにより柔軟に様々な処理を行えるようになっています。NRは「プログラムが実行開始してからそれまでに入力されたレコードの数」が格納されています。

注意する点としてヘッダー部分(計算対象外のデータ)もNRは数えてしまうので、sedなどであらかじめ削除した後にawkへパイプで渡してください。

```BASH:NRの値
[root@centos74 log]# cat personal_infomation06.csv | awk -F "," '{$7} END{print NR}'
11 #先頭の「乱数」もデータとしてカウントしてしまっているので意図した値より1多い。
```
###◆PowerShellの場合
Measure-Objectの-Averageを使います。構文は合計値算出時と変わりません。

```PowerShell:平均値の算出
PS C:\Tools\logs> $DATA = import-Csv .\personal_infomation06.csv
PS C:\Tools\logs> ($DATA.乱数 | Measure-Object -Average).Average
431.6
```

##【列の最大値の算出】
考え方は同じです。

###◆BASHの場合
```BASH:最大値の算出
[root@centos74 log]# cat personal_infomation06.csv | sed -e'/氏名/d' | awk -F "," '{if(max<$7) max=$7} END{print max}'
812
```
sedしなくてもいいんですが、正確にやる意味も込めて一応しておきます。

###◆PowerShellの場合
-Maximumを使用します。

```PowerShell:最大値の算出
PS C:\Tools\logs> $DATA = import-Csv .\personal_infomation06.csv
PS C:\Tools\logs> ($DATA.乱数 | Measure-Object -Maximum).Maximum
812
```

##【列の最小値の算出】

###◆BASHの場合
```BASH:最小値の算出
[root@centos74 log]# cat personal_infomation06.csv | sed -e'/氏名/d' | awk -F "," 'BEGIN{min=9999999}{if(min>$7) min=$7} END{print min}'
2
```
BASHでの最小値設定は最初にmin(変数)に初期値を当ててあげないと```if(min>$7)```の分岐処理時に空白値のminの方が大きいと判断してしまうためNGです。必ず対象列の中のどの数値よりも大きい数値を初期値として設定してください。

###◆PowerShellの場合
-Minimumを使用します。

```PowerShell:最小値の算出
PS C:\Tools\logs> $DATA = import-Csv .\personal_infomation06.csv
PS C:\Tools\logs> ($DATA.乱数 | Measure-Object -Minimum).Minimum
2
```

##【列のデータ数をカウント】
###◆BASHの場合
```BASH:列データのカウント
[root@centos74 log]# cat personal_infomation06.csv | awk -F "," '{$7} END{print NR}'
11
```
###◆PowerShelの場合
-Countを使用します。

```PowerShell:列データのカウント
PS C:\Tools\logs> $DATA = import-Csv .\personal_infomation06.csv
PS C:\Tools\logs> ($DATA.乱数 | Measure-Object).Count
10
```
PowerShell側のImport-Csvは先頭行をヘッダーとして読み込んでしまうのでBASHより1少ないです。もしヘッダーも数えたいとのことであればConverFrom-Stringで変数格納してやってみてください。

```PowerShell:列データのカウント
PS C:\Tools\logs> $DATA = get-Content -Encoding UTF8 .\personal_infomation06.csv | ConvertFrom-String -Delimiter ","
PS C:\Tools\logs> ($DATA.P7 | Measure-Object).Count
11
```
##【テキストファイルの行数・文字数・単語数カウント】
###◆BASHの場合
BASHはwcを利用してカウントします。

```BASH:行数のカウント
[root@centos74 log]# cat personal_infomation06.csv | wc -l
11
```

```BASH:文字数のカウント
[root@centos74 log]# cat personal_infomation06.csv | wc -m
346
```

```BASH:単語数のカウント
[root@centos74 log]# cat personal_infomation06.csv | wc -w
11
```
単語は，スペース，タブおよび改行で区切られた文字列の数と区別するためこうなっちゃいます。

###◆PowerShellの場合
Measure-Objectを使用します。

```PowerShell:行数のカウント
PS C:\Tools\logs> (Get-Content -Encoding UTF8 .\personal_infomation06.csv | Measure-Object -Line).Lines
11
```
またLengthメソッドでも行数カウントは可能です。

```PowerShell:行数のカウント
PS C:\Tools\logs> (Get-Content -Encoding UTF8 .\personal_infomation06.csv).Length
11
```

```PowerShell:文字数のカウント
PS C:\Tools\logs> (Get-Content -Encoding UTF8 .\personal_infomation06.csv | Measure-Object -Character).Characters
335
```

```PowerShell:単語数のカウント
PS C:\Tools\logs> (Get-Content -Encoding UTF8 .\personal_infomation06.csv | Measure-Object -Word).Words
11
```

ここで気づいたのですが、BASHとPowerShellの文字数カウントの結果数が異なります。調べてみた結果、１行につき１文字ずつBASHの方が多い(PowerShellが少ない)ようです。行数ごとという観点からおそらく改行コードの分で差が出ているのかなと考えますが、知ってらっしゃる方いたらぜひ教えてください...!!!!

##【⑥に続きます】
⑤が長くなったので一旦⑥に続きます。
⑥は集計について紹介していきます。

ここまで閲覧頂きありがとうございました。
なにか追加情報や指摘事項、「もっといい方法あるよ！」などありましたらコメントへお願いします。