问题
Is jq the best choice for pretty-printing arbitrary JSON?
cat my.json | jq .
pretty-prints the given JSON, but expands every field on a separate line.
But what if some of the fields are repetitive, such as a list of points? How can fields that match a pattern be formatted on a single line with --compact-output
?
For example, format "coords" and "list" fields below on a single line:
[
{
"field1": {
"a": "",
"b": ""
"list": [{ "name": "x", "score": 1, "rect": { "x": 156, "y": 245, "w": 35, "h": 45 }, ... ]
},
"field2": 2,
"coords": [{ "x": 100, "y": 400 },{ "x": 100, "y": 0 }]
},
....
]
The fields formatted with --compact-output
can wrap (no need to break these long lines).
回答1:
A constrained-width JSON pretty-printer could be written in jq itself. Here is a pretty-printer which illustrates how this could be done, though in its present incarnation, it is of limited usefulness.
ppArray(indent; incr; width) will emit a stream of JSON strings that
together are equivalent to the tostring
value of the input. For
robustness, it will always act as a pretty-printer, even if the
width restriction is violated.
If the input is an array, and if none of its elements (or recursively their elements) contains any large objects or long strings, then assuming the values of the parameters are reasonably chosen and that nesting is not too deep relative to these parameters, each emitted string should be no longer than "width".
# indent is the initial indentation level;
# incr is the number of spaces to add for one additional indentation level;
# width is the target maximum width.
#
def ppArray(indent; incr; width):
# The inner function produces an array of unindented strings.
def ppArray_(incr_; width_):
tostring as $tostring
| if $tostring|length <= (width_ - incr_) then [$tostring]
else reduce .[] as $i
([];
($i|tostring) as $is
| if length == 0 then [ $is ]
else .[-1] as $s
| ($s|length) as $n
| ($is|length) as $isl
| if $n + $isl <= (width_ - incr_)
then .[-1] = ($s + ", " + $is)
elif ($i|type) == "array"
then (.[-1]+=",") + [ $i | ppArray(0; incr_; width_ - incr_) ]
else (.[-1]+=",") + [ $is ]
end
end )
end;
(" " * indent) as $indentation
| if type == "array"
then ppArray_(incr; width - indent)
| $indentation + "[",
(.[] | ($indentation + " " + . )),
$indentation + "]"
else $indentation + tostring
end
;
Example:
[range(0;16)]
|
(ppArray(0; 2; 10)),
"::",
([{a:1}, {b:2}, {c:3}] | ppArray(0; 2; 10)),
"::",
(.[2]=[range(0;10)]) | ppArray(0; 2; 10)
Invocation:
jq -nrf pp.jq
Output:
[
0, 1, 2, 3,
4, 5, 6, 7,
8, 9, 10,
11, 12, 13,
14, 15
]
::
[
{"a":1},
{"b":2},
{"c":3}
]
::
[
0, 1,
[
0, 1, 2,
3, 4, 5,
6, 7, 8,
9
], 3, 4, 5,
6, 7, 8, 9,
10, 11, 12,
13, 14, 15
]
来源:https://stackoverflow.com/questions/42729731/use-jq-to-format-certain-fields-as-compact