lsofコマンドでは、前々回で紹介してきたように開かれているファイルと、それを開いているプロセスの情報を取得するだけでなく、オプションを指定したり、ほかのコマンドを併用することで表示されるデータを変更したり、絞り込んだりすることもできる。サーバモニタリングの際にはなにかと重宝するコマンドだ。今回は、その辺りの使い方について解説しよう。

lsofの使い方 - ちょっとした応用

lsofコマンドの出力制御はオプションの指定でも可能だが、せっかくなので、本連載でこれまでに紹介してきたさまざまな便利コマンドを使って出力を加工する例を紹介したい。 まず、次のようなデフォルト出力があったとする。

% lsof
COMMAND     PID   USER   FD     TYPE             DEVICE           SIZE/OFF    NODE NAME
kernel        0   root  cwd     VDIR               0,90                512       2 /
kernel        0   root  rtd     VDIR               0,90                512       2 /
init          1   root  cwd     VDIR               0,90                512       2 /
init          1   root  rtd     VDIR               0,90                512       2 /
init          1   root  txt     VREG               0,90            1061880 2809013 /sbin/init
adjkerntz   148   root  cwd     VDIR               0,90                512       2 /
adjkerntz   148   root  rtd     VDIR               0,90                512       2 /
adjkerntz   148   root  txt     VREG               0,90               9896 2808973 /sbin/adjkerntz
adjkerntz   148   root  txt     VREG               0,90             136760 3290906 /libexec/ld-elf.so.1
adjkerntz   148   root  txt     VREG               0,90            1744432  240771 /lib/libc.so.7
adjkerntz   148   root    0u    VCHR               0,26                0t0      26 /dev/null
adjkerntz   148   root    1u    VCHR               0,26                0t0      26 /dev/null
adjkerntz   148   root    2u    VCHR               0,26                0t0      26 /dev/null
...略...
lsof      18412   root  cwd     VDIR               0,90                512 2899866 /Users/daichi/Documents/lwt/20170529/commands
lsof      18412   root  rtd     VDIR               0,90                512       2 /
lsof      18412   root  txt     VREG               0,90             133728 2086789 /usr/local/sbin/lsof
lsof      18412   root  txt     VREG               0,90             136760 3290906 /libexec/ld-elf.so.1
lsof      18412   root  txt     VREG               0,90              60552  240805 /lib/libkvm.so.7
lsof      18412   root  txt     VREG               0,90            1744432  240771 /lib/libc.so.7
lsof      18412   root  txt     VREG               0,90              97592  240798 /lib/libelf.so.2
lsof      18412   root    0u    VCHR              0,109           0t108478     109 /dev/pts/2
lsof      18412   root    1u    VCHR              0,109           0t108478     109 /dev/pts/2
lsof      18412   root    2u    VCHR              0,109           0t108478     109 /dev/pts/2
lsof      18412   root    3r    VCHR               0,19                0t0      19 /dev/mem
lsof      18412   root    4r    VCHR               0,20 0xfffff80003a48280      20 /dev/kmem

lsofコマンドは、「巨大なデータファイルを開いているプロセスを探す」といった目的で使うことがある。上記の出力で言うと、7列目に表示されている「SIZE/OFF(ファイルサイズ)」でソートをかけて、サイズの大きなものから表示させたいところだ。その場合、lsofコマンドと組み合わせてsortコマンドを次のように使えばよい。

