lsof: list open files

Linux command 2/N

公開日: 2022-08-02
更新日: 2022-08-04

  Table of Contents

What is lsof command?

lsof commandはオープンしているファイルを一覧表示するコマンドです. 引数なしの出力を確認してみます:

1
2
3
4
5
6
7
8
9
10
11
12
13
% lsof | head
lsof: WARNING: can't stat() fuse.gvfsd-fuse file system /run/user/125/gvfs
      Output information may be incomplete.
COMMAND     PID   TID TASKCMD               USER   FD      TYPE             DEVICE  SIZE/OFF       NODE NAME
systemd       1                             root  cwd   unknown                                         /proc/1/cwd (readlink: Permission denied)
systemd       1                             root  rtd   unknown                                         /proc/1/root (readlink: Permission denied)
systemd       1                             root  txt   unknown                                         /proc/1/exe (readlink: Permission denied)
systemd       1                             root NOFD                                                   /proc/1/fd (opendir: Permission denied)
kthreadd      2                             root  cwd   unknown                                         /proc/2/cwd (readlink: Permission denied)
kthreadd      2                             root  rtd   unknown                                         /proc/2/root (readlink: Permission denied)
kthreadd      2                             root  txt   unknown                                         /proc/2/exe (readlink: Permission denied)
kthreadd      2                             root NOFD                                                   /proc/2/fd (opendir: Permission denied)
rcu_gp        3                             root  cwd   unknown                                         /proc/3/cwd (readlink: Permission denied)

defaultでの表示項目は

COMMAND ファイルを開いているプロセスのコマンド名
PID process id
TID thread identifier
TASKCMD task command
USER processをcreateしたユーザー名
FD file descriptor
TYPE 種類(directory, file, and so on)
DEVICE デバイス
SIZE/OFF ファイルサイズまたはオフセット
NODE i-node number
NAME openの対象となるファイル名

FD, file descriptor,の種類

FDカラムに出現するオブジェクトは大きく分けて2つのパターンがあります:

  • 特定の文字列
  • 数字 + アルファベットの組合せパターン

FDカラムに出現する特定の文字列

cwd Current Working Directory
txt Text file
mem Memory mapped file
mmap Memory mapped device

数字 + アルファベットの組合せパターン

1uというパターンの場合, 標準出力によるread and writeモードを表しています

  • 数字: 標準入出力0~2, シェル以外のプロセスはに続く3番以降を使用
  • alphabet: ファイルが開かれているモード

standard file descriptor numeric value

0 Standard input (stdin)
1 Standard output (stdout)
2 Standard error (stderr)

Alphabet Rule

r read access
w write access
u both of read and write access
R a read lock on the entire file;
W a write lock on the entire file;
U a lock of unknown type;

fuse.gvfsd-fuse warning

lsofコマンドはdefaultではmountされたfile system全てに対して動作します. 一方, FUSU を用いてmountされたGVFSファイルは, mountしたUSER(=gvfsd-fuse)以外のアクセスを拒否する挙動となっており, gvfsd-fuseでないならば管理者権限のあるユーザからもアクセスできないようになっています.

そのため, lsofが動作しませんというwarningが出力される訳となります. 基本的には無視してかまわないものです.

対処方法を知りたい場合は, stackExchange > lsof: WARNING: can’t stat() fuse.gvfsd-fuse file systemを確認してください.

List opened files with a condition

lsofコマンドを用いて興味のあるprocessを検索したい場合は効率的に検索が掛けられるようになる必要があります. 執筆時点でのUbuntu OS上で開かれているファイル数を検索すると

1
2
3
4
% lsof | wc -l
lsof: WARNING: can't stat() fuse.gvfsd-fuse file system /run/user/125/gvfs
      Output information may be incomplete.
907374

と人間の目で検索するには大変すぎるラインがあることがわかります. 検索するにあたって, grep, awkを用いるのも一つの手段ですが, lsofにbuilt-inとして組み込まれている検索オプションを理解すると便利です. 以下, 代表的なものを紹介します.

List opened files by a specified user

1
% lsof -u <username>

特定のuser以外という条件でsearchする場合は

1
% lsof -u ^<username>

List opened files by a specified command

1
% lsof -c <command>

List opened files under a directory

1
% lsof +D <directory>

List all open files by a specific process

1
% lsof -p <process-id>

List all open files at a specified port

1
% lsof -i:<port-number>

複数のportで検索したい場合は

1
% lsof -i:<port-number>,<port-number>

How do we combine multiple conditions: AND/OR

Defaultでは複数条件を組み合わせると, OR条件で検索が走る挙動となっています:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
% lsof -u hoge -c systemd |head
lsof: WARNING: can't stat() fuse.gvfsd-fuse file system /run/user/125/gvfs
      Output information may be incomplete.
COMMAND     PID             USER   FD      TYPE             DEVICE  SIZE/OFF       NODE NAME
systemd       1             root  cwd   unknown                                         /proc/1/cwd (readlink: Permission denied)
systemd       1             root  rtd   unknown                                         /proc/1/root (readlink: Permission denied)
systemd       1             root  txt   unknown                                         /proc/1/exe (readlink: Permission denied)
systemd       1             root NOFD                                                   /proc/1/fd (opendir: Permission denied)
systemd-j   325             root  cwd   unknown                                         /proc/325/cwd (readlink: Permission denied)
systemd-j   325             root  rtd   unknown                                         /proc/325/root (readlink: Permission denied)
systemd-j   325             root  txt   unknown                                         /proc/325/exe (readlink: Permission denied)
systemd-j   325             root NOFD                                                   /proc/325/fd (opendir: Permission denied)
systemd-u   379             root  cwd   unknown                                         /proc/379/cwd (readlink: Permission denied)

