This release adds sixteen definitions (the registry holds 280 commands through 758 definitions, from 270 and 742), makes an option either change the answer or be refused before anything is read, keeps the headings of a csv read as data as written, and fixes readers that returned JSON different from their input: YAML, JSON Lines, LTSV, local timestamps, folded lines and floats too small to hold.
Added
rsync --stats(rsync/stats): the transfer counts rsync prints at the end of a run, with the summary lines that follow them, as one object of typed numbers. The counts by kind that rsync prints in parentheses are read as an object of their own, and a kind it leaves out is null rather than zero.-v,-i,--progressand two or more-hoptions print something else and are refused.7z l -slt -ba(7z/list-technical-bare): the entry blocks 7-Zip prints with-ba, which leaves out the banner, the scan line, the archive name and the archive's own properties. An entry is the same object7z/list-technicalgives it; what differs is the whole, which is the array of them rather than an object holding the archive beside them.openssl x509 -noout -text(openssl/x509-text): the version, the serial, the signature algorithm, the issuer, the subject, the two dates, the kind of key and its size, and one record per X509v3 extension with its critical mark and its value as printed. The key material and the signature are hexadecimal folded over a dozen lines or more and are not read;input.ignorenames those lines, so--explainreports how many were left out.tesseract IMAGE stdout tsv(tesseract/tsv): one row per page, block, paragraph, line and word, with the box each occupies and, for a word, its confidence. A row that is not a word prints -1 for the confidence, which is tesseract's own value and stays the number it printed.hocr,alto,pdfand the plain text tesseract writes when no configuration is named are other formats and are refused.- Seven definitions for time zones, the SSH client and the desktop:
zdump(zdump/current) andzdump -v/-V(zdump/verbose, which keeps the lines where gmtime or localtime failed, with the seconds they failed on),ssh -G HOST(ssh/config-dump, a list of name and value, so a keyword given more than once such asidentityfileorlocalforwardkeeps every value),xwininfo(xwininfo/stats),usb-devices(usb-devices/linux, one object per device with its interfaces and their endpoints),glxinfo -B(glxinfo/brief) andeglinfo -B(eglinfo/brief, one record per platform and per device, holding the errors a platform printed). - Five definitions:
lscpu -p(lscpu/parsable, the columns named by the header comment, so any-p=LISTis read, and a row whose cache IDs lscpu left out is refused rather than shifted),gcc -print-search-dirs(gcc/print-search-dirs, also underg++, with the program and library paths as arrays),apt-cache rdepends(apt-cache/rdepends, marking an alternative and the other packages that satisfy the same dependency),pw-cli ls(pw-cli/list-objects, one record per PipeWire object with its properties), andxprop -root/xprop -id(xprop/default, one record per property, with the lines printed under it kept). The registry holds 280 commands through 758 definitions. - A server-side group in the cookbook: inspecting an uploaded PDF with
pdfinfo, an archive with7z l -slt, a certificate withopenssl x509, an upload's type withfile -i, and recording what a backup run moved withrsync --stats, closing with thejz runexit-status contract and what converting the output does not do. The five commands run for real in the end-to-end suite on Linux, over paths holding a space and shell metacharacters, with their failure cases. group_separatoron an int or a float field: the one character a format writes between groups of three digits. It is removed only where the digits are grouped by it, so a value of another shape is an error rather than a number made by dropping characters. It is for a format that decides the character itself; a count printed with the separator of the user's locale still stays the string it was printed as.
Changed
- An option either changes the answer or is refused with exit 2 before anything is read or run.
--raw,--assume-yearand--assume-zoneare now refused for a data format (--formator a data file's extension), which is read without a definition's field rules and so could change nothing, and--assume-yearand--assume-zoneare refused when no variant of the named parser, or the--define, prints a timestamp they could complete (jz run --assume-year now df), the way a key to--extractnone of them has already was.--assume-yearand--assume-zonebeside--raware refused as--typebeside it is, since--rawleaves a timestamp as the text it was cut as. When the definition is found from the text, an option it has no use for still passes, since which definition reads the input is not known until it has been read. - The header line of a csv or tsv read as data (
--format csv, a.csvfile,jz new k:=@x.csv,--stream) is now the keys as written:名前,In Stockand%CPUstay as they are, where they becamecolumn,in_stockandcpu_percent. An empty heading is stillcolumnand a repeated onea_2.--parser csv, which reads with a definition, normalises the headings as before. jz list df/gnuandjz list --schema df/gnutake the name--explainandjz listprint for a definition. A path such as/usr/bin/dfis still read as the program it names.- An ini section heading with no name (
[]) is an error. It merged into the keys written before the first heading, which go under the empty name.
Fixed
apt-cache/dependsrefused the line of a relationship ORed with the next one (|PreDepends: coreutils-from-uutils), sojz run apt-cache depends coreutilswas exit 3. The mark is now read intoalternative, which is true for such a relationship and false for the others.apt-cache/dependsclaimed the output ofapt-cache rdepends -o APT::Cache::ShowDependencyType=true, then failed on itsReverse Depends:line with exit 3. It now leaves that output toapt-cache/rdepends.gpg/list-keysrefused a user ID whose validity gpg pads on both sides ([ full ]), which is how a key signed into full validity is listed, with exit 3.- A
timefield withlocation: localmoved a wall clock the zone skips to another hour. WithTZ=America/New_York,2025-03-09 02:30came out as2025-03-09T01:30:00-05:00, the same answer as for01:30, becausetime.ParseInLocationnormalises the hour a change to summer time skips. The value is now refused with exit 3. input.foldjoined a continuation onto a blank line above it, soa, an empty line and an indentedbgave a record" b"with a space the text does not hold. A blank line is now nothing to join onto, in the whole reading and in--streamalike, and the continuation is an error naming its line.- A
floatfield, and--type COLUMN=float, wrote0for a value too small for a 64-bit float (1e-400), while one too large was refused. Both are now refused with exit 3. - The error for a
treeline that skips a level gave the wrong levels:afollowed by a line indented twice said "indented 1 levels below a line at level 1". It now says the line is at level 2 under a line at level 0, and a first line that is indented says there is no line above it. jz list dffdid not suggestdf, althoughjz run dffand--parser dffdo.jz listnow gives the same suggestion.- YAML: the value of an explicit key written on the line of its ":" was read as one string when it opened a collection there.
? afollowed by: - xand an indented- ygave{"a":"- x - y"}with exit 0; it is now the list["x","y"], and: b: 1is a mapping. - YAML: a sequence item written on the line of its key,
a: - b, was read as the string"- b". The same happened with- 1inside a flow sequence and with? bused where a value belongs. YAML does not allow a plain scalar to start with an indicator and a space, and other readers refuse the line; jz now refuses it with exit 3 and says to start the items on the next line. - YAML: a comment did not end a plain scalar written over several lines.
a: x # notefollowed by an indentedygave"x y", keeping the text after the comment; the indented line is now refused as unexpected indentation. - YAML: a literal or folded scalar at the end of a text without a final line break gained one.
a: |overxwith no newline after it gave"x\n"; the break a scalar keeps is the one its last line has, so it is now"x". - JSON Lines, LTSV and
jz new --eachskipped any line of Unicode white space. A line holding only a no-break space, an ideographic space, a form feed or a vertical tab disappeared with exit 0, although none of these is white space in JSON, and--format jsonrefuses the same text. Only a line of JSON's white space, spaces, tabs and carriage returns, is blank in JSON Lines now; LTSV skips only an empty line and, as its reference says, refuses a line of spaces as a field without a label. jz run go test -bench=Parsewas exit 4.go/benchrequired-benchor the literal-bench=., and an argument written with=is matched by its name and the=, so any other value left it without a candidate.go/benchnow takes-bench=and the two-dash spellings, andgo/testrefuses them.FuzzReadJSONreported an escape naming half of a surrogate pair as valid JSON the reader refused, somake fuzzfailed on every run that reached that input.json.Validaccepts such a document andjson.Unmarshalthen hands back U+FFFD, which is a character the input may hold for itself, so refusing it is what keeps a conversion from changing what it was given. The fuzz target now names it among the refusals it expects, beside a key given twice, a document nested past the limit and text that is not UTF-8, and the input is in the seed corpus.file/posixrefused a listing whose path holds a space. The signature required a path of non-space characters, although the expression that reads the line has always taken[^:]+, sofile 'quarterly report.pdf'was exit 4.jz run file -i FILEcould land onfile/posix. file(1) reports a file it cannot open in the description and still exits 0, and that sentence satisfiedfile/posixbecause "No such file or directory" holds the word "directory", so a caller that asked for a MIME type was handed a record with atypeinstead.file/posixnow states that it does not read the output of-i,--mime,--mime-type,--mime-encoding,--extensionor--apple, and the answer is exit 4 with a diagnostic saying so.