{"id":18326650,"url":"https://github.com/orhankupusoglu/jo-jq","last_synced_at":"2025-08-24T11:39:17.112Z","repository":{"id":104229629,"uuid":"128904088","full_name":"OrhanKupusoglu/jo-jq","owner":"OrhanKupusoglu","description":"JSON with Bash","archived":false,"fork":false,"pushed_at":"2020-10-02T12:09:22.000Z","size":160,"stargazers_count":6,"open_issues_count":0,"forks_count":1,"subscribers_count":1,"default_branch":"master","last_synced_at":"2025-04-06T00:32:24.435Z","etag":null,"topics":["bash","jo","jq","json"],"latest_commit_sha":null,"homepage":null,"language":"Shell","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/OrhanKupusoglu.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2018-04-10T08:59:58.000Z","updated_at":"2024-10-27T18:49:32.000Z","dependencies_parsed_at":null,"dependency_job_id":"f6ca79a1-f26e-4e93-9787-da0f7050ddbc","html_url":"https://github.com/OrhanKupusoglu/jo-jq","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/OrhanKupusoglu/jo-jq","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/OrhanKupusoglu%2Fjo-jq","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/OrhanKupusoglu%2Fjo-jq/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/OrhanKupusoglu%2Fjo-jq/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/OrhanKupusoglu%2Fjo-jq/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/OrhanKupusoglu","download_url":"https://codeload.github.com/OrhanKupusoglu/jo-jq/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/OrhanKupusoglu%2Fjo-jq/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":271854475,"owners_count":24834453,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","status":"online","status_checked_at":"2025-08-24T02:00:11.135Z","response_time":111,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["bash","jo","jq","json"],"created_at":"2024-11-05T19:07:34.181Z","updated_at":"2025-08-24T11:39:17.104Z","avatar_url":"https://github.com/OrhanKupusoglu.png","language":"Shell","funding_links":[],"categories":[],"sub_categories":[],"readme":"# JSON with Bash\n\n[JSON](https://en.wikipedia.org/wiki/JSON) is a syntax for serializing numbers, strings, booleans, null, objects and arrays.\n\nFirst proposed by [Douglas Crockford](https://en.wikipedia.org/wiki/Douglas_Crockford) in 2001 and published as [RFC 4627](https://tools.ietf.org/html/rfc4627) (ten pages only, now obsolete) in 2006, JSON is widely used as a language-independent data format.\n\nWhile JSON has six data types, an important omission has been comments, Douglas Crockford himself [explains](https://plus.google.com/+DouglasCrockfordEsq/posts/RK8qyGVaGSr) his reasoning as:\n\n\u003eI removed comments from JSON because I saw people were using them to hold parsing directives, a practice which would have destroyed interoperability.\n\nAny unused key can act as a *comment*, a particularly good choice is **//**. The following example is a [valid](https://jsonlint.com/) JSON:\n```\n{\n    \"//\": \"my comment\"\n}\n```\n\n## jo \u0026mdash; the JSON Output Tool\n\n[jo](https://github.com/jpmens/jo) is a utility to generate **structured** JSON with Bash.\n\nGenerating JSON simply with **echo** is, as expected, error-prone. This is the **unstructured** way to generate JSON with Bash. In general, other than on very simple samples using simple string manipulation to generate JSON should better be avoided.\n\n### Installation\n\nOn Ubuntu the following commands add a [repository](https://launchpad.net/~duggan/+archive/ubuntu/jo) and install **jo**.\n\n```\n$ sudo apt add-repository ppa:duggan/jo\n$ sudo apt update\n$ sudo apt install jo\n```\n### Primitives \u0026mdash; numbers, strings, booleans, and null\n\nLet's start with the time-honored cliche:\n\n```\n$ jo greeting='Hello World'\n{\"greeting\":\"Hello World\"}\n```\n\nThe quotes, both double and single, are interpreted by the shell and stripped from the command line arguments before **jo** receives them:\n```\n$ TEST_PASS=\"89\"\n$ TEST_TEMP='11.43'\n$ TEST_NOTE='mediocre'\n$ TEST_STATUS=true\n$ TEST_OBJECT=\"null\"\n\n# with double quotes\n$ jo pass=\"$TEST_PASS\" temp=\"$TEST_TEMP\" note=\"$TEST_NOTE\" status=\"$TEST_STATUS\" object=\"$TEST_OBJECT\"\n{\"pass\":89,\"temp\":11.43,\"note\":\"mediocre\",\"status\":true,\"object\":null}\n\n# without double quotes\n$ jo pass=$TEST_PASS temp=$TEST_TEMP note=$TEST_NOTE status=$TEST_STATUS object=$TEST_OBJECT\n{\"pass\":89,\"temp\":11.43,\"note\":\"mediocre\",\"status\":true,\"object\":null}\n```\n\nIf strings contain white spaces then double quotes are required:\n```\n$ TEST_NOTE='more work is required'\n\n$ jo pass=$TEST_PASS temp=$TEST_TEMP note=\"$TEST_NOTE\" status=$TEST_STATUS object=$TEST_OBJECT\n{\"pass\":89,\"temp\":11.43,\"note\":\"more work is required\",\"status\":true,\"object\":null}\n```\n\njo can pretty-print with **-p**:\n```\n$ jo -p pass=$TEST_PASS temp=$TEST_TEMP note=\"$TEST_NOTE\" status=$TEST_STATUS object=$TEST_OBJECT\n{\n   \"pass\": 89,\n   \"temp\": 11.43,\n   \"note\": \"more work is required\",\n   \"status\": true,\n   \"object\": null\n}\n```\n\n### Objects and Arrays\njo generates arrays with **-a**:\n```\n$ jo -a 1 2 3\n[1,2,3]\n\n$ jo -p -a 1 2 3\n[\n   1,\n   2,\n   3\n]\n```\nAn object can be created with **key=value**:\n```\n$ jo dtype=temperature\n{\"dtype\":\"temperature\"}\n```\nSuffix **[]** marks an array:\n```\n$ jo dtype=temperature data[]=11.9 data[]=20.3 data[]=30.7\n{\"dtype\":\"temperature\",\"data\":[11.9,20.3,30.7]}\n```\nThis usage can be cumbersome, so nested element output can be preferable:\n```\n$ jo dtype=temperature data=$(jo -a 11.9 20.3 30.7)\n{\"dtype\":\"temperature\",\"data\":[11.9,20.3,30.7]}\n```\n\nObjects can be nested, too:\n```\n$ jo dtype=wind meta=$(jo time=day height=150 speed=m/s)\n{\"dtype\":\"wind\",\"meta\":{\"time\":\"day\",\"height\":150,\"speed\":\"m/s\"}}\n```\n\n### JSON Variables\n\nCapturing JSON into a Bash variable with [command substitution](https://www.gnu.org/software/bash/manual/html_node/Command-Substitution.html) is quite useful:\n```\n$ temp=$(jo dtype=temperature data=$(jo -a 11.9 20.3 30.7))\n$ wind=$(jo dtype=wind meta=$(jo time=day height=150 speed=m/s))\n\n$ echo $temp\n{\"dtype\":\"temperature\",\"data\":[11.9,20.3,30.7]}\n$ echo $wind\n{\"dtype\":\"wind\",\"meta\":{\"time\":\"day\",\"height\":150,\"speed\":\"m/s\"}}\n```\n\n## jq \u0026mdash; the JSON Query Tool\n\n[jq](https://github.com/stedolan/jq) is an advanced JSON processor, suitable to query and output JSON data. The [jq manual](https://stedolan.github.io/jq/manual/) contains many examples.\n\n### Installation\n\nOn Ubuntu the **jq** [installation](https://stedolan.github.io/jq/download/) is a breeze:\n\n```\n$ sudo apt install jq\n```\n\n### Commands\n\n**jq** can easily query one-line-JSONs:\n\n```\n$ echo '{\"dtype\":\"wind\",\"meta\":{\"time\":\"day\",\"height\":150,\"speed\":\"m/s\"}}' | jq \".dtype\"\n\"wind\"\n```\nA JSON file can be queried, too:\n```\n$ cat \u003e wind.json \u003c\u003c EOF\n{\"dtype\":\"wind\",\"meta\":{\"time\":\"day\",\"height\":150,\"speed\":\"m/s\"}}\nEOF\n\n$ cat wind.json\n{\"dtype\":\"wind\",\"meta\":{\"time\":\"day\",\"height\":150,\"speed\":\"m/s\"}}\n\n$ jq \".dtype\" wind.json\n\"wind\"\n$ jq \".meta\" wind.json\n{\n  \"time\": \"day\",\n  \"height\": 150,\n  \"speed\": \"m/s\"\n}\n```\n\nKeys can be obtained:\n```\n$ jq --sort-keys 'keys' wind.json\n[\n  \"dtype\",\n  \"meta\"\n]\n```\n\nInstead of parsing many times, a JSON file can be read and parsed at once into an array:\n```\n$ jq -n --slurpfile data wind.json '$data'\n[\n  {\n    \"dtype\": \"wind\",\n    \"meta\": {\n      \"time\": \"day\",\n      \"height\": 150,\n      \"speed\": \"m/s\"\n    }\n  }\n]\n\n$ jq -n --slurpfile data wind.json '$data[0].meta'\n{\n  \"time\": \"day\",\n  \"height\": 150,\n  \"speed\": \"m/s\"\n}\n```\n\nThis data can be captured with command substitution:\n```\n$ meta=$(jq -n --slurpfile data wind.json '$data[0].meta')\n$ echo $meta\n{ \"time\": \"day\", \"height\": 150, \"speed\": \"m/s\" }\n```\n\u0026nbsp;\n\n### Example\n\n[Rally](https://github.com/openstack/rally) is a benchmarking tool for OpenStack. The [OPNFV Functional Testing](https://wiki.opnfv.org/display/functest/Opnfv+Functional+Testing) project uses Rally to verify an OpenStack installation. Its JSON output is a rather large JSON file with a strange structure. A similar JSON data is to be be embedded into the HTML output, and is designed to ease the work of its AngularJS scripts. The [status.sh](./example/status.sh) script uses **jq** to parse this JSON content. Expected input filename is **report.json**. It outputs a text file of test names including IDs and a trimmed JSON file consisting of results of the same status. By default it is **fail**, but the desired status can be given as an argument to the script. \n\n```\n$ ./status.sh help\nUSAGE: enter commands, no command defaults to '--status=fail --file=report.json'\n    --status=fail       -- filter status 'fail'\n    --status=success    -- filter status 'success'\n    --status=skip       -- filter status 'skip'\n    --file=report.json  -- enter file to filter\n    help                -- print this help\n\n$ ./status.sh \n++ Verification ID:\n\tdeace42c-3f52-4bb2-9259-f41b364a7a44\n++ Test started at:\n\t2018-02-13T15:00:24\n++ Total tests:\n\t1599 tests\n++ Status:\n\tfail - 367 tests\n++ Duration:\n\t00:02:51\n++ See:\n\tfail_2018-02-13_15-00-24.txt\n\tfail_2018-02-13_15-00-24.json\n\n$ ./status.sh --status=success\n++ Verification ID:\n\tdeace42c-3f52-4bb2-9259-f41b364a7a44\n++ Test started at:\n\t2018-02-13T15:00:24\n++ Total tests:\n\t1599 tests\n++ Status:\n\tsuccess - 1118 tests\n++ Duration:\n\t00:02:12\n++ See:\n\tsuccess_2018-02-13_15-00-24.txt\n\tsuccess_2018-02-13_15-00-24.json\n\n```\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Forhankupusoglu%2Fjo-jq","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Forhankupusoglu%2Fjo-jq","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Forhankupusoglu%2Fjo-jq/lists"}