#json #command-line #cli

bin+lib jf

A small utility to safely format and print JSON objects in the commandline

20 releases (5 breaking)

new 0.6.2 Jun 1, 2023
0.6.1 May 28, 2023
0.5.0 May 27, 2023
0.4.2 May 27, 2023
0.1.2 Mar 29, 2023

#460 in Command line utilities

Download history 44/week @ 2023-03-24 16/week @ 2023-03-31 1/week @ 2023-04-07 4/week @ 2023-04-14 4/week @ 2023-04-21 2/week @ 2023-04-28 7/week @ 2023-05-05 48/week @ 2023-05-12 470/week @ 2023-05-19 375/week @ 2023-05-26

903 downloads per month
Used in xplr

MIT license

1.5K SLoC


Crate Status

Packaging status

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





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 and q, 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}"),


~44K SLoC