Skip to main content

statblk

Gather disk and partition information for block devices and print it as a table or JSON.

Supports Linux and macOS.

Install

From PyPI:

pip install statblk

From a clone of this repository:

pip install .

Optional shell tab completion:

pip install 'statblk[completion]'

Requires Python 3.6+ and the multiCMD package (>= 1.55).

Quick start

statblk
statblk -j                    # JSON output (rows, header first)
statblk -J                    # JSON objects with numeric sizes/rates
statblk -o NAME,SIZE,MOUNTPOINT
statblk sda nvme              # filter rows matching sda or nvme
statblk 2                     # refresh every 2 seconds (watch mode)

Output columns

By default every column that has data is shown (a column that is empty for every row, such as LABEL when nothing is labelled, is hidden from the table):

Column Description
NAME Block device name (device-mapper devices show their /dev/mapper name, e.g. pve-root)
FSTYPE Filesystem type
SIZE Device or filesystem size
FSUSE% Filesystem space used (mounted entries); TIMEOUT for a mount that didn't answer (e.g. dead NFS server)
MOUNTPOINT Mount path
SMART SMART health: OK, STANDBY (spun-down drive, not woken), a failure such as FAILED!, TIMEOUT (smartctl stuck), or why it couldn't be read (NO SMARTCTL, DENIED, UNKNOWN). Blank for devices without SMART (loop, dm, md, zram, nbd)
LABEL Volume label
UUID Filesystem UUID
MODEL Drive model (from udev via lsblk, sysfs fallback)
SERIAL Drive serial (from udev via lsblk, sysfs fallback)
DISCARD TRIM / discard support
READ Read throughput: the device's since-boot average on the first query, the live rate on later watch refreshes (see READ / WRITE numbers)
WRITE Write throughput, same as READ

Use -o / --output to select columns (comma-separated) or -x / --exclude to omit columns. Columns named with -o are always shown, even when empty; --show_empty_columns keeps empty columns in the default view. JSON output (-j / -J) always includes every selected column.

READ / WRITE numbers

The first query (a single run, or the first refresh of watch mode) does not show a real-time rate. It shows each device's average since boot: bytes read (or written) since boot divided by the time the kernel spent on reads (or writes) since boot. Idle time is left out, so the number describes the device's work pattern, how fast it typically moves data when it is working, rather than what it is doing at this moment. For example:

  • a parity drive that mostly does long sequential syncs and scrubs shows a high READ (e.g. 150 MiB/s) even while it sits idle;
  • a snap or disk image written once at install time can show a very high WRITE (e.g. 1 GiB/s), because all of its writes happened in one short burst;
  • a device with no I/O since boot shows 0 B/s, so -A on a single run lists the devices that have done any I/O since boot.

The kernel counts the time of every request separately, so a device with many requests in flight at once (e.g. NVMe under load) reports more busy time than wall-clock time, and its average reads lower than its real transfer speed.

From the second watch refresh on, READ / WRITE are live rates: bytes transferred during the last interval divided by the wall-clock time of that interval. -J gives the same values as bytes per second.

Options

Output format

Flag Description
-j, --json Print JSON instead of a table (list of rows, header first; values as displayed)
-J, --json_objects Print JSON as a list of objects: SIZE/READ/WRITE in bytes and FSUSE% as an integer (null when unavailable)
-b, --bytes Print sizes and throughput as raw byte counts
-H, --si Use powers of 1000 (SI) instead of 1024 for sizes
-R, --full Do not truncate long values to terminal width
-o, --output Columns to include (default: all with data)
-x, --exclude Columns to omit
--show_empty_columns Keep columns that are empty for every row in the table

Filtering

