jf is a jo alternative, A small utility to safely format and print JSON objects in the commandline.
However, unlike jo
, where you build the JSON object by nesting jo
outputs,
jf
works similar to printf
, i.e. it expects the template in YAML format as the first argument, and then the values for the placeholders as subsequent arguments.
For example:
jf "{one: %s, two: %q, three: [%(four)s, %(five=5)q]}" 1 2 four=4
# {"one":1,"two":"2","three":[4,"5"]}
As a CLI tool
cargo install jf
Or as a library:
cargo add jf
nix-env -f https://github.com/NixOS/nixpkgs/tarball/nixos-unstable -iA jf
jf [OPTION]... [--] TEMPLATE [VALUE]... [NAME=VALUE]... [NAME@FILE]...
option | help |
---|---|
- | alias for -f - , i.e. read template from stdin |
-- | stop parsing CLI options |
-r, --raw | print the raw rendered value without formatting |
-p, --pretty | pretty print the JSON formatted output |
-y, --yaml | print the output as YAML instead of JSON |
-h, --help | print this help message |
-v, --version | print the version number |
-f, --file | treat the template argument as a file to read from |
Template should render into valid YAML. It can contain the following placeholders:
%%
a literal%
character%s
%q
read positional argument%-s
%-q
read stdin%(NAME)s
%(NAME)q
read named value from argument%(NAME=DEFAULT)s
%(NAME=DEFAULT)q
placeholder with default value%(NAME@FILE)s
%(NAME@FILE)q
read default value from file path%(NAME@-)s
%(NAME@-)q
read default value from stdin%(NAME?)s
%(NAME?)q
nullable placeholder that defaults to null%(NAME)?s
%(NAME)?q
optional placeholder that defaults to blank%*s
%*q
expand positional args as array items%*-s
%*-q
expand stdin as array items%**s
%**q
expand positional args as key value pairs%**-s
%**-q
expand stdin as key value pairs%(NAME)*s
%(NAME)*q
expand named args as array items%(NAME)**s
%(NAME)**q
expand named args as key value pairs
Use placeholders with suffix q
for safely quoted JSON string and s
for JSON values
other than string.
- Pass values for positional placeholders in the same order as in the template.
- Pass values for named placeholders using
NAME=VALUE
syntax. - Pass values for named array items using
NAME=ITEM_N
syntax. - Pass values for named key value pairs using
NAME=KEY_N NAME=VALUE_N
syntax. - Pass values to stdin following the order and separate them with null byte (
\0
). - Use
NAME@FILE
syntax to read from file where FILE can be-
for stdin. - Do not pass positional values after named values.
- To allow merging arrays and objects via expansion, trailing comma after
s
andq
, if any, will be auto removed if no value is passed for the expandable placeholder.
jf %s 1
# 1
jf %q 1
# "1"
jf '{%**q}' one 1 two 2 three 3
# {"one":"1","two":"2","three":"3"}
seq 1 3 | xargs printf '%s\0' | jf '[%*-s]'
# [1,2,3]
jf "{%q: %(value=default)q, %(bar)**q}" foo value=bar bar=biz bar=baz
# {"foo":"bar","biz":"baz"}
jf "{str or bool: %(str)?q %(bool)?s, nullable: %(nullable?)q}" str=true
# {"str or bool":"true","nullable":null}
jf '{1: %s, two: %q, 3: %(3)s, four: %(four=4)q, "%%": %(pct?)q}' 1 2 3=3
# {"1":1,"two":"2","3":3,"four":"4","%":null}
You can set the following aliases in your shell:
alias str='jf %q'
alias arr='jf "[%*s]"'
alias obj='jf "{%**s}"'
Then you can use them like this:
str 1
# "1"
arr 1 2 3
# [1,2,3]
obj one 1 two 2 three 3
# {"one":1,"two":2,"three":3}
obj 1 2 3 $(arr 4 $(str 5))
# {"1":2,"3":[4,"5"]}
let json = match jf::format(["%q", "JSON Formatted"].map(Into::into)) {
Ok(value) => value,
Err(jf::Error::Jf(e)) => bail!("mytool: {e}"),
Err(jf::Error::Json(e)) => bail!("mytool: json: {e}"),
Err(jf::Error::Yaml(e)) => bail!("mytool: yaml: {e}"),
};