ByteScope

du

読み取りのみ

ディレクトリツリーが占めているディスク容量を報告します。

コマンド
adb shell du
コマンド
ファイルとストレージ
リスク
読み取りのみ

構文

du [-k] [-m] [-K] [-b] [-a] [-s] [-d <depth>] [-h] <path>

フラグと引数

トークン意味
-k1024 バイト単位で印字します。既定でもそうなので、これは明示のためです。
-m1 MiB 単位で印字します。
-K512 バイト単位で印字します。
-b使用ブロックではなく見かけのファイルサイズを印字します。
-s引数ごとに合計 1 行だけ。ディレクトリごとの行を出しません。
-aディレクトリだけでなくファイルも含めます。
-d <n>深さを制限します。引数自身が深さ 0 なので、`-d 1` は引数とその直下の子を印字します。
-h人間向けのサイズ。読むには便利で、解析するには不正確です。
-cすべての後ろに総合計の行を足します。パス列に入るのはディレクトリではなく `total` という語そのもので、パーサは行数を数えずに本物の行と区別できます。
-x別のファイルシステムへ渡ることを拒みます。端末ではこれが効きます。共有ストレージと userdata パーティションは別のマウントなので、両方より上から歩き始めると、同じブロックを 2 つの名前の下で二重に数えかねません。
-lハードリンクされたファイルを、1 回ではなくリンクごとに数えます。既定は inode で重複を除いていて、それが「消したらどれだけ戻るか」への正直な答えです。

使用例

  • du -k -d 2 /sdcard

    共有ストレージの上位 2 階層を KiB で。

  • du -k -s /sdcard/DCIM

    カメラロールの合計を 1 つの数値で。

  • du -k -d 1 /sdcard/Android/data

    アプリごとのデータディレクトリ。読めるかどうかは Android のバージョン次第です。

  • du -k -d 1 /data/local/tmp

    shell が完全に所有しているディレクトリなので拒否は出ず、合計が完全であることが分かっています。

  • du -k -s -c /sdcard/DCIM /sdcard/Download

    合計 2 つと、それを足した `total` の行。手で足すより安く、しかも手で足した数と丸めが食い違いません。

出力の読み方

出力例

12048	/sdcard/DCIM/Camera
12456	/sdcard/DCIM
348920	/sdcard

サイズ、タブ 1 文字、パスの並びで、1 ディレクトリ 1 行。後行順なので、含まれる子が親より先に出ます。区切りはタブで、しかも意味を持つのは最初の 1 つだけです。だからファイル名に空白(規格上はタブも)が入っていても壊れません。この行を空白で分割しないでください。

出力フィールド

フィールド意味
<size>フラグが指定した単位で。既定は 1024 バイトブロックです。
<tab>唯一の区切り文字。
<path>端末上のとおりのディレクトリ。
total`-c` の総合計行。そのパスは実在のディレクトリではなくその単語です。
du: <path>: Permission denied標準エラーに出て、表に混ざります。飛ばされたディレクトリで、それを含むすべての合計が過小になります。

必要な権限

root も `adb root` も要らず、USB デバッグを超えて開発者向けオプションで入れるものもありません。実際にツリーのどこまで測れるかを決めるのは、`adbd` が権限を落とす前に `shell` ユーザーへ渡すグループの一覧です。`packages/modules/adb/daemon/main.cpp` は補助 gid として `sdcard_r`、`sdcard_rw`、`ext_data_rw`、`ext_obb_rw` を名指ししていて、共有ストレージが(そしてたいていのビルドでは `/sdcard/Android/data` も)ケーブルからはきれいに測れるのに、同じ端末の普通のアプリはどちらも断られる理由がまさにそこです。それでも shell が開けないのは `/data/data` と `/data/user/0` のアプリ専用ストレージで、そこへ `du` を向けると数値ではなく拒否のページが返ります。root なしの入り口は、debuggable なパッケージに対する `run-as` です。ここには書き込みが一切ありません。ディレクトリを開き、カーネルが報告するブロック数を足し、印字するだけです。途中で出会う拒否も致命的ではなく、ディレクトリを歩く側は読めなかったディレクトリごとに報告して先へ進みます。だからエラーが混ざって届いた合計は「部分的な」合計で、そう明言しているのは終了コードだけです。Android Storage Analyzer が 1 階層ずつ掘るのはそのためで、断られたサブツリーは、それを含む何かに黙って畳み込まれるのではなく、絵の中の穴として見えたままになります。

エラーメッセージの読み解き

メッセージ意味
du: /sdcard/Android/data/com.example: Permission denied歩く側がそのディレクトリを開けず、標準エラーに名指しして先へ進みました。既に印字された行はすべて正しく、それを含むディレクトリの合計だけが中身のぶん足りません。Android 11 以降、共有ストレージ配下のアプリ別ディレクトリのどれを shell が開けるかはバージョンとベンダー次第なので、合計と拒否が混ざるのは壊れた実行ではなく普通の答えです。
du: /sdcard/nope: No such file or directory引数そのものを調べられませんでした。上の失敗とは別物で、何も測られておらず 1 行も印字されていません。ほとんどの場合、綴りを間違えて組み立てたパスです。最近のビルドの共有ストレージは FUSE の層で名前を大文字小文字を区別せずに比較しますが、単に間違っている名前を直してくれるものは何もありません。
du: Missing argument to -d (see "du --help")`-d` は深さを別の語として求めます。toybox のオプションパーサが `du` 自身より先にこれを上げるので、何も測られていません。`(see "… --help")` の接尾辞はそのパーサが付けるもので、頼れる目印になります。これを持つ行は引数の誤りであって、ファイルシステムの問題ではありません。
du: -d < 0 (see "du --help")`-d` は `d#<0`、つまり下限 0 の数値として宣言されているので、負の深さは範囲外で、何も測られません。`-d -1` に手を伸ばした人がここに来ます。-1 は `du` が内部で「無制限」に使っている値だからです。ただし無制限に歩かせたいなら、その数値を渡すのではなく `-d` を付けないのが正解です。行が出ない側も押さえておいてください。`-h`・`-k`・`-K`・`-m` は排他ではなく後勝ちのグループなので、`du -k -h` は黙って受け付けられ、最後に書いたフラグが勝ちます。