Flag Description
filter_patterns … Show rows matching any pattern (regex)
-D, --match_devname_only Apply patterns to device names only (kernel name or /dev/mapper name)
-v, --invert_match Invert pattern match (with no patterns, prints only the header)
-F, -fo, --formated_only Only entries with a filesystem type
-M, -mo, --mounted_only Only mounted devices
-B, -bo, --best_only Shortest mount point per device
-A, -ao, --active_only Only devices with read/write activity (since boot on the first query, during the last interval on later watch refreshes)
-P, --pseudo Include pseudo filesystems (tmpfs, nfs, cifs, …)
--show_zero_size_devices Include zero-size devices
--show_squashfs Include squashfs images on loop devices (snaps, AppImages), hidden by default

Runtime

Flag Description
-t, --timeout Time budget per refresh in seconds for lsblk, smartctl and statvfs (default: 2; fractions allowed)
-w, --watch SECONDS Repeat output every SECONDS (watch mode; fractions allowed, e.g. 0.5)
--check Health check: print only problem rows and exit 1, or print nothing and exit 0 (see Health check)
--max_use PCT FSUSE% at or above which --check reports a filesystem (default: 90)
--sudo Run external commands via sudo (needed for SMART on many systems). smartctl is also looked up in /usr/sbin, /sbin, /usr/local/sbin when it isn't on PATH
--debug Print suppressed exceptions to stderr
-V, --version Show version and exit

Watch mode

Prefer -w / --watch, which also takes fractions. A trailing integer positional still works the same as before (whole seconds only, so a pattern like 0.5 stays a filter):

statblk -w 5       # update every 5 seconds
statblk -w 0.5     # twice a second
statblk 5          # same (trailing integer)
statblk sda 3      # filter to sda, refresh every 3 seconds
statblk -w 3 sda   # same with explicit flag (flag wins if both are given)

Each table refresh starts with a watch(1)-style header, Every 2s on <hostname>: <date time>. On a terminal the screen is redrawn in place; when output is piped or redirected every refresh is kept, so the log reads top to bottom. With -j / -J, watch mode prints one compact JSON document per line (NDJSON) so a reader can parse each refresh as it arrives; single-run JSON stays indented.

The first table shows each device's since-boot READ / WRITE average and later refreshes show live rates (see READ / WRITE numbers). After the first refresh, --active_only is enabled automatically on Linux so only busy devices are shown, unless you gave filter patterns: devices you named stay on screen even while idle (not on macOS, where throughput isn't available; -A still forces it). Each refresh re-reads mounts, labels, UUIDs, sizes, and per-drive sysfs info such as model/serial, so hot-swapped drives show up correctly (throughput iterators stay live across refreshes). Press Ctrl-C to stop (exit status 130).

If a filter pattern looks like a number, append 0 so it is not treated as the refresh interval (or use -w and keep the number as a filter):

statblk nvme0 0    # match nvme0, single run (no watch)
statblk -w 0 nvme0 # same via flag

Health check

--check runs once and prints only the rows that need attention; when everything is healthy it prints nothing, so cron only mails on trouble. Exit status:

Exit Meaning
0 Healthy (nothing printed). A STANDBY drive counts as healthy: it is checked on the next run that finds it awake
1 Problem: FSUSE% at or above --max_use (default 90) or TIMEOUT (hung mount), or SMART reporting a failure — FAILED!, a vendor failure string, or TIMEOUT (smartctl stuck on the disk)
3 Unknown: no problem found, but SMART couldn't be read on a disk — NO SMARTCTL (install smartmontools), DENIED (run as root or with --sudo) or UNKNOWN (no verdict, e.g. a disk behind a RAID controller)

A problem beats an unknown, and both kinds of rows are listed. Exit 3 exists so that "not checked" never looks like "healthy" in a sweep. For a space-only check use -x SMART; to skip a device that has no SMART at all (an SD card, a USB stick) filter it out, e.g. statblk --check -D -v mmcblk. FSUSE% and SMART are always added to the shown columns so you can see why a row failed; excluding one with -x turns that check off. Filters (-M, -B, patterns) and JSON output (-j / -J) work as usual, but filters narrow what is checked: -M and patterns skip disks with no mount of their own (md/LVM/ZFS/Ceph members, extra btrfs pool devices), so cluster sweeps should run plain --check. --check can't be combined with watch mode.

