-
Notifications
You must be signed in to change notification settings - Fork 1.7k
Description
Context
- issue closed due to lack of varargs support: Add built in printf function #614
- potentially somewhat maybe obsoleted by dlopen(), random, I/O, eval, and co-expressions (co-routines) #1843
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.