df コマンド(がやることの一部)の python な alternative

検索で調べようとすると結構めんどくてなこれ。検索ワードを苦心しないと DataFrame ばっかヒットする。そっちじゃのーて、れがしーな「df コマンド」ん話ばね。

Windows ではエクスプローラでディスク使用状態はわかる。Unix で伝統的なものが、ほぼ全ての Unix において組み込みコマンドとして提供される「df」で。Unix もどきであるところの MSYS にも含まれる:

 1 [me@host: ~]$ df
 2 Filesystem           1K-blocks      Used Available Use% Mounted on
 3 C:\Users\hhsprings\AppData\Local\Temp
 4                      975853100 213647480 762205620  22% /tmp
 5 C:\MinGW\msys\1.0    975853100 213647480 762205620  22% /usr
 6 C:\MinGW\msys\1.0    975853100 213647480 762205620  22% /
 7 c:\MinGW             975853100 213647480 762205620  22% /mingw
 8 c:                   975853100 213647480 762205620  22% /c
 9 df: `/d': no medium
10 e:                   117218300  74057388  43160912  64% /e
11 f:                   4883637932 564701368 4318936564  12% /f
12 g:                   234428412  58487564 175940848  25% /g
13 h:                    60604384  48458848  12145536  80% /h
14 [me@host: ~]$ df -h
15 Filesystem            Size  Used Avail Use% Mounted on
16 C:\Users\hhsprings\AppData\Local\Temp
17                       931G  204G  727G  22% /tmp
18 C:\MinGW\msys\1.0     931G  204G  727G  22% /usr
19 C:\MinGW\msys\1.0     931G  204G  727G  22% /
20 c:\MinGW              931G  204G  727G  22% /mingw
21 c:                    931G  204G  727G  22% /c
22 df: `/d': no medium
23 e:                    112G   71G   42G  64% /e
24 f:                    4.6T  539G  4.1T  12% /f
25 g:                    224G   56G  168G  25% /g
26 h:                     58G   47G   12G  80% /h
27 [me@host: ~]$ df -B M
28 Filesystem           1M-blocks      Used Available Use% Mounted on
29 C:\Users\hhsprings\AppData\Local\Temp
30                        952982M   208642M   744341M  22% /tmp
31 C:\MinGW\msys\1.0      952982M   208642M   744341M  22% /usr
32 C:\MinGW\msys\1.0      952982M   208642M   744341M  22% /
33 c:\MinGW               952982M   208642M   744341M  22% /mingw
34 c:                     952982M   208642M   744341M  22% /c
35 df: `/d': no medium
36 e:                     114471M    72322M    42150M  64% /e
37 f:                    4769178M   551467M  4217712M  12% /f
38 g:                     228934M    57117M   171818M  25% /g
39 h:                      59184M    47331M    11854M  80% /h

まぁ日常的にはそのエクスプローラで見るか、ワタシの場合はこのように MSYS の df で事足りる、てわけなんだけれども。

まれに、長時間このディスク使用量を監視していたいことがあってね。今の場合は絶賛大量ファイル圧縮中、なんだけど、その効果・推移を観察していたい、てやつ。この場合、エクスプローラでは物足りなくて、df コマンドだと今ひとつ融通がきかない。たとえば「3.23 GB」みたいなのが読みやすくていいんだがなぁ、てニーズには df はこたえてくんないし、そもそもグラフにでもしたいなら…。

「ゆえに python で」、て話。「ワタシさえ良ければいい」の中でも最も極端な考え方を採る場合、ワタシは MSYS を持っているわけで、なので MSYS 付属の df を subprocess で呼び出して使うんでもいい、んだけれど、一応 python だけで出来るやり方で。結局は「ワタシさえ良ければいい」であることには変わりはないんだけどね。

python 3.3+ では簡単で:

1 Python 3.5.4 (v3.5.4:3f56838, Aug  8 2017, 02:17:05) [MSC v.1900 64 bit (AMD64)] on win32
2 Type "help", "copyright", "credits" or "license" for more information.
3 >>> import shutil
4 >>> shutil.disk_usage("h:/")
5 usage(total=62058889216, used=49641783296, free=12417105920)

一応ワタシ個人の事情により一応 python 2.7 の話もしとくと、「3.3+」と言った通り 2.7 の shutil には disk_usage は含まれないので、ほかの手段を考える必要がある。

Windows のことを考えなくていいなら実は 2.7 だろうがなんだろうが「os.statvfs」がいつでも使えるが、Windows なのでね、ワタシが日常使っているのは。「標準添付モジュールで出来る範囲で」の(ctypes で Win32 API を直接叩く以外の)やり方は見つけてない。結局は psutil が救世主よね:

1 Python 2.7.18 (v2.7.18:8d21aa21f2, Apr 20 2020, 13:25:05) [MSC v.1500 64 bit (AMD64)] on win32
2 Type "help", "copyright", "credits" or "license" for more information.
3 >>> import psutil
4 >>> psutil.disk_usage("h:/")
5 sdiskusage(total=62058889216L, used=49693163520L, free=12365725696L, percent=80.1)
6 >>> res = psutil.disk_usage("h:/")
7 >>> print("{:.2f} GB".format(res.free / (1024.**3)))
8 11.51 GB

グラフ…はまぁやりたくなったらそのうち。matplotlib の animation とか、tkinter を使うとかで、それなりのものは作れるけど、今日のワタシには不要なので。今日のワタシにとっては「11.51 GB」で存分に「よしよし」なの。今日のワタシに必要なコマンドライン:

1 [me@host: ~]$ while true ; do py -3 -c 'import psutil ; r = psutil.disk_usage("h:/") ; print("{:.2f} GB\t{:.1f} %".format(r.free/(1024.**3), 100 - r.percent))' ; sleep 90 ; done
2 11.78 GB        20.4 %
3 11.78 GB        20.4 %
4 11.77 GB        20.4 %

これでファイル圧縮が順調に進んでいることを眺めて喜ぶことができる。

見出しが「(がやることの一部)」としている理由であるところの「今日のワタシには不要」は、ちょっとあとで真剣に考えてもいいかと思ってる。df はマウントポイントを列挙して全部出力するよね。今日のワタシPCの場合は、「c:/、d:/~h:/」。今日ここまでやったのは、「h:/ の」と特定してその情報を取得することしか出来てない。ま、やりたくなったら、ね。(実はこの目的が主食だったら、「今日のワタシ」には df を subprocess で呼び出して使う方が手っ取り早かったりする。)


2021-03-17追記:
グラフ化について、「265-nize」の追記参照。


2021-03-26追記:
ついでというか。

psutil が如何に救世主なのか、てのは、以前「コンソールウィンドウのタイトルをセットする(Windows)」なんてので書いたことがあった。「コンソールウィンドウのタイトルをセットする」動機というのはそもそも、「ワタシ、今何を? どこで?」を識別したい、てことである。異論はないよね? そして「やっぱ Windows なのだよなおぬしは」てこと。

「ワタシ、今何を? どこで?」を簡単に調べる術はこれは Windows では超絶にめんどい。「コンソールウィンドウのタイトルをセットする(Windows)」に書いた通りの理由で、エンドユーザが日常使う道具も相当欠落している。Windows しか知らないならそんなに怒りを覚えないところだったんだけれど、Unix だとこれが恐ろしく簡単だから弱るわけよね。基本的にはコマンドラインツールとしては ps か top あたりに頼れば、ほとんど日常は足りる。

Windows XP あたりから少しずつマシになっているとはいえ、それでもなお「tasklist.exe」はあまりにも役不足、タスクマネージャ・パフォーマンスモニタでは欲しい情報が足りてない。SysInternals のプロセスエクスプローラは非常に優秀で使い勝手がいいものの、それでもまだ欲しいものが少し欠けている。

一番毎日欲しいのに手に入らないのが、「現在動作中のコマンドライン」なんだけど、これは Unix なら ps で冗長オプション MAX にするなりで簡単に見ることが出来る。top でも同じく。これと同じことを、MSYS に付属の ps が出来ないのが…、まぁ本当のところは一番の癇癪の種なのかも(msys2は未確認)。

「コンソール」と ffmpeg みたいなのが実は非常に相性悪くて、打ち込んだ複雑な ffmpeg コマンドラインはその冗長過ぎる ffmpeg 出力によりすぐに可視ビューポート外となり、つまり「スクロールバーを操作しないと打ち込んだコマンドラインを確認出来ない」ということになるのだが、まぁやってみればわかる通り、現実的にはスクロールバーの操作は不可能である。ので、まぁすぐに「オレ、何やってるんだっけ」がわからなくなる。Windows + MSYS 環境でもう一つ致命傷なのが、「Ctrl-Z」でジョブをサスペンド出来ないことで、Unix に似てるからこそイライラの種になる。それが出来さえすれば、いったんサスペンドして何を打ち込んだのか確認ののち再開なんてことも出来るんだけどね。

そういうわけで、こういうものを必要とするわけだ:

pscmdlines.py
 1 #! py -3
 2 # -*- coding: utf-8 -*-
 3 from __future__ import print_function
 4 from __future__ import unicode_literals
 5 
 6 import os
 7 import sys
 8 import psutil
 9 
10 
11 if __name__ == '__main__':
12     import argparse
13     ap = argparse.ArgumentParser()
14     ap.add_argument("--cmdbasename", action="store_true")
15     ap.add_argument("--cwdbasename", action="store_true")
16     args = ap.parse_args()
17     for p in psutil.process_iter():
18         cmdl, pwd = [], ""
19         try:
20             cmdl = p.cmdline()
21         except Exception as e:
22             print(e, file=sys.stderr)
23         try:
24             pwd = p.cwd()
25         except Exception as e:
26             print(e, file=sys.stderr)
27         if not cmdl:
28             continue
29         if pwd and args.cwdbasename:
30             pwd = os.path.basename(pwd)
31         if args.cmdbasename:
32             cmdl[0] = os.path.basename(cmdl[0])
33         print(pwd, cmdl)

「自分で見繕わねばならぬ」というだけでそれなりには地獄とも言えるけれど、だけれども psutil なしでこれと同じことをやろうとするとどうなるか知っていると、まさにこれは「天国」。


2021-03-26 18:00追記:
「Windows だと超絶にめんどい」がうまく伝わらんかなぁと思ってたんだが、やっぱ psutil 自身のソースコードがわかりやすかなと。たとえば _psutil_linux.c_psutil_windows.c の行数を比較するだけでも雰囲気がわかるんではないかと。


2021-03-27追記:
psutil に基づくglancesについて触れておいた。


2021-04-03追記:
「df はマウントポイントを列挙して全部出力する」について、psutil に「disk_partitions」があった:

 1 >>> import psutil
 2 >>> dps = psutil.disk_partitions()
 3 >>> dps[0]
 4 sdiskpart(device='C:\\', mountpoint='C:\\', fstype='NTFS', opts='rw,fixed', maxfile=255, maxpath=26
 5 >>> dps[0].mountpoint
 6 'C:\\'
 7 >>> [p.mountpoint for p in dps]
 8 ['C:\\', 'D:\\', 'E:\\', 'F:\\', 'G:\\', 'H:\\']
 9 >>> [psutil.disk_usage(p.mountpoint) for p in dps]
10 Traceback (most recent call last):
11   File "<stdin>", line 1, in <module>
12   File "<stdin>", line 1, in <listcomp>
13   File "C:\Program Files\Python39\lib\site-packages\psutil\__init__.py", line 1995, in disk_usage
14     return _psplatform.disk_usage(path)
15   File "C:\Program Files\Python39\lib\site-packages\psutil\_pswindows.py", line 265, in disk_usage
16     total, free = cext.disk_usage(path)
17 PermissionError: [WinError 21] デバイスの準備ができていません。: 'D'
18 >>> [psutil.disk_usage(p.mountpoint).free for p in dps if p.fstype]
19 [799600259072, 44196773888, 4567875444736, 180163428352, 22662057984]

てわけで、curses も使って(Windows の場合は windows-curses 必要):


2021-04-09追記:
「pythonの」と言っているのでいわゆるトピック違いではあるんだけれど、根底にあるのは「欲しいものが手元にない、何かいい手はないか」ということだけなので、一応触れておく。

別件でちょっと「Windows での一番の救世主は実は PowerShell」てことを言ったのだが、その流れで「powershell cmdlet unix command equivalent」という検索をしたら、まさに「unix df -ht in powershell」もヒットした。まぁそりゃそーだわな。ワタシんちでやればこんなね:

 1 Windows PowerShell
 2 Copyright (C) Microsoft Corporation. All rights reserved.
 3 
 4 新しいクロスプラットフォームの PowerShell をお試しください https://aka.ms/pscore6
 5 
 6 PS C:\Windows\Temp> Get-PSDrive
 7 
 8 Name           Used (GB)     Free (GB) Provider      Root                          CurrentLocation
 9 ----           ---------     --------- --------      ----                          ---------------
10 Alias                                  Alias
11 C                 195.57        735.07 FileSystem    C:\                              Windows\Temp
12 Cert                                   Certificate   \
13 D                                      FileSystem    D:\
14 E                  70.63         41.16 FileSystem    E:\
15 Env                                    Environment
16 F                 400.93       4256.47 FileSystem    F:\
17 Function                               Function
18 G                  55.78        167.79 FileSystem    G:\
19 H                  50.00          7.81 FileSystem    H:\
20 HKCU                                   Registry      HKEY_CURRENT_USER
21 HKLM                                   Registry      HKEY_LOCAL_MACHINE
22 Variable                               Variable
23 WSMan                                  WSMan
24 
25 
26 PS C:\Windows\Temp> help Get-PSDrive
27 
28 名前
29     Get-PSDrive
30 
31 構文
32     Get-PSDrive [[-Name] <string[]>]  [<CommonParameters>]
33 
34     Get-PSDrive [-LiteralName] <string[]>  [<CommonParameters>]
35 
36 
37 エイリアス
38     gdr
39 
40     ... (省略) ...
41 
42 
43 PS C:\Windows\Temp> gdr
44 
45 Name           Used (GB)     Free (GB) Provider      Root                          CurrentLocation
46 ----           ---------     --------- --------      ----                          ---------------
47 Alias                                  Alias
48 C                 195.57        735.07 FileSystem    C:\                              Windows\Temp
49 Cert                                   Certificate   \
50 D                                      FileSystem    D:\
51 E                  70.63         41.16 FileSystem    E:\
52 Env                                    Environment
53 F                 400.93       4256.47 FileSystem    F:\
54 Function                               Function
55 G                  55.78        167.79 FileSystem    G:\
56 H                  50.01          7.81 FileSystem    H:\
57 HKCU                                   Registry      HKEY_CURRENT_USER
58 HKLM                                   Registry      HKEY_LOCAL_MACHINE
59 Variable                               Variable
60 WSMan                                  WSMan

よくわからんものも出てる。レジストリのこれはなんなんだろうかね。まぁとにかく df に近いことは出来る、てことで。