% lsof | sort --numeric-sort -k7,7 -r
nginx       602 daichi    4w    VREG               0,90            3657866 2167622 /var/log/nginx/access.log
nginx       600   root    4w    VREG               0,90            3657866 2167622 /var/log/nginx/access.log
vmtoolsd    142   root  txt     VREG               0,90            2802048 2329561 /usr/local/lib/libicui18n.so.58.2
sshd      10964 daichi  txt     VREG               0,90            2529000  240770 /lib/libcrypto.so.8
sshd      10962   root  txt     VREG               0,90            2529000  240770 /lib/libcrypto.so.8
sshd        637   root  txt     VREG               0,90            2529000  240770 /lib/libcrypto.so.8
ssh-agent   801 daichi  txt     VREG               0,90            2529000  240770 /lib/libcrypto.so.8
sendmail    643  smmsp  txt     VREG               0,90            2529000  240770 /lib/libcrypto.so.8
sendmail    640   root  txt     VREG               0,90            2529000  240770 /lib/libcrypto.so.8
nginx       602 daichi  txt     VREG               0,90            2529000  240770 /lib/libcrypto.so.8
nginx       600   root  txt     VREG               0,90            2529000  240770 /lib/libcrypto.so.8
nvim      18073 daichi  txt     VREG               0,90            2505328 2410252 /usr/local/bin/nvim
vmtoolsd    142   root  txt     VREG               0,90            1812440 2332339 /usr/local/lib/libicuuc.so.58.2
ydwait    18625 daichi  txt     VREG               0,90            1744432  240771 /lib/libc.so.7
vmtoolsd    142   root  txt     VREG               0,90            1744432  240771 /lib/libc.so.7
syslogd     492   root  txt     VREG               0,90            1744432  240771 /lib/libc.so.7
sudo      18676   root  txt     VREG               0,90            1744432  240771 /lib/libc.so.7
sshd      10964 daichi  txt     VREG               0,90            1744432  240771 /lib/libc.so.7
sshd      10962   root  txt     VREG               0,90            1744432  240771 /lib/libc.so.7
sshd        637   root  txt     VREG               0,90            1744432  240771 /lib/libc.so.7
ssh-agent   801 daichi  txt     VREG               0,90            1744432  240771 /lib/libc.so.7
sh        18066 daichi  txt     VREG               0,90            1744432  240771 /lib/libc.so.7
sendmail    643  smmsp  txt     VREG               0,90            1744432  240771 /lib/libc.so.7
sendmail    640   root  txt     VREG               0,90            1744432  240771 /lib/libc.so.7
rpcbind     511   root  txt     VREG               0,90            1744432  240771 /lib/libc.so.7
rpc.statd   545   root  txt     VREG               0,90            1744432  240771 /lib/libc.so.7
rpc.lockd   548   root  txt     VREG               0,90            1744432  240771 /lib/libc.so.7
nvim      18073 daichi  txt     VREG               0,90            1744432  240771 /lib/libc.so.7
...略...
ydwait    18736 daichi    7r    VREG               0,90               1165 2899873 /Users/daichi/Documents/lwt/20170529/typescript.html
rpc.statd   545   root    3r    VREG               0,90                789 2495738 /etc/netconfig
ydwait    18736 daichi    5r    VREG               0,90                565 2899865 /Users/daichi/Documents/lwt/20170529/Makefile
ydwait    18736 daichi    6r    VREG               0,90                539 2904027 /Users/daichi/Documents/lwt/20170529/typescript.xml
...略...
%

sortコマンドは、オプションとして「—numeric-sort」を指定すると、対象を数字として比較してくれる。これを指定しないと、例えば「10」と「2」では2のほうを大きな値として処理してしまうのだ。「—numeric-sort」をオプションに指定すると、「数字の10」と「数字の2」として比較するようになり、10のほうが大きな値だと認識して処理してくれる。

また、今回はファイルサイズの大きなものほど上位に表示させたいので、「-r」も指定する。これで、サイズの大きな順に表示するようになる。そして、「-k7,7」だ。このオプションで7列目の値(つまりファイルサイズ)をソートの対象としてくれる。「—numeric-sort」を指定したソートは何かと便利なので、これを機に覚えておいてもらえればと思う。

実際にデータを使うとなると、上記の出力では余分なデータが含まれているし、ファイルサイズ以外のデータも表示されている。そこで、次のようにawkコマンドやgrepコマンドを組み合わせると、表示データを絞り込むことができる。

% lsof | awk '{print $1,$7}'            |
> sort --numeric-sort -k2,2 -r          |
> grep -E ' [0-9]+$'
nginx 3657866
nginx 3657866
sshd 2529000
sshd 2529000
sshd 2529000
ssh-agent 2529000
sendmail 2529000
sendmail 2529000
nginx 2529000
nginx 2529000
nvim 2505328
nvim 2505328
ydwait 1744432
syslogd 1744432
sudo 1744432
sshd 1744432
sshd 1744432
sshd 1744432
ssh-agent 1744432
sh 1744432
sendmail 1744432
sendmail 1744432
...略...
lsof 0
gsort 0
fish 0
fish 0
fish 0
fish 0
awk 0
%

まず、「awk ‘{print $1,$7}’」の処理でデータを1列目と7列目に絞り込むことができる。データが2列になったので、ソートの処理では「sort —numeric-sort -k2,2 -r」と指定して2列目をソートの対象にする。最後に、「grep -E ’ [0-9]+$’」の処理でファイルサイズ以外のデータが表示されている行を除外している。「’ [0-9]+$’」の指定で2列目に数字以外のデータが含まれている行を除外しているのだ。

実際の業務ではこういった処理をスクリプトにまとめておき、一定以上のサイズのファイルが開かれていたり、開かれているファイルの総サイズ数が一定の値を超えたりした場合、管理者に警告のメールを送信するといった処理を組むことになるだろう。後は「crontab(5)」に登録して定期的に実行するようにすれば、管理の手間が1つ減るというわけだ。

こんな感じで何らかのコマンドで必要なデータを含む値を出力させて、ほかのコマンドで出力されたデータを切り貼りし、結果として別の処理を行わせる……というのが、管理を自動化する際の1つのポイントとなる。