{"id":13476374,"url":"https://github.com/micha/jsawk","last_synced_at":"2025-05-15T23:08:24.110Z","repository":{"id":577403,"uuid":"209968","full_name":"micha/jsawk","owner":"micha","description":"Like awk, but for JSON.","archived":false,"fork":false,"pushed_at":"2021-08-31T15:23:11.000Z","size":301,"stargazers_count":1381,"open_issues_count":28,"forks_count":96,"subscribers_count":45,"default_branch":"master","last_synced_at":"2025-05-10T14:04:40.261Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":"","language":"Shell","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":"knieriem/markdown","license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/micha.png","metadata":{"files":{"readme":"README.markdown","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2009-05-25T21:05:43.000Z","updated_at":"2025-04-28T04:20:18.000Z","dependencies_parsed_at":"2022-07-08T02:06:42.350Z","dependency_job_id":null,"html_url":"https://github.com/micha/jsawk","commit_stats":null,"previous_names":[],"tags_count":5,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/micha%2Fjsawk","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/micha%2Fjsawk/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/micha%2Fjsawk/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/micha%2Fjsawk/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/micha","download_url":"https://codeload.github.com/micha/jsawk/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":254436949,"owners_count":22070947,"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","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":[],"created_at":"2024-07-31T16:01:29.519Z","updated_at":"2025-05-15T23:08:18.398Z","avatar_url":"https://github.com/micha.png","language":"Shell","funding_links":[],"categories":["Shell","Command-line tools","\u003ca name=\"data-management-json\"\u003e\u003c/a\u003eData management - JSON/YAML/etc."],"sub_categories":[],"readme":"# Quick Start\n\n*If you use Jsawk and want to help maintain it, please let me know and I'll add you to the repo.*\n\n[Updated underscore.js to v1.8.2.](http://documentcloud.github.com/underscore/)\n\nJsawk is like awk, but for JSON. You work with an array of JSON objects\nread from stdin, filter them using JavaScript to produce a results array\nthat is printed to stdout. You can use this as a filter to manipulate data\nfrom a REST JSON web service, for example, in a shell script. Also, you can\nsuppress JSON output and use the built-in printing functions to translate\nyour JSON input to other formats and send that to stdout, to be piped to\nother processes. You can load JavaScript libraries on the command line to\nincrease your processing power, and other things.\n\n## Setup\n\n[This is a great blog post on setup and basic use of jsawk and resty, thanks\nto @johnattebury.](http://johnattebury.com/blog/2011/06/spidermonkey-jsawk-resty-on-snow-leopard/)\n\nYou need to have the `js` interpreter installed. Your best bet is to navigate to\nthe mozilla site [download and build the source](https://developer.mozilla.org/en-US/docs/Mozilla/Projects/SpiderMonkey)\nbased on the maintained documentation there.\n\nReady? Go.\n\n## Install\n\nFirst, get the jsawk script:\n\n      curl -L http://github.com/micha/jsawk/raw/master/jsawk \u003e jsawk\n\nThen make it executable and put it somewhere in your path:\n\n      chmod 755 jsawk \u0026\u0026 mv jsawk ~/bin/\n\n## Use\n\nNow you can do some stuff with JSON data. Here's an example using data from\na REST service that serves JSON (we use [resty](http://github.com/micha/resty)\nto do the HTTP requests):\n\n      resty http://example.com:8080/data*.json\n      GET /people/47 | jsawk 'this.favoriteColor = \"blue\"' | PUT /people/47\n\nThis would do a `GET` request on the resource `/data/people/47.json`, which\nwould result in a JSON object. Then jsawk takes the JSON via stdin and for\neach JSON object it runs the little snippet of JavaScript, setting the\n`favoriteColor` property to `\"blue\"`, in this case. The modified JSON is then\noutput via stdout to `resty` again, which does the `PUT` request to update\nthe resource.\n\n## Usage\n\n      jsawk [OPTIONS] [SCRIPT]\n\n      OPTIONS\n      -------\n\n      -b \u003cscript\u003e | -a \u003cscript\u003e\n          Run the specified snippet of JavaScript before (-b) or after (-a)\n          processing JSON input. The `this` object is set to the whole JSON\n          array or object. This is used to preprocess (-b) or postprocess\n          (-a) the JSON array before or after the main script is applied.\n          This option can be specified multiple times to define multiple\n          before/after scripts, which will be applied in the order they\n          appeared on the command line.\n\n      -f \u003cfile\u003e\n          Load and run the specified JavaScript file prior to processing\n          JSON. This option can be specified multiple times to load multiple\n          JavaScript libraries.\n\n      -h\n          Print short help page and exit.\n\n      -i \u003cfile\u003e\n          Read input JSON from `file` instead of stdin.\n\n      -j \u003cjsbin\u003e\n          Specify path to spidermonkey js binary.\n\n      -n\n          Suppress printing of JSON result set.\n\n      -q \u003cquery\u003e\n          Filter JSON through the specified JSONQuery query. If multiple\n          '-q' options are specified then each query will be performed in\n          turn, in the order in which they appeared on the command line.\n\n      -s \u003cstring\u003e\n          Use `string` for input JSON instead of stdin.\n\n      -v \u003cname=value\u003e\n          Set global variable `name` to `value` in the script environment.\n\n      SCRIPT\n      ------\n\n      This is a snippet of JavaScript that will be run on each element\n      of the input array, if input is a JSON array, or on the object if\n      it's an object. For each iteration, the `this` object is set to the\n      current element.\n\n### Using A Specific JS Binary\n\nThe path to the `js` binary can be specified in two different ways:\n\n* the `-j` command line option (see above)\n* the `JS` environment variable\n\nAdditionally, jsawk will `source` the following files at startup if they exist:\n\n* _/etc/jsawkrc_\n* _~/.jsawkrc_\n\nThese files can be used to export the `JS` environment variable.\n\nJsawk Scripting\n===============\n\nJsawk is intended to serve the purpose that is served by `awk` in the shell\nenvironment, but instead of working with words and lines of text, it works\nwith JavaScript objects and arrays of objects.\n\nIn awk, a text file is split into an array of \"records\", each of which being\nan array of \"fields\". The awk script that is specified on the command line is\nrun once for each record in the array, with the `$1`, `$2`, etc. variables\nset to the various fields in the record. The awk script can set variables,\nperform calculations, do various text-munging things, and print output. This\nprinting capablity makes awk into a filter, taking text input, transforming\nit record by record, printing out the resulting modified records at the end.\n\nJsawk is similar, but in jsawk records are elements of the JSON input array\n(if the input was a single object then there is a single record consisting\nof that object). The jsawk script is run once for each record object, with\nthe `this` object set to the current record. So here the properties of the\nrecord object are equivalent to the `$1`, `$2`, etc. in awk. The jsawk\nscript can then modify the record, perform calculations, do things. However,\ninstead of printing the modified record, the modified record is `return`ed.\nAt then end, if the `-n` option was not specified, the resulting array is\nprinted as JSON to stdout.\n\nJsawk JavaScript Environment\n----------------------------\n\nJsawk uses the Spidermonkey JavaScript interpreter, so you have access to all\nof the Spidermonkey functions and whatnot. Additionally, the following\nfunctions and properties are available from within a jsawk script:\n\n      PROPERTIES\n      ----------\n\n        window\n            The global object.\n\n        IS\n            The input set.\n\n        RS\n            The result set.\n\n        _   The underscore.js object.\n\n        $_\n            The current record index (corresponding to the index of the\n            element in the IS array).\n\n        $$\n            The current record object (global variable corresponding to the\n            `this` object in the script scope).\n\n      METHODS\n      -------\n\n        forEach(array, string)\n            Compiles 'string' into a function and iterates over the 'array',\n            running the function once for each element. The function has\n            access to the special variables 'index' and 'item' which are,\n            respectively, the array index and the array element. The 'this'\n            object is set to the array element each time the function runs.\n\n            params: Array array (array to iterate over)\n                    String string (the function source)\n            return: void\n\n        get()\n            Get the next record from the input set. This will prevent jsawk\n            from iterating over that record.\n\n            params: void\n            return: Object|Array|Number|String (the next input record)\n\n        put(record)\n            Push 'record' onto the input set so that jsawk will iterate over\n            it next.\n\n            params: Object|Array|Number|String record (the record to push)\n            return: void\n\n        json(thing)\n            Serialize 'thing' to JSON string.\n\n            params: Object|Array|Number|String thing (what to serialize)\n            return: String (the resulting JSON string)\n\n        uniq(array)\n            Return array of distinct elements.\n\n            params: Array array (the input array)\n            return: Array (the resulting array of distinct elements)\n\n        Q(query, thing)\n            Runs the JSONQuery 'query' on the JSON input 'thing'.\n\n            params: String query (the JSONQuery)\n                    Array|Object thing (the JSON input)\n            return: Array|Object (result of running the query)\n\n        err(thing)\n            Print arguments (JSON encoded, if necessary) to stderr.\n\n            params: Object|Array|Number|String thing (what to encode)\n            return: void\n\n        out(thing)\n            Print arguments (JSON encoded, if necessary) to stdout.\n\n            params: Object|Array|Number|String thing (what to encode)\n            return: void\n\nErrors and Output\n-----------------\n\nErrors in parsing scripts, JSON queries, or JSON input, and errors executing\nscripts will all result in the appropriate error message on stderr, and\nimmediate exit with a non-zero exit status. Normal output is written to\nstdout, unless the `-n` option is specified. In that case only output from\nthe `out()` or `err()` functions and error messages will appear.\n\nExit Status\n-----------\n\nOn successful completion jsawk returns an exit status of `0`. If an error\nocurred and execution was aborted, a non-zero exit status will be returned.\n\n### Exit Status\n\n  * **0** Successful completion.\n  * **1** Command line parsing error.\n  * **2** JSON parsing error.\n  * **3** Script error.\n  * **4** JSONQuery parsing error.\n  * **5** JSON stringify error.\n\nJSONQuery\n=========\n\nJsawk supports JSONQuery with the `-q` option. You can do almost anything\nwith JSONQuery that you can do with jsawk scripts, to include selecting\nrecords, drilling down into records, mapping input sets to output sets as\na sort of filter, modifying the JSON, sorting, whathaveyou. JSONQuery is\nto JSONPath is to JSON, as XQuery is to XPath is to XML. Here are some\nJSONQuery resources to get started with this powerful tool:\n\n  * [The persevere JSONQuery documentation](http://docs.persvr.org/documentation/jsonquery)\n  * [Kris Zyp's intro to JSONQuery in dojo](http://www.sitepen.com/blog/2008/07/16/jsonquery-data-querying-beyond-jsonpath/)\n\nExamples\n========\n\nFor the following examples, suppose there is a file `/tmp/t`, with the\nfollowing contents:\n\n      [\n        {\n          \"first\"   : \"trevor\",\n          \"last\"    : \"wellington\",\n          \"from\"    : \"england\",\n          \"age\"     : 52,\n          \"sports\"  : [ \"rugby\", \"badmitton\", \"snooker\" ]\n        },\n        {\n          \"first\"   : \"yoni\",\n          \"last\"    : \"halevi\",\n          \"from\"    : \"israel\",\n          \"age\"     : 26,\n          \"sports\"  : [ \"soccer\", \"windsurfing\" ]\n        },\n        {\n          \"first\"   : \"cory\",\n          \"last\"    : \"parker\",\n          \"from\"    : \"united states\",\n          \"age\"     : 31,\n          \"sports\"  : [ \"windsurfing\", \"baseball\", \"extreeeeme kayaking\" ]\n        }\n      ]\n\nThis is going to be the input JSON text we will use in the examples.\n\nJSON-to-JSON Transformations\n----------------------------\n\nThese examples transform the input JSON, modifying it and returning the\nmodified JSON as output on stdout to be piped elsewhere. Transformations of\nthis type are generally done with a script that follows one of these simple\npatterns:\n\n  1. Modify the `this` object in place (no `return` statement necessary).\n  1. Create a replacement object for each record, and `return` it at the end\n     of each iteration.\n\nThese patterns leave the records in JSON format, and they are automatically\nprinted to stdout without the use of the `out()` function.\n\n### The Identity Mapping\n\nThis is the identity transformation: it doesn't really do anything other\nthan pass the input straight through.\n\n      cat /tmp/t | jsawk\n\nYou should get the input back out, unmolested.\n\n### Increment Everyone's Age\n\nLooks like it's everyone's birthday today. We'll take the JSON input and\nincrement each object's `age` property, sending the resulting JSON output to\nstdout.\n\n      cat /tmp/t | jsawk 'this.age++'\n\nNotice that there is no need to write `return this` in the script. That is\nassumed---the runtime does it for you automatically if you don't explicitly\ncall `return` yourself.\n\n### Flatten The \"Sports\" Array Of Each Element\n\nHere we modify the input by replacing the `sports` property of each object\nin the input array (the `sports` property is itself an array of strings) with\na single string containing all of the person's sports, separated by commas.\n\n      cat /tmp/t | jsawk 'this.sports = this.sports.join(\",\")'\n\nNotice how altering the `this` object in place alters the result array\naccordingly.\n\n### Extract Only The \"Age\" Property Of Each Element ###\n\nNormally we would modify the input set in place, by manipulating the `this`\nobject, which would be returned by default after each iteration. However,\nsometimes we want only a single field from the input set.\n\n      cat /tmp/t | jsawk 'return this.age'\n\nPutting a return statement in the script expression causes the default\nreturn of `this` to be short-circuited, replacing this element with the\nreturn value in the output set.\n\n### JSON Grep: Select Certain Elements From Input ###\n\nSometimes you want to use awk to select certain records from the input set,\nleaving the rest unchanged. This is like the `grep` pattern of operation. In\nthis example we will extract all the records corresponding to people who are\nover 30 years old.\n\n      cat /tmp/t | jsawk 'if (this.age \u003c= 30) return null'\n\nThis demonstrates how you can remove records from the results array by\nreturning a null value from your script.\n\nAggregate Functions\n-------------------\n\nBefore and after scripts can be used to manipulate the JSON working set as\na whole, somewhat similar to the way aggregate functions like `SUM()` or\n`COUNT()` work in SQL. These types of operations fall under a few basic\npatterns.\n\n  1. Use a before script (`-b` option) to do things to the JSON input before\n     transformations are done by the main script.\n  2. Use an after script (`-a` option) to do things to the JSON result set\n     after all transformations are completed by the main script.\n\n### Count How Many Elements Are In The Input Array\n\nHere we use an after script to modify the result set, like this:\n\n      cat /tmp/t | jsawk -a 'return this.length'\n\nNotice how the entire results array is replaced by the single number and\nprinted to stdout.\n\n### Get a Sorted, Unique List of All Sports\n\nThis is an example of a JSON-to-JSON transformation that uses an after\nscript to manipulate the result set. It should produce an array of all\nsports played by the people in the input set, sorted lexically, and with\nall duplicate elements removed.\n\n      cat /tmp/t \\\n        | jsawk 'RS=RS.concat(this.sports); return null' -a 'return uniq(RS).sort()'\n\nNote the use of `return null` to prevent jsawk from adding the `this`\nobject to the result set automatically. Instead we manipulated the result\nset explicitly, enabling each iteration to add more that one element to\nit---the entire `sports` array. Also, notice the use of an after script\nto sort the result set and remove duplicates.\n\nJSON-to-Text Transformations\n----------------------------\n\nIn the following examples we will be manipulating the JSON input to\nproduce text output instead of JSON, for cases where you will be extracting\ninformation from a JSON data source and piping it to non JSON-accepting\nprocesses elsewhere.\n\nIt is frequently useful to supress the regular JSON output when doing\nJSON-to-Text transformations like these, with the `-n` option.\n\n### Get A List Of All Sports\n\nThis one generates a list of all the sports that are played by the people\nin our little JSON list, one per line, without duplicate entries, sorted\nalphabetically.\n\n      cat /tmp/t \\\n        | jsawk -a 'return this.join(\"\\n\")' 'return this.sports.join(\"\\n\")' \\\n        | sort -u\n\nNotice the use of JSONQuery to drill down into the JSON objects, an \"after\"\nscript to collate the results, and everything piped to the Unix `sort`\ntool to remove duplicate entries and do the lexical ordering.  This is\nstarting to show the power of the awk-like behavior now.\n\n### Return a Boolean Value\n\nSometimes you want to just check for a certain condition in a shell script.\nSuppose you want to know if there are any people over the age of 50 in the\nJSON input array, like this:\n\n      jsawk -n 'if (this.age \u003e 50) quit(1)' \u003c /tmp/t || echo \"We have people over 50 here---naptime in effect.\"\n\nWe suppress normal result set output with `-n` and use the `quit()` function\nto return a value in the exit status. The default exit status is, of course,\nzero for success.\n\nJSON Pretty-Printing\n====================\n\n[Resty](http://github.com/micha/resty) includes the `pp` script that will\npretty-print JSON for you. You just need to install the JSON perl module\nfrom CPAN. Use it like this:\n\n      GET /blogs.json | jsawk -q '..author' | pp\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmicha%2Fjsawk","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fmicha%2Fjsawk","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmicha%2Fjsawk/lists"}