Skip to content

RFE: single value printf builtin #3411

@benaryorg

Description

@benaryorg

Context

Reason

I use jq a lot.
For me it has become what awk has been for others in that I can go through a text file, grab some values out of each line and do some math on them.
Of course also when dealing with JSON.
As a side note, the Ansible module is also a great addition for Ansible users for complex data processing (mostly when having to do an operation on two dicts like complex lookups).

However the one thing that stood out through all of it was the lack of formatting.
The @ formatting filters are hands down awesome, but often even string interpolation is enough.
Every time I need to format something in a more nuanced way though I run into this issue and in some instances makes jq really hard to work with.
Padding numbers, doing rounding, adding sign prefixes, radix conversion, or even just aligning some text, it's all very difficult.
And while those problems can be solved within jq with a sizeable amount of code, that code is big and hard to maintain, especially out-of-tree.

With the lack of varargs I'd like to propose a single-value format filter that allows me to run .foo | format("% .2f") and go on with my day.
It can be used in string interpolation as-is, doesn't need any syntax additions.
The variadic versions of single-value formatting of printf (such as (%.*f, 1, 1.34) being 1.3) can be used via string interpolation a la "%\(.length)s" as $format | .value | format($format).

Implementation

Ideally implementing the full spectrum of printf(3) would be nice, however the padding and number formatting are probably the most pressing, while %x and friends would be extremely nice to have when generating shell commands (think of `@sh "chmod (.mode | format("%05o")) (.file)") for instance.
Delegating the actual format down to printf(3) would also be possible, with the caveat of jq having to trust user format strings to be correct, which – itself being a reasonable assumption – would also open jq scripts up to issues when they in turn pass unsanitized input through.
In hopes of it being common knowledge not to let an untrusted user (in this case the input which the script passes to jq and jq to printf) control the format string, this shouldn't be too bad.

Alternatives

Module implementations of printf are technically possible, but difficult (I just opened a bug with that one, which gave me the final push to opening an issue here).

With varargs support it could actually be implemented.

With string interpolation existing one could have special syntax for formatting in there, such as (making this up of course): \{"%.3f" .my_value}.

With formatting filters, which aren't limited to string values (compare @json) one could potentially implement something like: 3.1415 | @printf "the truncated value: \({format: "%+3.2f", value: .})"

The mentioned PR adding dlopen and similar features would technically allow loading printf from some form of libc, however this wouldn't work for Windows I imagine (while technically Not My Problem™, it would be nice to avoid that) and would probably require some path guessery.
I'm unsure about the viability of that.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions