ディスクの空き容量が減った原因を特定したい
df -hでディスクの使用率が上がっていると分かっても、どのディレクトリが容量を占めているかまでは分からない。
$ df -h /
Filesystem Size Used Avail Use% Mounted on
/dev/sda1 50G 47G 3.0G 94% /
使用量の内訳を調べるにはdu(disk usage)コマンドを使う。上の階層から順に大きいディレクトリをたどれば、容量を消費している場所を絞り込める。
以下では次のようなディレクトリ構成を例に説明する。
/work
├── home/example/media/movie.mp4 (300M)
├── home/example/docs/manual.pdf (3M)
├── tmp/dump.sql (90M)
├── var/lib/mysql/ibdata1 (420M)
├── var/log/app.log (180M)
└── var/log/access.log (60M)
duコマンドの基本
引数に指定したディレクトリ配下の使用量を、サブディレクトリごとに表示する。-hオプションでKやMなどの単位付きの表示になる。
$ du -h /work
91M /work/tmp
3.1M /work/home/example/docs
301M /work/home/example/media
304M /work/home/example
304M /work/home
421M /work/var/lib/mysql
421M /work/var/lib
241M /work/var/log
661M /work/var
1.1G /work
すべての階層が出力されるため、対象が大きいと画面が流れて読めない。合計だけを知りたい場合は-s(--summarize)オプションを使う。
$ du -sh /work
1.1G /work
階層を絞って全体像をつかむ
-d(--max-depth)オプションで表示する階層の深さを指定する。-d 1なら指定したディレクトリの直下までを表示する。
$ du -h -d 1 /work
91M /work/tmp
304M /work/home
661M /work/var
1.1G /work
同じ結果はシェルのグロブでも得られる。ただし.で始まる隠しディレクトリが対象から漏れる点に注意する。
$ du -sh /work/*
304M /work/home
91M /work/tmp
661M /work/var
大きい順に並べ替える
du -hの出力はディレクトリの走査順に並ぶため、大きい順に並べ替えると読みやすい。sort -hはKやMなどの単位付きの数値を正しく比較できるので、-hを付けたままの出力をそのままパイプで渡せる。-rを追加すると降順になる。
$ du -h -d 1 /work | sort -hr
1.1G /work
661M /work/var
304M /work/home
91M /work/tmp
sort -hの詳細はsortコマンドでhuman readableな数値をソートする
を参照。
上の階層から掘り下げる
容量を占めている場所の見当が付かない場合は、調査したい範囲の最上位を-d 1で調べ、最も大きいディレクトリを次の調査対象にする。
まず/work直下を見ると/work/varが661Mで最大と分かる。
$ du -h -d 1 /work | sort -hr
1.1G /work
661M /work/var
304M /work/home
91M /work/tmp
次に/work/var直下を調べると、/work/var/libが421Mを占めている。
$ du -h -d 1 /work/var | sort -hr
661M /work/var
421M /work/var/lib
241M /work/var/log
同じ操作を繰り返して原因のディレクトリまでたどり着く。各段階の1行目は指定したディレクトリ自身の合計なので、2行目以降を見る。
-d 2のように深さを増やせば1回で2階層下まで見える。ただし行数が増えるためheadと組み合わせる。
$ du -h -d 2 /work | sort -hr | head -5
1.1G /work
661M /work/var
421M /work/var/lib
304M /work/home/example
304M /work/home
大きなファイルを直接探す
-a(--all)オプションを付けるとディレクトリだけでなくファイルも出力する。原因のディレクトリを特定した後、配下のどのファイルが大きいかを確認できる。
$ du -ah -d 1 /work/var/log
180M /work/var/log/app.log
60M /work/var/log/access.log
241M /work/var/log
-aとsort -hrを組み合わせるとファイルとディレクトリが混ざって並ぶ。ファイルだけを対象にしたい場合はfindの-sizeで絞り込む。
$ find /work -type f -size +100M -exec du -h {} \;
421M /work/var/lib/mysql/ibdata1
301M /work/home/example/media/movie.mp4
180M /work/var/log/app.log
find -sizeの指定方法は【find -size】指定サイズ以上(以下)のファイルを検索する
を参照。
小さい項目を出力から省く
-t(--threshold)オプションを使うと、指定したサイズ以上の項目だけを出力する。小さいディレクトリが多数ある場合に見通しがよくなる。
$ du -h -d 1 -t 300M /work
304M /work/home
661M /work/var
1.1G /work
調査対象から特定のディレクトリを外すには--excludeにパターンを指定する。
$ du -h -d 2 --exclude='*/log' /work | sort -hr | head -3
814M /work
421M /work/var/lib
421M /work/var
読み取れないディレクトリの扱い
権限のないディレクトリは走査されず、標準エラー出力にメッセージが出る。集計からも除外されるため、合計サイズが実際より小さくなる。
$ du -h -d 2 /work | sort -hr | head -3
du: cannot read directory '/work/var/lib/mysql': Permission denied
634M /work
304M /work/home/example
304M /work/home
/配下全体のようにシステム領域を調べる場合はsudoを使う。
$ sudo du -h -d 1 / | sort -hr
エラーメッセージが邪魔な場合は標準エラー出力を捨てる。ただし集計から漏れた分も見えなくなる。
$ du -h -d 1 /work 2>/dev/null | sort -hr
/から調べる場合は-x(--one-file-system)オプションを付けると、別のファイルシステムをたどらない。マウントした外部ストレージやネットワークボリュームを巻き込まずに済む。
$ sudo du -h -d 1 -x / | sort -hr
duの合計とdfの使用量が合わない場合
大きなファイルを削除してもdfの空き容量に反映されない場合がある。プロセスが開いたままのファイルは、削除してもプロセスが終了するまでディスクを占有し続ける。duはディレクトリをたどって集計するため、削除済みのファイルは合計に現れない。
$ du -sh /work
4.0K /work
削除済みのまま開かれているファイルはlsof +L1で確認できる。
$ sudo lsof +L1
COMMAND PID USER FD TYPE DEVICE SIZE/OFF NLINK NODE NAME
tail 56 root 3r REG 0,44 209715200 0 4009144 /work/big.log (deleted)
NLINKが0の項目が該当する。表示されたプロセスを再起動すれば領域が解放される。
対話的に探す
duとパイプの組み合わせでは、階層を1つ下るたびにコマンドを打ち直す必要がある。カーソル操作で掘り下げたい場合はncduが便利。使い方は【Mac】ncduでディスク使用量の大きいディレクトリを探す
を参照。
補足
duが集計するのはディスク上のブロック使用量であり、ファイルサイズの単純な合計ではない。ファイルサイズの合計を知りたい場合は--apparent-sizeオプションを使う。スパースファイルや、ブロックサイズより小さいファイルが大量にあるディレクトリでは両者に差が出る。
Dockerを動かしているホストでは、イメージやボリュームが容量を占めている場合がある。内訳はdocker system dfで確認できる。詳細は【Docker】docker system dfコマンドでディスク使用量の内訳を見る
を参照。
空き容量が十分あるのに書き込めない場合はinodeの枯渇を疑う。【Linux】df -iでinodeの枯渇を調査する を参照。
macOS標準のduはBSD版のため--max-depthや--excludeを受け付けない。深さの指定は-d、除外は-Iを使う。GNU版と同じオプションを使いたい場合はHomebrewでcoreutilsをインストールする。
オプションの詳細はdu(1) - Linux manual page を参照。
