Coverage

On this page

jz reads output formats, not commands. A command that changes its columns with an option prints two formats and needs two definitions, so “jz supports df” says less than it sounds like. This page says, for the commands asked about most, what each form of their output does when it reaches jz.

Three things can happen, and each of them is an answer:

what it means
readpiping the output in identifies it and converts it
nameduse jz --parser NAME or jz run; some formats also need --variant VARIANT
refusedjz does not read it, and the reason is below

“named” is not a shortcoming. A format whose text could be half a dozen other things is one jz declines to guess at, because the failure worth designing against is confident JSON from the wrong parser rather than exit 4.

Everything below but the Windows section, which names its own machines, was run on Ubuntu 26.04 (Linux 7.0) with LC_ALL=C: GNU coreutils 9.7 and uutils coreutils 0.8.0, procps-ng 4.0.4, util-linux 2.41.3, iproute2 6.19.0, systemd 259, sysstat 12.7, BIND dig 9.20.24, iputils, BusyBox 1.37.0. net-tools was not installed, so the netstat rows below were checked with BusyBox netstat, whose socket and routing tables the existing definitions read, and the interface table was written from the format strings net-tools prints it with rather than captured.

Storage and memory #

invocationdefinition
dfreaddf/gnu
df -kreaddf/gnu
df -a, df --totalreaddf/gnu
df -h, df -Hreaddf/gnu-human
df -m, df -B512, df --block-size=Nreaddf/gnu-blocks
df -Treaddf/gnu-type
df -T -mreaddf/gnu-blocks-type
df -ireaddf/gnu-inodes
df -ihreaddf/gnu-inodes-human
df -P, df -PTreaddf/portable, df/portable-type
df --output=...refusedthe columns are whatever the option named; jz --parser table --variant aligned reads it as a table
freereadfree/gnu
free -hreadfree/gnu-human
free -wreadfree/gnu-wide
free -h -wreadfree/gnu-wide-human
free -t, free -l, free -s N -c Nreadthe variant the other options chose
lsblkreadlsblk/linux
lsblk -breadlsblk/bytes
lsblk -freadlsblk/filesystems
lsblk -treadlsblk/topology
lsblk -mreadlsblk/permissions; in a container without the device nodes, owner, group and mode are null together
lsblk -Preadlsblk/pairs
lsblk -rreadlsblk/raw
lsblk -nnamedlsblk/no-headings; with no header the text is a tree drawing and some words
lsblk -Jrefusedit is JSON already
lsblk -o ...refusedthe columns are whatever the option named; --parser table reads it
mount, mount -l, mount -t TYPEreadmount/linux
/proc/mounts, /etc/mtabnamedjz --parser etc reads them as etc/fstab, which is their format
stat FILEreadstat/gnu
stat FILE FILEreadstat/gnu, one object per file
stat -freadstat/gnu-filesystem
stat -tnamedstat/gnu-terse; a row of numbers describes too many things
stat -c, stat --printfrefusedthe format is the one the option gave

A figure df rounds for a person (1.8T) stays a string. The output does not record the base the rounding used and the value is already rounded, so converting it would invent precision the command did not print; run df or df -B1 for exact numbers. Where df counts in blocks, the unit is in the heading and comes out beside the rows.

Processes #

invocationdefinition
psreadps/posix
ps -efreadps/unix
ps auxreadps/bsd
ps -elreadps/long
ps -eFreadps/full-format
ps -elyreadps/long-y
ps -eLfreadps/threads
ps axjf, ps -e --forestreadps/jobs, ps/posix
ps -eo ..., ps -o ...=refusedthe columns are whatever the option named; --parser table reads it
top -b -n1readtop/linux
pidstat, pidstat -d, -r, -wreadthe pidstat variants

Listings #

invocationdefinition
ls -lreadls/long
ls -la, -lh, -lt, -lS, -lnreadls/long
ls -l --full-timereadls/full-time
ls -l --time-style=long-isoreadls/long-iso
ls -lZreadls/long-context
ls -lRreadls/long-recursive
ls -log, ls -lgGreadls/long-no-owner-group
ls -lG, ls -lonamedls/long-no-group
ls -lgnamedls/long-no-owner
ls -linamedls/long-inode; ls -ls prints a number in the same place
ls, ls -1namedls/names; a list of lines is not evidence of anything
ls -F, ls -prefusedthe mark after a name is not part of the name and no rule can say which trailing character is one

ls -lG and ls -lg print the same text: one drops the group column and the other the owner, and nothing in the output says which name is left. Both are reached by naming the variant, and jz run ls -lG picks the right one from the arguments. Naming only the command reports both rather than choosing.

Network #

