sortコマンドで複数キーによるソート
sort コマンドの挙動がわかりにくかったのでメモです。
サンプルとして次のような3つのフィールドを持ったデータを使います。
sort_sample.tsv
5 aab 5
1 abb 5
10 aab 10
5 abb 1
1 baa 10
1 aba 5
10 bab 5
10 abb 10
1 bab 1
1 aab 5
sort コマンドではキーに関してソートを行います。
このキーはデフォルトで1行全体です。つまり
$ sort sort_sample.tsv
1 aab 5
1 aba 5
1 abb 5
1 baa 10
1 bab 1
10 aab 10
10 abb 10
10 bab 5
5 aab 5
5 abb 1
のように、得られる結果としては第1フィールドに関してASCIIコードの昇順にソートされ、第1フィールドの同じものは第2フィールドに関してASCIIコードの昇順にソートされ、第1フィールドも第2フィールドも同じものは第3フィールドに関してASCIIコードの昇順にソートされたものとなっています。
-k オプションを使ったソート
このソートをもっと柔軟に行うために用意されているのが -k オプションです。
次のように指定します。
-k POS1[,POS2]
ここで、POS1はキーの最初となる位置、POS2はキーの最後となる位置です。POS1以降全体がキーとなります。
POS1やPOS2は次のように指定します。
フィールドの位置[.文字の位置][ソートのオプション]
※POS1の文字の位置を省略すると1になり、POS2の文字の位置を省略するとそのフィールドの最後の文字までが対象になるみたいです
※第1フィールド以外は区切り文字を指定しない限り区切り文字が含まれるらしく、区切り文字を除いた2文字目を指定するには3にする必要があります
例えば、第2フィールドでソートして、第2フィールドが同じものは第3フィールドでソートしたければ
$ sort -k 2 sort_sample.tsv
10 aab 10
1 aab 5
5 aab 5
1 aba 5
5 abb 1
10 abb 10
1 abb 5
1 baa 10
1 bab 1
10 bab 5
となります。
これを第2フィールドでソートして、第2フィールドが同じものは第3フィールドで数値としてソートしたければ
$ sort -k 2,2 -k 3n sort_sample.tsv
1 aab 5
5 aab 5
10 aab 10
1 aba 5
5 abb 1
1 abb 5
10 abb 10
1 baa 10
1 bab 1
10 bab 5
となります。-k 2,2 のように範囲を絞るのがポイントです。
これが -k 2 のままだと
$ sort -k 2 -k 3n sort_sample.tsv
10 aab 10
1 aab 5
5 aab 5
1 aba 5
5 abb 1
10 abb 10
1 abb 5
1 baa 10
1 bab 1
10 bab 5
のように所望の結果は得られません。これはおそらく第2フィールドでASCIIコードとしてソートし、第2フィールドが同じものは第3フィールドでASCIIコードとしてソートし、第2フィールドと第3フィールドが同じものは第3フィールドで数値としてソートする、という無意味な指定になっているんだと思います。
最後に・・・
そんなわけで、-k オプションを駆使すれば第1フィールドはASCIIコードとして昇順にソートして、第2フィールドは2文字目に関してASCIIコードとして降順にソートして、第3フィールドは数値として降順にソートするという変態的なことまでできるわけです。
$ sort -k 1,1 -k 2.3,2.3r -k 3,3n sort_sample.tsv
1 aba 5
1 abb 5
1 baa 10
1 aab 5
1 bab 1
10 abb 10
10 aab 10
10 bab 5
5 abb 1
5 aab 5
※区切り文字を指定した場合は -k 2.2,2.2r になります
sort コマンド便利ですねっ!!!!