sortコマンドでCSVファイルをソートする場合はソート列の指定方法に注意
はじめに
sort
コマンドを使ってソートを行うとき、「CSVファイル」や「TSVファイル」を対象とすることがあります。
ただし、意外と知られていないのがソートの条件として任意の列を指定する方法について。
-k
オプションを使えば可能なのですがひと癖あるオプションなので取り上げました。
sort
コマンドの挙動でハマった方の手助けになれば幸いです。
検証環境
準備
CSVをJSONに変換するためのNode.jsライブラリ「csv2json」 | ゲンゾウ用ポストイット でも使ったダミーデータ生成サービスを利用してCSVデータを取得します。
test.csv
整形すると以下のようなデータとなります。
CSVやTSVのソートに使われるオプションは2つ
sort
コマンドでCSVデータを取り扱う際には、「列の区切り文字」と「ソートに利用する列」を指定する必要があります。
- 「列の区切り文字」は
-t
オプションを使って指定します。 - 「ソートに利用する列」は、
-k
オプションを使って指定します。- 列番号を指定します。一番左の列は 1 として扱われます。
実際に試してみます。
わかりやすいように column -t -s,
(CSVファイルを表形式に整形するコマンド)で整形して出力します。
気持ちの悪い点があります。 年齢順にソートしたつもりが正しくソートされていません(9才が一番下にある)。
これを解消していきましょう。
数値列のソート時には数値であることを教えて上げる必要がある
「1. 年齢順にソートしたつもりが正しくソートされていない(9才が一番下にある)」 について。sort
コマンドは ソート列の値を一文字ずつ辞書順にソート します。57
と 9
を比較した場合、一文字目の 5
と 9
では 5
のほうが小さいと判断されたわけです。
これを解消するためには -k5
オプションの後ろに n
という値を付与して数値の大小比較をさせるように指定します。
27
と 9
の値が正しくソートされていません。
なぜこのようなことが起こるのでしょうか?
実はこれ、 sort
の -k
オプションのわかりにくいところなんですね。
sort
コマンドの-k
オプションは「単一のソート列」を指定するものではない!
man
コマンドで sort
コマンドのオプションに関して調べてみましょう。
苦手な英語(^^;)を紐解くと以下のようなことがわかります。
- 「
-k
オプションではフィールド番号を指定する」 - カンマ区切りで2つの数値を指定できる
- カンマの前は「ソートに利用する列」の開始列番号
- カンマの後ろは「ソートに利用する列」の終了列番号
- デフォルトは行末
つまり、以下のコマンドはいずれも同じ処理を行っていることになります。
cat test.csv | sort -t, -k5n | column -t -s,
cat test.csv | sort -t, -k5,6n | column -t -s,
先程の問題は5列目の「年齢」だけでなく、6列目の「取得ポイント」列までをつなげて1つの数値として扱い、ソートされてしまったようです。
sort
コマンドの-k
オプションで「単一のソート列」を指定するには
先程のコマンドは以下のようにソート条件開始列、ソート条件終了列の両方を指定して、5列目だけを扱うようにすれば解決します。
-k
オプションは複数指定可能
「年齢」が同じデータについては、さらに「取得ポイント」でソートしたいと思います。
44
才の方のデータが「取得ポイント」順に表示されるようにしたい場合は-k
オプションを更に追加します。
ディスカッション
コメント一覧
まだ、コメントがありません