大量のデータが詰め込まれたファイルがUnixサーバー上にあって、そのデータファイルを修正したり集計したいといった場合、わざわざプログラム作るのも面倒だし、ダウンロードしてExcelで加工するか、なんてことないでしょうか。
Linux上でも幾つかのコマンドを覚えておけば、結構簡単にデータの集計作業というものができます。
特定の情報を持つデータのみを抜き出すgrepコマンド
こちらはかなりメジャーなコマンドなので普段から使っている人も多いのではないでしょうか。
例えばこんなCSVファイルがあったとして
- hoge.csv
100,apple,50
103,orange,75
102,banana,30
100,apple,20
103,orange,75
この中から「apple」の行だけを取り出したいといったときに使います。
$ grep apple hoge.csv
100,apple,50
100,apple,20
逆に「apple」を含まない行を取り出したい場合は「-v」オプションを
$ grep -v apple hoge.csv
101,orange,75
102,banana,30
103,orange,75
個数を調べたいときは「-c」オプションを
$ grep -c apple hoge.csv
2
「apple」の文字を含むファイルを探したい場合は「-l」オプションを
$ grep -l apple ./*
./foo.csv
./hoge.csv
予断ですが、圧縮ファイルに対してそのままgrepをかけられるzgrepというコマンドもあります。
$ zgrep apple hoge.csv.gz
100,apple,50
100,apple,20
その他にも多彩なオプションがありますし、検索する文字は正規表現が使えますので、かなり柔軟にデータを取り出すことができます。
取り出したデータを他のファイルへリダイレクトしておけば、次の加工もしやすいですしね。
データを順番に並び替えるsortコマンド
特定の行に対してデータをソートしたいという場合に役立つのがsortコマンドです。
先ほどのCSVファイルを、1番目の要素である3桁の数値でソートしてみます。
$ sort -t "," -k1,1 hoge.csv
100,apple,20
100,apple,50
102,banana,30
103,orange,75
103,orange,75
「-t」オプションで指定しているのは列の区切り(カンマ)、「-k」オプションはどの列からどの列までをソートキーとするかを指定しています。(1から1なので1番目だけをソートキーに指定)
例えば、3番目の要素である2桁の数値でソートしたければ
$ sort -t "," -k3,3 hoge.csv
100,apple,20
102,banana,30
100,apple,50
103,orange,75
103,orange,75
と言うように指定します。
また、逆順にしたければ「-r」オプションを指定します。
$ sort -t "," -k1,1 -r hoge.csv
103,orange,75
103,orange,75
102,banana,30
100,apple,50
100,apple,20
特定の列のみを取り出すcutコマンド
grepコマンドで特定の行を取り出すように、指定の列を取り出すのに便利なのがcutコマンドです。
先ほどのCSVファイルの中から果物の名前が書かれた列だけを取り出す場合は
$ cut -d "," -f 2 hoge.csv
apple
orange
banana
apple
orange
のように指定します。
「-d」オプションで列の区切り(カンマ)、「-f」オプションで何番目の列を取り出すかを指定しています。
ユニークな行だけを取り出すuniqコマンド
まったく同じデータを取り除きたいときに便利なのがuniqコマンドです。
ただし、このコマンドを使うにはファイルの内容が予めソートされていなくてはなりません。
そこで、先ほどのsortコマンドと併用して実行すると、同じ行を綺麗に消してくれたりします。
$ sort hoge.csv | uniq
100,apple,20
100,apple,50
102,banana,30
103,orange,75
orangeの行はまったく同じ行となっているため、uniqコマンドにより削除されています。
一方で先頭の3桁のIDが同じものを消して取り出したいと言う場合もあるでしょう。
その場合は、条件判定を文字の位置を指定して実行します。
$ sort foo.csv | uniq -w3
100,apple,20
102,banana,30
103,orange,75
これで、ユニークなIDだけを持つ行を取り出すことができます。
文字の置換ができるsedコマンド
ファイル内の文字を置換したいと言うことは良くあることです。
こういう場合、エディタ(例えばvimとか)で開けば一気に置換できたりもしますが、エディタを使わずともsedコマンドを通して一気に置換をかけることができます。
$ sed -e "s/apple/peach/" hoge.csv
100,peach,50
103,orange,75
102,banana,30
100,peach,20
103,orange,75
出力結果を保存したい場合は、別のファイルにリダイレクトしておきましょう。
sedコマンドも正規表現が使えるほか、非常に豊富で強力な機能を持つコマンドです。
計算も実行できるawkコマンド
awkコマンドは非常に多彩な機能を持つため、ここでは特定の列の合計値を計算するような例しか書いていません。
やりすぎるとプログラミングした方が早いと言うケースもありますしね・・・。
先ほどのCSVファイルの中から3番目の要素である2桁の数値の合計値を求めてみます。
$ cut -d "," -f 3 hoge.csv | awk 'BEGIN {sum=0} {sum+=$1} END {print sum}'
250
少しややこしくなりましたが、やったことはまずcutコマンドで3番目の要素を取り出し、それをawkコマンドに渡しています。
awkコマンドではsumという内部変数を作って、1番目の標準入力(cutコマンドで取り出したCSVファイルの3番目の要素)を足し続けています。
最後にその合計値を出力するといった具合です。
工夫すれば平均値を出すと言うことももちろん可能です。
ファイルの差分を表示するdiffコマンド
こちらもメジャーなコマンドですね。
ファイルを編集して別名で保存した場合、オリジナルと編集後のファイルとの差を見てみたいときに、わかりやすく表示してくれます。
先ほどのsedコマンドで置換したCSVファイルと、オリジナルのhoge.csvファイルのファイルの中身を比較してみると
$ diff foo.csv bar.csv
1c1
< 100,apple,50
---
> 100,peach,50
4c4
< 100,apple,20
---
> 100,peach,20
1行目と4行目が変更されていると言うことがわかります。
diffは、ディレクトリ内の差分をも表示してくれたりできるオプションなども存在します。
この辺りは、以前に書いた「簡単にファイル比較ができるdiffコマンドの使い方
」を参考にしてみてください。
行を結合できるpasteコマンド
行単位でファイルを結合したいという場合に便利なのがpasteコマンドです。
例えば、hoge.csvにロケーションを記述したファイルを結合して1つのファイルにしてみます。
$ more location.txt
tokyo
osaka
nagoya
tokyo
chiba
このファイルに記述したロケーションはhoge.csv内の各行に対応しているという条件で、下記のようにpasteコマンドを実行します。
paste -d "," hoge.csv location.txt
100,apple,50,tokyo
103,orange,75,osaka
102,banana,30,nagoya
100,apple,20,tokyo
103,orange,75,chiba
「-d」オプションで結合時の区切り文字を指定できます。
行頭から指定行数だけを表示するheadコマンド
大きなファイルになると、先頭から何行目までを取り出したい、表示したいということがあったりします。
そういう時はheadコマンドが便利です。
例えば、1行目から3行目までを取り出したい場合は、
$ head -n 3 hoge.csv
100,apple,50
103,orange,75
102,banana,30
のように指定しすれば、ファイルの頭から3行分だけ表示してくれます。
また、行数だけでなデータ量で取り出すこともできます。
例えば、頭から30バイト分だけ表示すると言う場合は、「-c」オプションを指定して下記のように実行します。
$ head -c 30 hoge.csv
100,apple,50
101,orange,75
102
行末から指定行数だけを表示するtailコマンド
こちらは、先ほどのheadコマンドとは逆のコマンドになります。
ファイルの最後からn行を取り出したい、というような場合に使います。
$ tail -n 3 hoge.csv
102,banana,30
100,apple,20
103,orange,75
こちらもheadコマンド同様に「-c」オプションを指定すれば、データ量分だけ取り出すと言うことも可能です。
また、これも予断ですが、tailコマンドは「-f」オプションを指定しておくと、リアルタイムにファイルの変化を追うことができます。
例えば、Apacheのアクセスログはアクセスがあるたびに追記されていくので、
$ tail -f access_log
なんてしてると、アクセス状況が端末に表示され続けます。
システムのログファイルを表示させ続けたりすると、デバッグなんかにも有効だったりしますね。
これらのコマンドを組み合わせることでかなり自由なデータの書こうというものができるかと思います。
わざわざプログラムを書く必要も無いので、Windows上でファイルを編集しようという前にLinuxサーバー上でできることを把握しておけば作業も楽になるのではないでしょうか。