バージョンとメーカーに関する注意

  • 既定の単位は 1024 バイトのブロックで、割り算は「切り上げ」です。1 バイトのファイルは 1 と報告され、極小ファイル 1 万個のディレクトリは中身のバイト数よりずっと大きく報告されます。それは実際に占めているディスク量として正しく、消すものを決めるときの正しい問いですが、ファイルサイズの合計ではありません。もう一方の問いには `-b` が答えます。
  • `-h` は便利で曖昧です。有効桁は 3 つしか残らず、キロバイトの接尾辞より上の文字は 1000 で割ったか 1024 で割ったかで同じです。数値が重要ならブロック単位で頼んでください。
  • 出力に混ざる `du: …: Permission denied` はノイズではなく本当の発見です。Android 11 以降、共有ストレージ配下のアプリ別ディレクトリへのシェルからの読み取りはバージョンとメーカー次第です。
  • `adbd` が shell に与える補助グループ(`sdcard_r`、`sdcard_rw`、`ext_data_rw`、`ext_obb_rw`)こそが、そもそも共有ストレージをケーブルから測れるようにしているものです。`du` の内側は権限を要求しませんし、何かがそれを与えることもできません。
  • 断られたディレクトリは歩みを終わらせないので、エラーを印字した実行は合計も印字していて、その合計は開けなかったぶんちょうど足りません。標準エラーを集めないと、その不足は見えないままです。

これには UI があります

Android Storage Analyzer はこのコマンドを USB 経由で実行し、返ってきたものを解析します。Chromium 系ブラウザだけで、SDK も不要、どこにもアップロードしません。

Android Storage Analyzer を開く

関連コマンド

du と同じ作業で出てくるコマンド。

コマンド何をするか
dfマウントされているファイルシステムごとの空きと使用量を報告します。
findディレクトリツリーを歩いて一致したものを印字します。大きなファイル、空のフォルダ、残骸を探すのに使います。
dumpsys diskstatsパーティションごとの空き容量、ディスク書き込み遅延の実測、そしてキャッシュされたアプリ別の使用量内訳。
rm端末上のファイル、またはディレクトリツリーを削除します。

Web ADB ツール群のパーサを書きながら、AOSP・toybox・カーネルのソースに突き合わせて確認しています。バージョンやメーカーで本当に挙動が変わるところは、世界の半分の端末で間違いになる数値を出す代わりに、そう書いてあります。

よくある質問

adb shell のコマンドはどう実行しますか?

端末で開発者向けオプションと USB デバッグを有効にし、ケーブルを繋いだうえで、platform-tools を入れた機械から adb shell <コマンド> を実行します。adb shell だけを実行すれば対話プロンプトが出て、接頭辞なしで打てます。スクリーンショットのようにバイナリを出力するコマンドでは adb shell ではなく adb exec-out を使ってください。素のシェルサービスは端末を割り当て、それが改行のバイトを書き換えてデータを壊します。

adb shell のコマンドに root は必要ですか?

このリファレンスにあるものには不要です。すべて shell ユーザーとして動き、自分の Android ユーザー向けのパッケージ管理、ほとんどの dumpsys サービスの読み取り、設定プロバイダへの書き込み、入力の注入、共有ストレージの読み取りができます。root が必要なのはこのリファレンスがあえて避けていること、つまり他のアプリのプライベートデータの読み取り(debuggable なビルドに対する run-as を除く)、システムパーティションへの書き込み、/data/anr の直接読み取りです。

自分の端末では出力が違って見えるのはなぜ?

Android のバージョンか、メーカーのどちらかです。一部のフラグやフィールドは特定のリリースから入ったもので、それはコマンドごとに注記しています。残りはメーカーによる改変で、いちばん影響が大きいのは dumpsys です。ダンプはデバッグ出力で、そのテキストはサービスの作者が最後に印字した内容そのもの、しかもメーカーはそれを変えて自分の変更をバックポートします。フィールドは位置ではなく名前で読み、見慣れない形は失敗ではなく差分として扱ってください。

端末ではなくブラウザから実行できますか?

多くのコマンドは可能です。このサイトの Web ADB ツール群は、Chromium 系のデスクトップブラウザから WebUSB で端末と話し、SDK のインストールも不要、どこにもアップロードしません。各ページは、該当するツールがあればそこへリンクしています。知っておく価値のある制限が 2 つあります。ADB インターフェイスを保持できるプログラムは同時に 1 つだけなので、デスクトップの adb server は先に止める必要があります。そして adb forward と adb reverse はブラウザでは一切動きません。

打つより押したい場合は、Web ADB Toolkit がこの種のコマンドをブラウザから USB 経由で実行します。あるいは全コマンドを見る。