jql 5.1.7

A JSON query language CLI tool
Documentation

jql

GitHub Workflow Status Crates.io contribute.design

A JSON Query Language CLI tool built with Rust 🦀

📜 Core philosophy

  • 📦 Stay lightweight
  • 🎮 Keep its features as simple as possible
  • 🧠 Avoid redundancy
  • 💡 Provide meaningful error messages
  • ↔️ Eat JSON as input, process, output JSON back

⚠️ Non-goal

This tool has absolutely no plan to be on par with jq and such other similar CLI.

🚀 Installation

Alpine Linux

The package is maintained by @jirutka.

apk add jql

Archlinux

The AUR package is maintained by @barklan.

yay -S jql

Cargo

cargo install jql

Fedora

dnf install jql

Homebrew

brew install jql

Nix

nix-env -i jql

openSUSE

zypper install jql

Manual installation from GitHub

Compiled binary versions are automatically uploaded to GitHub when a new release is made. You can install jql manually by downloading a release.

🛠️ Usage

If you find some of the following examples confusing, please have a look at The JavaScript Object Notation (JSON) Data Interchange Format.

Root selection

"This is a valid JSON text with one value"
jql '.' example.json
"This is a valid JSON text with one value"

Child selection

{
  "some": {
    "property": "yay!"
  }
}
jql '"some"."property"' example.json
"yay!"

Index selection

{
  "primes": [7, 11, 13]
}
jql '"primes".[0]' example.json
7

Please note that the following is also valid:

jql '"primes"[0]"' example.json
7

You can also select a set of indexes:

jql '"primes".[2,0]' example.json
[13, 7]

Range selection

{
  "cats": [{ "first": "Pixie" }, { "second": "Kitkat" }, { "third": "Misty" }]
}
jql '"cats".[1:2]' example.json
[
  {
    "second": "Kitkat"
  },
  {
    "third": "Misty"
  }
]

Please note that you can reverse it:

jql '"cats".[2:1]' example.json
[
  {
    "third": "Misty"
  },
  {
    "second": "Kitkat"
  }
]

Bonus, you can do it again to get it back:

jql '"cats".[2:1].[1:0]' example.json
[
  {
    "second": "Kitkat"
  },
  {
    "third": "Misty"
  }
]

Please note that you can still access the children:

jql '"cats".[2:1].[0]."third"' example.json
"Misty"

You can also use the start or the end position as a range selector:

jql '"cats".[1:]' example.json
[
  {
    "second": "Kitkat"
  },
  {
    "third": "Misty"
  }
]
jql '"cats".[:1]' example.json
[
  {
    "first": "Pixie"
  },
  {
    "second": "Kitkat"
  }
]

Array selection

{
  "primes": [7, 11, 13]
}
jql '"primes".[]' example.json
[7, 11, 13]

Please note that this is basically an alias for a full range selection:

jql '"primes".[0:2]' example.json

Property selection

{
  "object": { "a": 1, "b": 2, "c": 3 }
}
jql '"object".{"a","c"}' example.json
{
  "a": 1,
  "c": 3
}

Property selection can also be used with indexes and ranges. Please note that in this case a remapping/transformation is applied to the JSON data:

{
  "alpha": "red",
  "beta": "green",
  "gamma": "blue"
}
jql '{[2,0,1]}' example.json
{
  "2": "blue",
  "0": "red",
  "1": "green"
}
jql '{[1:2]}' example.json
{
  "1": "green",
  "2": "blue"
}

This is pretty unusual, but it might help in some scenarios when e.g. one wants to extract some properties out of a complex JSON structure based on their order:

{
  "some-property": [
    {
      "key1": [
        {
          "subkey1": "value"
        }
      ],
      "key2": 123
    },
    {
      "key3": [
        {
          "subkey3": "value"
        }
      ],
      "key4": "something"
    }
  ]
}
jql '.."some-property"|{[0]}|"0"' example.json
[
  {
    "subkey1": "value"
  },
  {
    "subkey3": "value"
  }
]

Multi-selection

{
  "one": [1, 2, 3],
  "two": 2,
  "three": 3
}
jql '"one".[2:0],"two","three"' example.json
[[3, 2, 1], 2, 3]

Filter

{
  "laptops": [
    {
      "laptop": {
        "brand": "Apple",
        "options": ["a", "b", "c"]
      }
    },
    {
      "laptop": {
        "brand": "Asus",
        "options": ["d", "e", "f"]
      }
    }
  ]
}
jql '"laptops"|"laptop"' example.json
[
  {
    "brand": "Apple",
    "options": ["a", "b", "c"]
  },
  {
    "brand": "Asus",
    "options": ["d", "e", "f"]
  }
]