invocationdefinition
ip address, ip -4 address, ip -6 addressreadip/address
ip -br address, ip -o addressreadip/brief-address, ip/oneline-address
ip link, ip -d linkreadip/link
ip -br linkreadip/brief-link
ip -s link, ip -s -s linkreadip/stats-link, ip/stats-link-detail
ip route, ip -6 routereadip/route
ip neigh, ip rule, ip maddrreadthe matching ip variants
ip -j ...refusedit is JSON already
ip tunnel, ip netns, ip xfrmrefusedno definition; the subcommands are each their own format
ss, ss -a, ss -l, ss -x, ss -tuln, ss -preadss/linux
ss -e, ss -o, ss -m, ss -ireadss/linux, with what the option added under info
ss -t, ss -ua, ss -ulreadss/single-protocol
ss -u, ss -wreadss/connected
ss -sreadss/summary
ss -Hrefused-H removes the header, which is the line that says what the format is
netstat, -a, -t, -u, -x, -w, -l, -n, -ereadnetstat/all-sockets, netstat/internet, netstat/unix
netstat -r, netstat -rnreadnetstat/routing
netstat -e -rreadroute/linux, which is the table those columns are
netstat -ireadnetstat/interface
netstat -srefusedwhich counters appear, in which order and at which indent comes from the kernel and the net-tools build; there is no capture here to write it against
netstat on Windowsrefusedno definition; no vendor-published text sample was found to write one against, only screenshots
dig NAMEreaddig/bind
dig NAME A NAME MXreaddig/bind, one entry in replies per query
dig +nocmdreaddig/bind, with an empty query
dig +nsid, +dnssec, +tcp, +norecreaddig/bind
a query that reached no serverreaddig/bind, with an empty replies and the attempt under transport
dig axfrreaddig/axfr
dig +noall +answernameddig/answers; the same five columns are what a zone file holds
dig +shortrefusedthe output is the data of the records with nothing naming them
dig +tracerefusedthe delegation steps have no line that opens one, so nothing says where a step ends
ping -c N, -q, -D, -A, -s, -W, ping6readping/linux, ping/bsd
ping -frefusedflood output is a line of dots, not records
tracepathreadtracepath/linux
tracerouterefusedno definition

systemd #

invocationdefinition
systemctl, systemctl list-units, --all, --plain, --failedreadsystemctl/units
systemctl list-unit-filesreadsystemctl/unit-files
systemctl list-timersreadsystemctl/timers
systemctl list-socketsreadsystemctl/sockets
systemctl list-jobs, including with nothing queuedreadsystemctl/jobs
systemctl list-machinesreadsystemctl/machines
systemctl list-pathsreadsystemctl/paths
systemctl list-automountsreadsystemctl/automounts
systemctl list-dependencies --plainreadsystemctl/dependencies
systemctl status UNITreadsystemctl/status
systemctl show UNITreadsystemctl/show
systemctl shownamedsystemctl/show-properties; NAME=value is also what env prints
systemctl list-dependenciesrefusedwithout --plain a line carries a state marker and a drawing, and a line’s depth then depends on both
systemctl statusrefusedthe whole-system report is a different format with no definition
systemctl list-units --no-legendrefusedthe option removes the header, which is what says the format is this one
systemctl cat UNITrefusedit is the unit file; jz --parser ini reads that
journalctl -o short*readthe journalctl variants

Repeating reports #

invocationdefinition
vmstat, vmstat N M, vmstat -wreadvmstat/linux
vmstat -a, -d, -sreadvmstat/linux-active, -disk, -stats
vmstat -frefusedone line saying how many forks there have been
iostat, iostat N Mreadiostat/linux
iostat -x, -c, -d, -hreadiostat/extended, cpu, device, human
iostat -t and each of those with -treadthe -timestamped variant of each
mpstat, mpstat -Ireadmpstat/linux, mpstat/interrupts
sar -u, -r, -b, -n DEV, …readthe sar variants

Windows #

jz builds and runs on Windows, and that is a different thing from reading what Windows commands print. The rows below were checked against the real commands on the GitHub-hosted Windows Server 2022 and 2025 runners, English, with the console on code page 65001: the end-to-end suite runs each command there on every change and compares what jz reports with hostname, ver and PowerShell on the same machine, and a capture from each release is kept as a fixture beside the output published by the vendor.

invocationdefinition
ipconfig /allreadipconfig/all
ipconfigreadipconfig/windows
systeminfo, systeminfo /fo listreadsysteminfo/windows; /fo list prints the same lines, and jz run refuses it on the argument, since /fo also names the csv and table forms
systeminfo /fo csvnamedjz --parser csv --variant comma
ipconfig /displaydnsrefuseda different format; pinned as a refusal rather than read
netstat on Windowsrefusedno vendor-published text sample was found to write one against, only screenshots
net user, net localgroup, dir, route print, ver, tasklist, wmicrefusedno definition