hogeと指定したにもかかわらず, headで確認できる範囲内はUSERはrootとなっています. このOR条件をAND条件へ変更したい場合は-a optionを最後に付与します.

1
2
3
4
5
6
7
8
9
10
11
12
13
% lsof -u hoge -c systemd -a |head   
lsof: WARNING: can't stat() fuse.gvfsd-fuse file system /run/user/125/gvfs
      Output information may be incomplete.
COMMAND  PID    USER   FD      TYPE             DEVICE SIZE/OFF       NODE NAME
systemd 1934 hoge  cwd       DIR              259,3     4096          2 /
systemd 1934 hoge  rtd       DIR              259,3     4096          2 /
systemd 1934 hoge  txt       REG              259,3  1620224     927712 /usr/lib/systemd/systemd
systemd 1934 hoge  mem       REG              259,3  1369384     922181 /usr/lib/x86_64-linux-gnu/libm-2.31.so
systemd 1934 hoge  mem       REG              259,3   178528     923096 /usr/lib/x86_64-linux-gnu/libudev.so.1.6.17
systemd 1934 hoge  mem       REG              259,3  1575112     926081 /usr/lib/x86_64-linux-gnu/libunistring.so.2.1.0
systemd 1934 hoge  mem       REG              259,3   137584     925304 /usr/lib/x86_64-linux-gnu/libgpg-error.so.0.28.0
systemd 1934 hoge  mem       REG              259,3    67912     925517 /usr/lib/x86_64-linux-gnu/libjson-c.so.4.0.0
systemd 1934 hoge  mem       REG              259,3    34872     924835 /usr/lib/x86_64-linux-gnu/libargon2.so.1

USERがhogeだけになっており, 出力内容がAND条件に基づいているとわかります.

Output the process ID that matches the condition

特定の条件に従ってlsofを出力する場合, 条件に合致したprocessのpidをkillしたいなどが要望として多くのケースあります. lsofから目件でPIDを確認するという方法もありますが, -t optionを用いることで, PIDを効率的に出力することが出来ます:

1
2
% lsof -t -u hoge -c systemd -a
1934

これをpipeや$()を用いてコマンドを組合せて使用したりします. 例として,

1
% kill -9 $(lsof -t -u hoge)

このコマンドによって, USER hogeによるprocess全てをkillすることができます. なお, <filename>を引数で用いる際は, lsof -t <filename>としてください.

Example: kill the process which access to /var/log/bad.log

とあるサーバー上のプログラムが継続的に/var/log/bad.logに書き込みを行っており, そのためserver storageが逼迫しています. /var/log/bad.logにアクセスしているプログラムをまとめてkillしたい場合は

1
2
3
4
$ lsof /var/log/bad.log
COMMAND   PID   USER   FD   TYPE DEVICE SIZE/OFF  NODE NAME
badlog.py 618 ubuntu    3w   REG  259,1     7696 67701 /var/log/bad.log
$ kill $(lsof -t /var/log/bad.log)

Tips

output based on the FD status

lsofコマンドにはFD statusに応じて検索を掛けられる機能はdefaultでは存在しません. 特定の<filename>に対して, 書き込み動作をしているprocessを検索したい場合はawkをpipeで繋いで以下のように入力します.

1
2
3
4
5
## file version
% lsof <filename>| awk '(NR == 1) || ($4 ~ "[0-9]{1,}[a-z]{1,}[UNR]{0,}" && $4 ~ "[uw]" && NF == 9) || ($6 ~ "[0-9]{1,}[a-z]{1,}[UNR]{0,}" && $6 ~ "[uw]" && NF == 11 )  {print $0}'

## directory version
lsof +D <directory>| awk '(NR == 1) || ($4 ~ "[0-9]{1,}[a-z]{1,}[UNR]{0,}" && $4 ~ "[uw]" && NF == 9) || ($6 ~ "[0-9]{1,}[a-z]{1,}[UNR]{0,}" && $6 ~ "[uw]" && NF == 11 )  {print $0}'

Appendix: Inode number(index node number)

inodeは, filesystem内の各fileやdirectoryに割り当てられたint型整数で表現される一意の識別子のことです. inodeのなかにfileやdirectoryのmedata(permission, file size, and on)が格納されています.

各filesystemにinodeの上限設定数値があり, 使用可能なinodeの数はそのfilesystem上で作成できる最大のfileやdirectoryの数となります.

fileやdirectoryのinodeを確認したい場合は, ls -iで確認することが出来ます:

1
2
3
4
5
6
7
8
9
10
## [inode, name]の順番で出力される
% ls -i|head
  919688 airflow/
 2102745 app_icon/
 1183217 bin/
 5507154 deb_packages/
  786495 Desktop/
  786769 Documents/
  786766 Downloads/
 1183239 gems/

References



Share Buttons
Share on:

Feature Tags
Leave a Comment
(注意:GitHub Accountが必要となります)