statblk --check || mail -s "disk alert on $(hostname)" ops@example.com   # cron
statblk --check -x SMART --max_use 80                                    # space only
mssh 'nodes[1-64]' 'statblk --check'                                     # whole cluster via multiSSH3

Platform notes

Linux

Uses sysfs, /proc/self/mountinfo, lsblk, and optionally smartctl.

  • SMART requires smartctl (smartmontools). Use --sudo if permission is denied. It only runs against hardware-backed disks (not loop, dm, md, zram, nbd). smartctl runs with -n standby, so spun-down drives are not woken (not even by watch mode); they show STANDBY until they're next awake. This is verified for SATA drives on the kernel's libata driver; drives behind USB enclosures or some RAID/SAS controllers may still spin up, because smartctl's device-type probe goes through the bridge. On a hardware disk where SMART can't be read the column says why (NO SMARTCTL, DENIED, UNKNOWN); it is blank for virtual devices.
  • squashfs on loop devices (snap packages, AppImages) is hidden by default: these images are read-only and always 100% full. Use --show_squashfs to list them. Other loop devices, such as a mounted disk image, are always shown.
  • autofs trigger mounts are ignored (stat-ing them would trigger the automount); the real filesystem appears once mounted.
  • READ / WRITE come from /sys/class/block/*/stat (always 512-byte sector units): a since-boot average on the first query, live rates on later watch refreshes (see READ / WRITE numbers).

macOS

Uses diskutil and mount. Throughput columns are always zero (no per-device sysfs stats). APFS snapshot nodes such as the sealed system volume (disk3s1s1 on /) are listed.

Development

Install test deps:

pip install -r requirements-dev.txt

Run unit tests (default; live excluded) and embedded doctests:

pytest
python -m doctest statblk.py -v
python statblk.py --doctest

Optional live checks:

pytest -m live          # soft smoke on this host
pytest -m live_strict   # compare FSUSE% and names to df/lsblk

License

GPLv3+ — Yufei Pan (pan@zopyr.us)

Project home: github.com/yufei-pan/statblk

Metadata

Release files for statblk 1.56

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for statblk 1.56
File Size Uploaded Provenance Actions
statblk-1.56.tar.gz 70.5 kB Without provenance Details for statblk-1.56.tar.gz

Built distribution (wheel)

Table of built distributions (wheels) for statblk 1.56
File Interpreter ABI Platform Actions
statblk-1.56-py3-none-any.whl Python 3 none any Details for statblk-1.56-py3-none-any.whl

Total release size: 125.6 kB

Release files / statblk-1.56.tar.gz

Download URL statblk-1.56.tar.gz
Size 70.5 kB
Tags Source
SHA-256 checksum
How to use checksums
3917958d895d499b529c027d33d062597e9faf4bde71d44c5b3c633e885065cd
BLAKE2b-256 checksum
How to use checksums
7a041dcaed835c91f055a3b48d93534c99bc81a9a53acf6cb536611a5ac824c8
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via uv/0.13.5 {"installer":{"name":"uv","version":"0.13.5","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Debian GNU/Linux","version":"13","id":"trixie","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}

Release files / statblk-1.56-py3-none-any.whl

Download URL statblk-1.56-py3-none-any.whl
Size 55.1 kB
Tags Python 3
SHA-256 checksum
How to use checksums
b714cab2eb3f39c100ce92dee0d4df8f281fc438ea5db25a55a876547c63b7cc
BLAKE2b-256 checksum
How to use checksums
ec9c4ed9e76e6b47036c20cacb007960c38e67119b7571b133148401ea5ec86c
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via uv/0.13.5 {"installer":{"name":"uv","version":"0.13.5","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Debian GNU/Linux","version":"13","id":"trixie","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}

Security for statblk 1.56

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

No provenance found

None of the files in this release were uploaded with provenance metadata.

A note on package security

PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.

To learn more about protecting yourself from malicious actors, visit our package security documentation.

Release history Release notifications | RSS feed

This release

1.56 This release

2 release files No provenance

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page