You can also combine a filter with a child selection, a multi-selection and ranges at the same time:

jql '"laptops"|"laptop"."brand"' example.json
["Apple", "Asus"]
jql '"laptops".[1:0]|"laptop"."brand","laptops"|"laptop"."brand"' example.json
[
  ["Asus", "Apple"],
  ["Apple", "Asus"]
]

Please note that you can combine filters to achieve the same result:

jql '"laptops".[1:0]|"laptop"|"brand","laptops"|"laptop"|"brand"' example.json
[
  ["Asus", "Apple"],
  ["Apple", "Asus"]
]

Flatten

Arrays

{
  "dna": [[[[["c", "a", "c"]]]], "g", "t", [[["a", ["t"]]]]]
}
jql '.."dna"' example.json
["c", "a", "c", "g", "t", "a", "t"]

Objects

{
  "test": {
    "foo": {
      "bar": false
    }
  }
}
jql '.."test"' example.json
{ "foo.bar": false }

Lens

Lenses enable filtering an array of objects by key, key/value pair or a combination of both. Please note that only number, string and null primitive can be used as value.

{
  "lenses": [
    { "alpha": 1, "beta": null },
    { "beta": 2 },
    { "gamma": 3, "delta": "something" },
    { "alpha": 7 },
    { "delta": 4 }
  ]
}
jql '"lenses"|={"alpha","delta"}' example.json
[
  {
    "alpha": 1,
    "beta": null
  },
  {
    "gamma": 3,
    "delta": "something"
  },
  {
    "alpha": 7
  },
  {
    "delta": 4
  }
]
jql '"lenses"|={"alpha":"7","beta":"null"}' example.json
[
  {
    "alpha": 1,
    "beta": null
  },
  {
    "alpha": 7
  }
]
jql '"lenses"|={"delta":"something","alpha"}' example.json
[
  {
    "alpha": 1,
    "beta": null
  },
  {
    "gamma": 3,
    "delta": "something"
  },
  {
    "alpha": 7
  }
]

Truncate

The truncate selector ! can be used to stop walking the children's values and to explore an unknown JSON file / structure. Each child is then transformed into a JSON primitive for convenience, e.g.:

primitive value result
object { "a": 1, "b": 2, "c": 3 } {}
array [1, 2, 3] []
string "foo" "foo"
number 666 666
null null null
{
  "foo": {
    "a": null,
    "b": "bar",
    "c": 1337,
    "d": {
      "woot": [1, 2, 3]
    }
  }
}
jql '.!' example.json
{
  "foo": {}
}
jql '"foo"!' example.json
{
  "a": null,
  "b": "bar",
  "c": 1337,
  "d": {}
}

Special characters

In order to be fully compliant with JSON's object keys, jql always expect selectors to be double-quoted.

{
  ".valid": 1337,
  "": "yeah!",
  "\"": "yup, valid too!"
}
jql '".valid"' example.json
1337
jql '""' example.json
"yeah!"
jql '"\""' example.json
"yup, valid too!"

💻 Shell integration

How to save the output

jql '"foo"."bar"' input.json > output.json

How to read from stdin

cat example.json | jql '"foo"."bar"'

Available flags 🤖

Help

jql -h
jql --help

Check

The command will return a matching exit code based on the validity of the JSON content or file provided. No selector is needed in this case!

jql -c example.json
jql --check example.json

Please note that this flag is exclusive.

From file

The command will reads the provided selectors from a file rather than from a command line.

jql -f selector.txt example.json
jql --from-file selector.txt example.json

Inlining the JSON output

jql -i '"some"."selector"' example.json
jql --inline '"some"."selector"' example.json

Raw output

Use the raw-output flag on a string selection to directly return the raw string without JSON double-quotes:

echo "{\"foo\":\"bar\"}" | jql --raw-output '"foo"'
bar
echo "{\"foo\":\"bar\"}" | jql -r '"foo"'
bar

Streaming

Use the stream flag to read a stream of JSON lines:

while true; do echo '{"foo": 2}'; sleep 1; done | jql '.!' --stream
while true; do echo '{"foo": 2}'; sleep 1; done | jql '.!' -s

Please note that this option is only about reading valid JSON output streamed line by line (e.g. Docker logs with the --follow flag). This is not an option to read an incomplete streamed content (e.g. a very large input)!

Version

jql -V
jql --version

🍿 Library

This crate is both a binary (the CLI tool) and a library that can be directly used https://docs.rs/crate/jql/.

⚡ Performance

Some benchmarks comparing a set of similar functionalities provided by this tool and jq are available here.