Not checked, and not claimed: a Windows in another display language, whose labels the signatures do not describe, so its output is refused rather than read; a console code page other than UTF-8, where a name outside ASCII is not valid UTF-8 and the input is refused; and a desktop edition, which no runner provides.

A rounded figure with a separator and a unit (16,384 MB) stays a string here for the reason it does everywhere else: the text does not say which base it was rounded in. A label that holds a colon of its own (Virtual Memory: Max Size:) keeps what follows its first colon as the value, since a list of labels the definition has not seen cannot say which colon is the separator.

What is not read on purpose #

  • Output whose columns are chosen by an option (ps -eo, df --output, lsblk -o, stat -c). There is no format to describe: the caller already knows the columns, and jz --parser table --variant aligned reads an aligned table under whatever headings it has.
  • Output with the header removed (ss -H, systemctl --no-legend, lsblk -n by automatic detection). The header is what says which format the text is; without it jz would be guessing. Leave the option out when piping into jz, or name the parser.
  • Output that is already structured (ip -j, lsblk -J, --format=json anywhere). Converting JSON to JSON is not what this is for.
  • A single word or number (systemctl is-active, id -u). There is nothing to convert.

Compared with jc #

jc converts many of the same commands, so it is a second opinion on what a text holds. The comparison below was made against jc 1.25.7 (git 8290734, MIT licence). No jc code or fixture is copied into this repository: the fixtures here were captured or quoted independently, and jc is used as a tool to run against them.

scripts/compare_jc.py runs both over the same saved input and reports, per fixture, whether each produced JSON, how many records, and which words of the input reached a leaf value of each result. It needs jc installed (python3 -m pip install jc) and nothing else in this repository depends on it. It compares against the input rather than between the two documents on purpose: the two name and nest their keys differently, and normalising that away would also hide a value one of them dropped.

--refused turns the harness around and runs it over the fixtures a definition is written to refuse: text of a neighbouring format, a row cut short, a line the definition never looked at. The counts here are those of the run that was made, and the registry has grown since. There were 47 such fixtures with a jc parser to compare against. jz refused 46 of them, jc read 34. The one jz read is wc -lwcL output given to jz --parser wc --variant posix, where the fourth count and a file name beginning with a number are the same text and the arguments are the only thing that separates them; jz run wc -lwcL refuses it on the argument.

Over the 380 fixtures a definition was written to read, jz read all of them and jc refused 30. The refusals are a file system name containing a space (df), every ip address fixture, an ls -l of a directory with nothing in it, the headerless and raw forms of lsblk, most ss forms, pidstat, swapon, an empty zip listing, who with an ISO time, and the systeminfo excerpt.

Where both read a text, the differences worth knowing are these.

  • A rounded number. df -h prints 13G; jc reports 13958643712 and jz reports "13G". The command rounded the value and did not record what it rounded, so the exact figure is not in the text; two rows whose sizes both round to 13G come back from jc as the same number.
  • A value made of parts. dig’s ;; SERVER: 127.0.0.53#53(127.0.0.53) (UDP) is one string in jc and three keys in jz (server, server_name, protocol). Both carry the information.
  • A converted value. jz turns Use% 7% into 7, TIME 00:02:57 into 177 seconds and a timestamp with an offset into RFC 3339, so the original spelling is not in the output. jc keeps more of them as printed.
  • A legend read as data. systemctl list-units closes with a legend explaining LOAD, ACTIVE and SUB; jc returns those lines as units, jz names them in input.ignore and returns the one unit the listing had.
  • Several replies. dig a.com A b.com MX is two replies; jz reads both under one banner, jc reads both, and a text made of two whole dig runs pasted together is refused by jz because a run has one banner.

Formats jc reads that jz does not, and which stay out of scope for now: shell and string values (jwt, url, semver, path, timestamp, email_address), structured file formats that already have readers everywhere (xml, toml, plist, x509_*; jz reads yaml, json, csv and jsonl files as data, by extension), and a set of commands with no definition here yet (traceroute, iptables, iwconfig, dmidecode, mdadm, ntpq, find, finger, rpm -qi, tune2fs, ufw, zpool status, zpool iostat, net user, net localgroup, dir). The string and file formats are a different job from reading what a command printed: a JWT or a URL is not a command’s output, and an XML or TOML reader is the tool for a file that already has a grammar. Adding them would make the count of formats larger without making the thing jz is for any better, which is why they are listed here rather than written.

jz reads around ninety commands jc has no parser for, among them the systemd-* tools, most of util-linux (lsfd, lsns, lsmem, lslocks, lsipc, lsirq, lsclocks, uuidparse, namei, prlimit), the lsb_release, loginctl, localectl, hostnamectl and resolvectl family, package and language tooling (apt-cache, npm, cargo, go, rustup, uv, mise, snap, docker), journalctl, sar, sensors, smartctl, pactl, nstat, tc, bridge and the table/csv/kv/ini shape readers.