シナプス技術者ブログ

シナプスの技術者公式ブログ。インターネットで、鹿児島の毎日を笑顔にします。

こんな時、どうsortする?

技術部ネットワーク課の上曽山です。
ログの分析や集計を行う時やコマンドの実行結果を整理する時、よくsortコマンドを使います。

最近、立て続けにsortの使い方で悩まされる場面があったので、どんなオプションを使えば適切に並び替えられるのかまとめました。

ケース1: 異なる単位の数値を並べる

ディスク使用量やファイルサイズを調べる時、human-readableな表記に変換されていると、うまくsort出来ません。

$ sudo du -sh /boot/*/ |sort
0       /boot/efi/
1.4M    /boot/extlinux/
4.0K    /boot/grub/
8.1M    /boot/grub2/

こんな時は-hオプションを使います。

shortオプション longオプション 機能
-h --human-numeric-sort 人間が読みやすい単位の数値を比較する

実行結果は以下の通りです。

$ sudo du -sh /boot/*/ |sort -h
0       /boot/efi/
4.0K    /boot/grub/
1.4M    /boot/extlinux/
8.1M    /boot/grub2/

比較対象の数値が先頭に無い時は-kと併用しましょう。

$ df -h |sort -k 2h
Filesystem      Size  Used Avail Use% Mounted on
tmpfs           1.1G     0  1.1G   0% /run/user/1000
devtmpfs        5.4G     0  5.4G   0% /dev
tmpfs           5.4G     0  5.4G   0% /dev/shm
tmpfs           5.4G     0  5.4G   0% /sys/fs/cgroup
tmpfs           5.4G  561M  4.9G  11% /run
/dev/sda1        10G  4.7G  5.4G  47% /
/dev/sda4        93G  6.7G   87G   8% /mnt

-kと併用する時はフィールドを指定する数字とオプションの間にスペースを入れないよう注意してください。

$ df -h |sort -k 2 h
sort: cannot read: h: No such file or directory

ケース2: 複数のログから抽出した結果を時系列順に並べる

syslogで出力されるログは月名が英字(JanとかFebとか)になっているためsortが難しい。

例えば、ユーザー「hogehoge」が最後にFTPログインした日を調べて欲しい、と言われた時。
※以下のログはダミーです。

$ zgrep -h "hogehoge.*LOGIN" /var/log/ftp/ftp.log*
Oct 10 13:30:12 example vsftpd[7785]: [hogehoge] OK LOGIN: Client "192.168.0.1"
Aug 25 05:30:12 example vsftpd[3074]: [hogehoge] OK LOGIN: Client "192.168.0.1"
Sep 15 18:10:11 example vsftpd[6269]: [hogehoge] OK LOGIN: Client "192.168.0.3"
Jul 30 17:20:07 example vsftpd[2810]: [hogehoge] OK LOGIN: Client "192.168.0.1"
Jul 27 01:10:09 example vsftpd[1389]: [hogehoge] OK LOGIN: Client "192.168.0.1"
Aug 29 11:50:11 example vsftpd[2964]: [hogehoge] OK LOGIN: Client "192.168.0.2"
Sep  2 16:30:12 example vsftpd[8845]: [hogehoge] OK LOGIN: Client "192.168.0.2"
Sep 23 04:00:13 example vsftpd[3274]: [hogehoge] OK LOGIN: Client "192.168.0.1"
Jul 16 01:20:07 example vsftpd[2058]: [hogehoge] OK LOGIN: Client "192.168.0.3"

これをsortするには-M-nを使います。

shortオプション longオプション 機能
-M --month-sort 英字の月名(Jan..Dec)で比較する
-n --numeric-sort 文字列を数値として比較する

実行結果は以下の通りです。

$ zgrep -h "hogehoge.*LOGIN" /var/log/ftp/ftp.log* | sort -k 1M -k 2n
Jul 16 01:20:07 example vsftpd[2058]: [hogehoge] OK LOGIN: Client "192.168.0.3"
Jul 27 01:10:09 example vsftpd[1389]: [hogehoge] OK LOGIN: Client "192.168.0.1"
Jul 30 17:20:07 example vsftpd[2810]: [hogehoge] OK LOGIN: Client "192.168.0.1"
Aug 25 05:30:12 example vsftpd[3074]: [hogehoge] OK LOGIN: Client "192.168.0.1"
Aug 29 11:50:11 example vsftpd[2964]: [hogehoge] OK LOGIN: Client "192.168.0.2"
Sep  2 16:30:12 example vsftpd[8845]: [hogehoge] OK LOGIN: Client "192.168.0.2"
Sep 15 18:10:11 example vsftpd[6269]: [hogehoge] OK LOGIN: Client "192.168.0.3"
Sep 23 04:00:13 example vsftpd[3274]: [hogehoge] OK LOGIN: Client "192.168.0.1"
Oct 10 13:30:12 example vsftpd[7785]: [hogehoge] OK LOGIN: Client "192.168.0.1"

月名の部分を-Mで、日付の部分から後を`-n‘でsortした事になります。

ケース3: rpmパッケージをバージョン順に並べる

rpmパッケージのバージョンは数字英字が混じっているため、これまたsortしにくいものになっています。

サンプルとしてkernelのバージョンをオプション無しでsortします。

$ rpm -q kernel |sort
kernel-3.10.0-1062.4.1.el7.x86_64
kernel-3.10.0-957.10.1.el7.x86_64
kernel-3.10.0-957.12.2.el7.x86_64
kernel-3.10.0-957.1.3.el7.x86_64
kernel-3.10.0-957.21.2.el7.x86_64

今度は-Vを使います。

shortオプション longオプション 機能
-V --version-sort 自然な(バージョン)番号順で比較する

実行結果は以下の通りです。

$ rpm -q kernel |sort -V
kernel-3.10.0-957.1.3.el7.x86_64
kernel-3.10.0-957.10.1.el7.x86_64
kernel-3.10.0-957.12.2.el7.x86_64
kernel-3.10.0-957.21.2.el7.x86_64
kernel-3.10.0-1062.4.1.el7.x86_64

最後に

色んなデータ処理をする時、整理する方法が分からないと時間をかけて力技で解決したり、複数のコマンドを組み合わせてトリッキーな手段を使う事が多いかと思います。
# 私だけですかね?(汗)

よく使われるコマンドには意外と便利なオプションが用意されているので、すべてを把握するのは無理だろうけど、1回くらい試しに実行してみると視野が開けるかもしれません。