json_xs lints JSON, pretty-prints it, and can rewrite it on the fly with a short Perl expression. That last trick saves you writing a whole script for a one-off fix. The examples target the Debian or Ubuntu package libjson-xs-perl. On this machine that is version 4.040-0ubuntu0.24.04.1, providing JSON::XS 4.04.
Allow about ten minutes. You need a shell, a readable input file, and permission to write the output directory. No example needs elevated privileges. Do not use this utility on an untrusted Storable, YAML, Perl or other serialised file merely to inspect it: those formats can carry behaviour or parser risks that ordinary JSON does not.
Confirm which executable will run and record the package version. These are read-only checks:
$ command -v json_xs
/usr/bin/json_xs
$ dpkg-query -W -f='${Package} ${Version}\n' libjson-xs-perl
libjson-xs-perl 4.040-0ubuntu0.24.04.1
The command accepts input on standard input. Its default input format is json and its default output format is json-pretty. That default is useful at a terminal, but it can make a noisy diff if a script was expecting compact one-line JSON.
Checkpoint: if command -v finds nothing, stop and install the package through your normal system-management process. Do not copy a different json_xs into a project directory and assume it has the same format support.
Use -t none when the question is only whether the input parses. It reads the file and writes nothing:
$ json_xs -t none < data.json
$ printf 'exit status: %s\n' "$?"
exit status: 0
A successful exit status means the installed parser accepted the input. It does not check your application's schema, required keys or business rules. A malformed file produces an error and a non-zero status. For example:
$ printf '%s\n' '{"name":"Ada",}' | json_xs -t none
malformed JSON string, ...
$ printf 'exit status: %s\n' "$?"
exit status: 255
The exact diagnostic includes an offset and can vary slightly. Treat the status, rather than a particular wording, as the scriptable result. Keep the original file untouched while investigating a failure.
Pipe valid JSON to the default output, or state the output format explicitly. Write to a new name first so a failed conversion cannot truncate the source:
$ json_xs -t json-pretty < data.json > data.pretty.json
$ test -s data.pretty.json && echo 'pretty output written'
pretty output written
$ json_xs -t none < data.pretty.json
$ printf 'valid pretty JSON: %s\n' "$?"
valid pretty JSON: 0
The pretty printer may reorder object keys because JSON objects are unordered. Do not use the visual order as evidence that data changed. If a consumer requires compact UTF-8 JSON, use -t json or -t json-utf-8 instead:
$ json_xs -t json < data.json > data.compact.json
$ wc -l data.compact.json
1 data.compact.json
The shell redirection operator creates or truncates its destination before json_xs starts. For a replacement, use a temporary file and move it only after both conversion and validation succeed:
$ json_xs -t json-pretty < data.json > data.pretty.json.tmp
$ json_xs -t none < data.pretty.json.tmp
$ mv -- data.pretty.json.tmp data.pretty.json
If the conversion fails, remove the temporary file after checking that it is the one you created. The original remains in place. The mv is the state-changing step; it normally needs no root access when both files are in your directory.
-e evaluates Perl after reading the input and before writing it. The parsed value is in $_, and whatever remains there is written using the selected output format. This makes small, reviewed transformations practical without writing a separate script.
For example, sort a numeric array while retaining the rest of the object:
$ printf '%s\n' '{"name":"Ada","items":[3,1,2]}' \
| json_xs -e '$_->{"items"} = [sort {$a <=> $b} @{$_->{"items"}}]'
{
"items" : [
1,
2,
3
],
"name" : "Ada"
}
Keep the expression single-quoted so the shell does not expand Perl variables such as $_, $a or $b. The expression is code, not a data value. Review it before running it, especially when it comes from a variable or another person.
To extract one value, assign the value to $_ and select a simple output format. This example prints a string without attempting to add JSON quoting:
$ printf '%s\n' '{"name":"Ada","items":[3,1,2]}' \
| json_xs -e '$_ = $_->{"name"}' -t string
Ada
Validate the input before a transformation when the file matters. If the expression assumes a key or array exists, a valid JSON document can still fail because it does not have the shape your expression expects.
The utility can read and write formats supported by the installed modules. The manpage lists cbor, storable, storable-file, bencode, clzf, yaml, dump, dumper, string and none, alongside JSON encodings. Some require optional Perl modules, so check availability on the machine that will run the command.
For example, a Storable file can be converted to YAML if the required support is installed:
$ json_xs -f storable-file -t yaml < data.storable > data.yaml
Security warning: do not confuse storable with storable-file. The manpage describes them as two incompatible Storable formats. Treat both as serialised Perl data, not as harmless text. Never process an untrusted file with -f eval, which evaluates Perl input, and do not use conversion as a reason to grant a file extra permissions.
If the command reports malformed JSON, inspect the named offset and check for a trailing comma, an unclosed quote, or a shell command that supplied an empty string. Re-run with a small, known-good input before changing a larger file:
$ printf '%s\n' '{"ok":true}' | json_xs -t none
$ printf 'status: %s\n' "$?"
status: 0
If output is unexpectedly binary or unreadable, check -t first. Formats such as CBOR and Storable are not JSON text. If an optional format is unavailable, keep the source and read the error before installing anything. A missing module is not fixed by adding sudo to the same command.
If a replacement output is wrong, restore the previous destination from the backup you made, or move the untouched original back into place. Avoid rm until you have verified the new file; deleting the only copy is irreversible.
json_xs -t none accepts the input and returns status 0.