'\" t .\" Automatically generated by Pandoc 3.6 .\" .TH "JAQ" "1" "" "" .SH NAME \f[B]\f[CB]jaq\f[B]\f[R] \[em] Command\-line JSON processor .SH SYNOPSIS \f[B]\f[CB]jaq\f[B]\f[R]\ [\f[I]OPTION\f[R]]\&...\ [\f[I]FILTER\f[R]]\ [\f[I]FILE\f[R]]\&... .SH DESCRIPTION jaq is an interpreter for the jq programming language. It is designed to be usable as a drop\-in replacement for the \f[B]\f[CB]jq\f[B]\f[R] program, which is the reference interpreter for the jq language written in C. .PP Written in Rust, jaq focuses on correctness, high performance, and simplicity. In addition, jaq adds some functionality not present in \f[B]\f[CB]jq\f[B]\f[R]: .IP \[bu] 2 Support for multiple file formats, including JSON, YAML, CBOR, TOML, XML .IP \[bu] 2 Support for invalid UTF\-8 code units in text strings .IP \[bu] 2 Byte strings .IP \[bu] 2 Objects with non\-string keys, such as \f[B]\f[CB]{0: 1, [2]: 3}\f[B]\f[R] .IP \[bu] 2 In\-place replacement of input files .PP This manual aspires to: .IP \[bu] 2 Be comprehensible, concise, and complete. .IP \[bu] 2 Document all functionality in jaq, in particular jaq\[cq]s command\-line interface, jq\[cq]s core language, and jq\[cq]s standard library. That covers the same concepts as the \c .UR https://jqlang.org/manual/ jq manual .UE \c \&. .IP \[bu] 2 Document all divergences between \f[B]\f[CB]jq\f[B]\f[R] and jaq. .PP In case that this manual falls short of these goals, please \c .UR https://github.com/01mf02/jaq/issues open an issue .UE \c or create a pull request. The same holds if you wish to propose new functionality for jaq. This project lives from your contributions! .PP The creation of this manual was funded through the \c .UR https://nlnet.nl/commonsfund NGI0 Commons Fund .UE \c , a fund established by \c .UR https://nlnet.nl NLnet .UE \c with financial support from the European Commission\[cq]s \c .UR https://ngi.eu Next Generation Internet .UE \c \ programme, under the aegis of \c .UR https://commission.europa.eu/about-european-commission/departments-and-executive-agencies/communications-networks-content-and-technology_en DG Communications Networks, Content and Technology .UE \c under grant agreement N^o^ \c .UR https://cordis.europa.eu/project/id/101135429 101135429 .UE \c \&. Additional funding is made available by the \c .UR https://www.sbfi.admin.ch/sbfi/en/home.html Swiss State Secretariat for Education, Research and Innovation .UE \c (SERI). .TP \f[I]Compatibility\f[R] This manual uses \[lq]compatibility\[rq] blocks to point out occasions where jaq diverges from \f[B]\f[CB]jq\f[B]\f[R]. In this manual, \[lq]\f[B]\f[CB]jq\f[B]\f[R]\[rq] refers to the C implementation, whereas \[lq]jq\[rq] refers to the jq language. .TP \f[I]Advanced\f[R] These \[lq]advanced\[rq] blocks are a kind of \[lq]making of\[rq] for this manual. They document experiments I made or ideas I had during the writing of the manual. As such, they are not essential for understanding the jq language. However, they might be useful if you wish to embark on a journey to become a master of the jq language. To satisfy your hunger for an even deeper understanding of jq semantics, my \c .UR https://github.com/01mf02/jq-lang-spec/ jq language specification .UE \c \ should provide sufficient material. Feel free to skip these \[lq]advanced\[rq] blocks if you do not seek enlightenment. .SH COMMAND\-LINE INTERFACE Running \f[B]\f[CB]jaq\f[B]\f[R] [\f[I]OPTION\f[R]]\&... [\f[I]FILTER\f[R]] [\f[I]FILE\f[R]]\&... performs the following steps: .IP \[bu] 2 Parse \f[I]FILTER\f[R] as jq program; see jq language .IP \[bu] 2 For each \f[I]FILE\f[R]: .RS 2 .IP \[bu] 2 Parse \f[I]FILE\f[R] to a stream of values .IP \[bu] 2 For each input value in the file: .RS 2 .IP \[bu] 2 Run \f[I]FILTER\f[R] on the input value and print its output values .RE .RE .IP \[bu] 2 If an uncaught error is encountered at any point, jaq stops. .PP For example, \f[B]\f[CB]jaq \[aq].name?\[aq] persons.json\f[B]\f[R] parses the filter \f[B]\f[CB].name?\f[B]\f[R], then reads all values in \f[B]\f[CB]persons.json\f[B]\f[R] one\-by\-one. It then executes the filter \f[B]\f[CB].name?\f[B]\f[R] on each of the values and prints the outputs of the filter as JSON. .SS INPUT If no \f[I]FILE\f[R] is given, jaq reads from standard input. jaq determines the format to parse a \f[I]FILE\f[R] as follows: .IP \[bu] 2 If \f[B]\f[CB]\-\-from\f[B]\f[R] \f[I]FORMAT\f[R] is used, jaq uses that format. .IP \[bu] 2 Otherwise, if \f[I]FILE\f[R] has a file extension known by jaq, such as \f[B]\f[CB].json\f[B]\f[R], \f[B]\f[CB].yaml\f[B]\f[R], \f[B]\f[CB].cbor\f[B]\f[R], \f[B]\f[CB].toml\f[B]\f[R], \f[B]\f[CB].xml\f[B]\f[R], \f[B]\f[CB].csv\f[B]\f[R], \f[B]\f[CB].tsv\f[B]\f[R] jaq uses the corresponding format. .IP \[bu] 2 Otherwise, jaq assumes JSON. .SS \f[B]\f[CB]\-\-from\f[B]\f[R] \f[I]FORMAT\f[R] Interpret all input files as \f[I]FORMAT\f[R]. For example, \f[B]\f[CB]jaq \-\-from yaml . myfile.yml\f[B]\f[R] parses \f[B]\f[CB]myfile.yml\f[B]\f[R] as YAML. Possible values of \f[I]FORMAT\f[R] include: \f[B]\f[CB]raw\f[B]\f[R], \f[B]\f[CB]raw0\f[B]\f[R], \f[B]\f[CB]json\f[B]\f[R], \f[B]\f[CB]yaml\f[B]\f[R], \f[B]\f[CB]cbor\f[B]\f[R], \f[B]\f[CB]toml\f[B]\f[R], \f[B]\f[CB]xml\f[B]\f[R], \f[B]\f[CB]csv\f[B]\f[R], \f[B]\f[CB]tsv\f[B]\f[R]. .PP jaq automatically chooses the corresponding input format for files with the extensions \f[B]\f[CB].json\f[B]\f[R], \f[B]\f[CB].yaml\f[B]\f[R], \f[B]\f[CB].yml\f[B]\f[R], \f[B]\f[CB].cbor\f[B]\f[R], \f[B]\f[CB].toml\f[B]\f[R], \f[B]\f[CB].xml\f[B]\f[R], \f[B]\f[CB].xhtml\f[B]\f[R], \f[B]\f[CB].csv\f[B]\f[R], \f[B]\f[CB].tsv\f[B]\f[R]. That means that \f[B]\f[CB]jaq \-\-from cbor . myfile.cbor\f[B]\f[R] is equivalent to \f[B]\f[CB]jaq . myfile.cbor\f[B]\f[R]. .TP \f[I]Compatibility\f[R] \f[B]\f[CB]jq\f[B]\f[R] does not have this option. .SS \f[B]\f[CB]\-n\f[B]\f[R], \f[B]\f[CB]\-\-null\-input\f[B]\f[R] Feed \f[B]\f[CB]null\f[B]\f[R] as input to the main program, ignoring any input files. For example: .IP .EX $ yes | jaq \-n null .EE .PP This shows that this does indeed not read any input. .PP The inputs can still be obtained via the \f[B]\f[CB]inputs\f[B]\f[R] filter. For example: .IP .EX $ yes true | jaq \-n \[aq]first(inputs)\[aq] true .EE .PP This can be useful to fold over all inputs with \f[B]\f[CB]reduce\f[B]\f[R] / \f[B]\f[CB]foreach\f[B]\f[R]. .SS \f[B]\f[CB]\-R\f[B]\f[R], \f[B]\f[CB]\-\-raw\-input\f[B]\f[R] Read lines of the input as sequence of strings. For example: .IP .EX $ printf \[dq]Hello\[rs]nWorld\[dq] | jaq \-R \[dq]Hello\[dq] \[dq]World\[dq] .EE .PP When combined with \f[B]\f[CB]\-\-slurp\f[B]\f[R], this yields the whole input as a single string. For example: .IP .EX $ printf \[dq]Hello\[rs]nWorld\[dq] | jaq \-Rs \[dq]Hello\[rs]nWorld\[dq] .EE .PP See \f[B]\f[CB]\-\-rawfile\f[B]\f[R]. .PP This is equivalent to \f[B]\f[CB]\-\-from raw\f[B]\f[R]. .SS \f[B]\f[CB]\-\-raw\-input0\f[B]\f[R] Read values like \f[B]\f[CB]\-\-raw\-input\f[B]\f[R], splitting by NUL (\f[B]\f[CB]\[rs]0\f[B]\f[R]) instead of newlines. For example: .IP .EX $ printf \[dq]Hello\[rs]nWorld\[rs]0foo\[dq] | jaq \-\-raw\-input0 \[dq]Hello\[rs]nWorld\[dq] \[dq]foo\[dq] .EE .PP When combined with \f[B]\f[CB]\-\-slurp\f[B]\f[R], this collects all inputs into an array. For example: .IP .EX $ printf \[dq]Hello\[rs]nWorld\[rs]0foo\[dq] | jaq \-sc \-\-raw\-input0 [\[dq]Hello\[rs]nWorld\[dq],\[dq]foo\[dq]] .EE .PP This option can be used to round\-trip output from \f[B]\f[CB]\-\-raw\-output0\f[B]\f[R]: .IP .EX $ printf \[aq]\[dq]some string\[rs]\[rs]nwith a newline\[dq] \[dq]another string\[dq]\[aq] | jaq \-\-raw\-output0 | jaq \-\-raw\-input0 \[dq]some string\[rs]nwith a newline\[dq] \[dq]another string\[dq] .EE .PP This is equivalent to \f[B]\f[CB]\-\-from raw0\f[B]\f[R]. .TP \f[I]Compatibility\f[R] \f[B]\f[CB]jq\f[B]\f[R] does not have this option. .SS \f[B]\f[CB]\-s\f[B]\f[R], \f[B]\f[CB]\-\-slurp\f[B]\f[R] Read all input values into one array (per file). For example: .IP .EX $ echo 1 2 3 | jaq 1 2 3 $ echo 1 2 3 | jaq \-cs [1,2,3] .EE .PP When combined with \f[B]\f[CB]\-\-raw\-input\f[B]\f[R], jaq reads the full input as a single string. For example: .IP .EX $ echo 1 2 3 | jaq \-Rs \[dq]1 2 3\[rs]n\[dq] .EE .PP See \f[B]\f[CB]\-\-rawfile\f[B]\f[R]. .TP \f[I]Compatibility\f[R] When multiple files are slurped in, \f[B]\f[CB]jq\f[B]\f[R] combines the inputs of all files into one single array, whereas jaq yields an array for every file. This is motivated by jaq\[cq]s \f[B]\f[CB]\-\-in\-place\f[B]\f[R] option, which could not work with the behaviour implemented by \f[B]\f[CB]jq\f[B]\f[R]. The behaviour of \f[B]\f[CB]jq\f[B]\f[R] can be approximated in jaq; for example, to achieve the output of \f[B]\f[CB]jq \-s . a b\f[B]\f[R], you may use \f[B]\f[CB]jaq \-s . <(cat a b)\f[B]\f[R]. .SS OUTPUT .SS \f[B]\f[CB]\-\-to\f[B]\f[R] \f[I]FORMAT\f[R] Print all output values in the given \f[I]FORMAT\f[R]. Any \f[I]FORMAT\f[R] accepted by \f[B]\f[CB]\-\-from\f[B]\f[R] can be used here. .PP Note that not every value can be printed in every format. For example, TOML requires that the root value is an object, so trying to print a non\-object root value as TOML yields an error: .IP .EX $ echo [] | jaq \-\-to toml 2>/dev/null; echo $? 2 .EE .TP \f[I]Compatibility\f[R] \f[B]\f[CB]jq\f[B]\f[R] does not have this option. .SS \f[B]\f[CB]\-c\f[B]\f[R], \f[B]\f[CB]\-\-compact\-output\f[B]\f[R] Print JSON compactly, omitting whitespace. For example: .IP .EX $ echo [1, 2, 3] | jaq \-c [1,2,3] .EE .SS \f[B]\f[CB]\-r\f[B]\f[R], \f[B]\f[CB]\-\-raw\-output\f[B]\f[R] Write (text and byte) strings without escaping them and without surrounding them with quotes. For example: .IP .EX $ printf \[aq]\[dq]Hello\[rs]\[rs]nWorld\[dq]\[aq] | jaq \-r Hello World $ printf \[aq]\[dq]Hello\[rs]\[rs]nWorld\[dq]\[aq] | jaq \[dq]Hello\[rs]nWorld\[dq] .EE .PP This does not impact strings contained inside other values, i.e. arrays and objects. For example: .IP .EX $ printf \[aq][\[dq]Hello\[rs]\[rs]nWorld\[dq]]\[aq] | jaq \-rc [\[dq]Hello\[rs]nWorld\[dq]] .EE .PP This is equivalent to \f[B]\f[CB]\-\-to raw\f[B]\f[R]. .SS \f[B]\f[CB]\-\-raw\-output0\f[B]\f[R] Output values like \f[B]\f[CB]\-\-raw\-output\f[B]\f[R], terminating them with NUL (\f[B]\f[CB]\[rs]0\f[B]\f[R]) instead of LF (\f[B]\f[CB]\[rs]n\f[B]\f[R]). .IP .EX $ printf \[aq]\[dq]some string\[rs]\[rs]nwith a newline\[dq] true\[aq] | jaq \-\-raw\-output0 | jaq \-s \-\-raw\-input tobytes b\[dq]some string\[rs]nwith a newline\[rs]x00true\[rs]x00\[dq] .EE .PP Any output value that is a string containing NUL produces an error. Note that this does not apply to strings contained in an array or an object. .IP .EX $ printf \[aq]\[dq]string with NUL \[rs]\[rs]u0000\[dq]\[aq] | jaq \-\-raw\-output0 2>/dev/null; echo $? 2 .EE .PP This is equivalent to \f[B]\f[CB]\-\-to raw0\f[B]\f[R]. .SS \f[B]\f[CB]\-j\f[B]\f[R], \f[B]\f[CB]\-\-join\-output\f[B]\f[R] Do not print a newline after each value. For example: .IP .EX $ echo true false | jaq \-j && echo \[dq] (no new line at end)\[dq] truefalse (no new line at end) .EE .PP This is particularly useful in combination with \f[B]\f[CB]\-\-raw\-output\f[B]\f[R] (\f[B]\f[CB]\-r\f[B]\f[R]); for example: .IP .EX $ printf \[aq]\[dq]Hello\[dq] \[dq] \[dq] \[dq]World\[dq] \[dq]\[rs]\[rs]n\[dq]\[aq] | jaq \-jr Hello World .EE .SS \f[B]\f[CB]\-i\f[B]\f[R], \f[B]\f[CB]\-\-in\-place\f[B]\f[R] Overwrite input file with its output. For example: .IP .EX $ echo 1 > tmp.json && jaq \-i \[aq].+1\[aq] tmp.json && cat tmp.json && rm tmp.json 2 .EE .PP This reads the file \f[B]\f[CB]tmp.json\f[B]\f[R] and overwrites it with the output of the filter \f[B]\f[CB].+1\f[B]\f[R]. Note that the input file is overwritten only once there is no more output and if there has not been any error. .TP \f[I]Compatibility\f[R] \f[B]\f[CB]jq\f[B]\f[R] does not have this option. .TP \f[I]Advanced\f[R] By default, this option disables colored output. However, when forcing colors with \f[B]\f[CB]\-C\f[B]\f[R], jaq respects this wish: .IP .EX $ echo [] > tmp.json $ jaq \-i . tmp.json && jaq \-R tobytes tmp.json b\[dq][]\[dq] $ jaq \-i \-C . tmp.json && jaq \-R tobytes tmp.json b\[dq]\[rs]x1b[1;39m[\[rs]x1b[0m\[rs]x1b[1;39m]\[rs]x1b[0m\[dq] $ rm tmp.json .EE .SS \f[B]\f[CB]\-S\f[B]\f[R], \f[B]\f[CB]\-\-sort\-keys\f[B]\f[R] Print objects sorted by their keys. For example: .IP .EX $ echo \[aq]{\[dq]b\[dq]: {\[dq]d\[dq]: 3, \[dq]c\[dq]: 2}, \[dq]a\[dq]: 1}\[aq] | jaq \-cS {\[dq]a\[dq]:1,\[dq]b\[dq]:{\[dq]c\[dq]:2,\[dq]d\[dq]:3}} $ echo \[aq]{\[dq]b\[dq]: {\[dq]d\[dq]: 3, \[dq]c\[dq]: 2}, \[dq]a\[dq]: 1}\[aq] | jaq \-c {\[dq]b\[dq]:{\[dq]d\[dq]:3,\[dq]c\[dq]:2},\[dq]a\[dq]:1} .EE .SS \f[B]\f[CB]\-C\f[B]\f[R], \f[B]\f[CB]\-\-color\-output\f[B]\f[R] Always color output, even if jaq does not print to a terminal. For example: .IP .EX $ echo {} | jaq \-C | jaq \-\-from raw tobytes b\[dq]\[rs]x1b[1;39m{\[rs]x1b[0m\[rs]x1b[1;39m}\[rs]x1b[0m\[dq] $ echo {} | jaq | jaq \-\-from raw tobytes b\[dq]{}\[dq] .EE .PP (Here, \f[B]\f[CB]jaq \-\-from raw tobytes\f[B]\f[R] prints a byte representation of its input, which contains ANSI color sequences in case of \f[B]\f[CB]\-C\f[B]\f[R].) .SS \f[B]\f[CB]\-M\f[B]\f[R], \f[B]\f[CB]\-\-monochrome\-output\f[B]\f[R] Do not color output. .SS \f[B]\f[CB]\-\-tab\f[B]\f[R] Use tabs for indentation rather than spaces. .PP For example: .IP .EX $ echo [1, [2]] | jaq \-\-tab | jaq \-Rs \[dq][\[rs]n\[rs]t1,\[rs]n\[rs]t[\[rs]n\[rs]t\[rs]t2\[rs]n\[rs]t]\[rs]n]\[rs]n\[dq] $ echo [1, [2]] | jaq | jaq \-Rs \[dq][\[rs]n 1,\[rs]n [\[rs]n 2\[rs]n ]\[rs]n]\[rs]n\[dq] .EE .SS \f[B]\f[CB]\-\-indent\f[B]\f[R] \f[I]N\f[R] Use \f[I]N\f[R] spaces for indentation (default: 2). .SS \f[B]\f[CB]NO_COLOR\f[B]\f[R] If the environment variable \f[B]\f[CB]NO_COLOR\f[B]\f[R] is set to a non\-empty value, then jaq prints no colors, unless the \f[B]\f[CB]\-C\f[B]\f[R] flag is used. .SS \f[B]\f[CB]JQ_COLORS\f[B]\f[R] The environment variable \f[B]\f[CB]JQ_COLORS\f[B]\f[R] is a colon\-separated list, where each entry gives a style to be used for printing some type of values. The entries of \f[B]\f[CB]JQ_COLORS\f[B]\f[R] are mapped in the following order to types of values: .IP \[bu] 2 \f[B]\f[CB]null\f[B]\f[R] .IP \[bu] 2 \f[B]\f[CB]false\f[B]\f[R] .IP \[bu] 2 \f[B]\f[CB]true\f[B]\f[R] .IP \[bu] 2 numbers .IP \[bu] 2 strings .IP \[bu] 2 arrays .IP \[bu] 2 objects .IP \[bu] 2 object keys .PP If \f[B]\f[CB]JQ_COLORS\f[B]\f[R] is not set, then it is assumed to be \f[B]\f[CB]90:39:39:39:32:1;39:1;39:1;34\f[B]\f[R]. That means that by default: .IP \[bu] 2 \f[B]\f[CB]null\f[B]\f[R] has the style \f[B]\f[CB]90\f[B]\f[R] (gray foreground color). .IP \[bu] 2 \f[B]\f[CB]false\f[B]\f[R]/\f[B]\f[CB]true\f[B]\f[R]/numbers have the style \f[B]\f[CB]39\f[B]\f[R] (default foreground color). .IP \[bu] 2 Strings have the style \f[B]\f[CB]32\f[B]\f[R] (green foreground color). .IP \[bu] 2 Arrays/objects have the style \f[B]\f[CB]1;39\f[B]\f[R] (bold and default foreground color). .IP \[bu] 2 Object keys have the style \f[B]\f[CB]1;34\f[B]\f[R] (bold and blue foreground color). .PP Each non\-empty entry of \f[B]\f[CB]JQ_COLORS\f[B]\f[R], such as \f[B]\f[CB]90\f[B]\f[R] or \f[B]\f[CB]1;39\f[B]\f[R], is turned into a \c .UR https://en.wikipedia.org/wiki/ANSI_escape_code#Select_Graphic_Rendition_parameters \[lq]Select Graphic Rendition\[rq] .UE \c \ (SGR) control sequence. For example: .IP \[bu] 2 \f[B]\f[CB]32\f[B]\f[R] is turned into \f[B]\f[CB]\[rs]x1b[32m\f[B]\f[R]. .IP \[bu] 2 \f[B]\f[CB]1;39\f[B]\f[R] is turned into \f[B]\f[CB]\[rs]x1b[1;39m\f[B]\f[R]. .PP jaq does not allow changing the color of byte strings, because jq does not provide any facilities to do that. .SS COMPILATION If no \f[I]FILTER\f[R] is given, jaq uses \f[B]\f[CB].\f[B]\f[R] (the identity filter) as filter. .PP When passing filters directly as \f[I]FILTER\f[R] argument on the command\-line, care has to be taken to properly escape the filter. How to do this depends from platform to platform, but on Unixoid systems, surrounding the filter with single quotes (\f[B]\f[CB]\[aq]\f[B]\f[R]) and replacing occurrences of \f[B]\f[CB]\[aq]\f[B]\f[R] in filters by \f[B]\f[CB]\[aq]\[rs]\[aq]\[aq]\f[B]\f[R] suffices. For example, to run the filter \f[B]\f[CB]\[dq]\[aq]\[dq]\f[B]\f[R] that produces a string containing a single quote, you can use: .IP .EX $ jaq \-n \[aq]\[dq]\[aq]\[rs]\[aq]\[aq]\[dq]\[aq] \[dq]\[aq]\[dq] .EE .PP Running filters that start with the negation operator, such as \f[B]\f[CB]jaq \[aq]\-1\[aq]\f[B]\f[R], fails because \f[B]\f[CB]\-\f[B]\f[R] is interpreted as start of a command\-line switch rather than negation. You can remedy this by using \f[B]\f[CB]\-\-\f[B]\f[R] or by surrounding the filter in parentheses: .IP .EX $ jaq \-n \-\- \[aq]\-1\[aq] \-1 $ jaq \-n \[aq](\-1)\[aq] \-1 .EE .SS \f[B]\f[CB]\-f\f[B]\f[R], \f[B]\f[CB]\-\-from\-file\f[B]\f[R] Read filter from a file given by filter argument. .PP With this option, jaq interprets the \f[I]FILTER\f[R] argument as name of a file containing the filter. Note that the file name may not directly succeed this option. For example: .IP .EX $ echo \[aq]2 * 21\[aq] > tmp.jq && jaq \-\-from\-file \-n tmp.jq && rm tmp.jq 42 .EE .SS \f[B]\f[CB]\-L\f[B]\f[R], \f[B]\f[CB]\-\-library\-path\f[B]\f[R] \f[I]DIR\f[R] Search for modules and data in given directory. .PP jaq searches for modules and data in a set of directories called \[lq]search paths\[rq]. Using \f[B]\f[CB]\-\-library\-path\f[B]\f[R] adds a new directory to the global search paths. .PP For example, \f[B]\f[CB]jaq \-L . \-L .. \[aq]include \[dq]script\[dq]; foo\[aq]\f[B]\f[R] looks for \f[B]\f[CB]script.jq\f[B]\f[R] first in the current directory, then in the parent directory. .PP If \f[B]\f[CB]\-\-library\-path\f[B]\f[R] is not given, the following global search paths are used: .IP \[bu] 2 \f[B]\f[CB]\[ti]/.jq\f[B]\f[R] .IP \[bu] 2 \f[B]\f[CB]$ORIGIN/../lib/jq\f[B]\f[R] .IP \[bu] 2 \f[B]\f[CB]$ORIGIN/../lib\f[B]\f[R] .PP See the modules section for more details. .SS VARIABLES .SS \f[B]\f[CB]\-\-arg\f[B]\f[R] \f[I]A\f[R] \f[I]V\f[R] Set variable \f[B]\f[CB]$A\f[B]\f[R] to string \f[I]V\f[R]. .PP For example: .IP .EX $ jaq \-\-arg name \[dq]John Doe\[dq] \-n \[aq]\[dq]Welcome, \[dq] + $name\[aq] \[dq]Welcome, John Doe\[dq] .EE .SS \f[B]\f[CB]\-\-argjson\f[B]\f[R] \f[I]A\f[R] \f[I]V\f[R] Set variable \f[B]\f[CB]$A\f[B]\f[R] to JSON value \f[I]V\f[R]. .PP For example: .IP .EX $ jaq \-\-argjson song \[aq]{\[dq]name\[dq]: \[dq]One of Us\[dq], \[dq]artist\[dq]: \[dq]ABBA\[dq], \[dq]year\[dq]: 1981}\[aq] \-n \[rs] \[aq]\[dq]Currently playing: \[rs]($song.name) (\[rs]($song.year))\[dq]\[aq] \[dq]Currently playing: One of Us (1981)\[dq] .EE .PP If \f[I]V\f[R] contains more than a single value, e.g. \f[B]\f[CB]1 2\f[B]\f[R], then jaq yields an error. .SS \f[B]\f[CB]\-\-slurpfile\f[B]\f[R] \f[I]A\f[R] \f[I]F\f[R] Set variable \f[B]\f[CB]$A\f[B]\f[R] to array containing the JSON values in file \f[I]F\f[R]. .PP For example: .IP .EX $ echo 1 2 3 > tmp.json && jaq \-\-slurpfile xs tmp.json \-cn \[aq]$xs\[aq] && rm tmp.json [1,2,3] .EE .SS \f[B]\f[CB]\-\-rawfile\f[B]\f[R] \f[I]A\f[R] \f[I]F\f[R] Set variable \f[B]\f[CB]$A\f[B]\f[R] to string containing the contents of file \f[I]F\f[R]. .PP jaq tries to load the file via memory mapping, taking constant time and allowing to load files that do not fit into memory. If this fails, jaq loads the file regularly, taking linear time. This is also what happens when using \f[B]\f[CB]\-Rs\f[B]\f[R] (\f[B]\f[CB]\-\-raw\-input\f[B]\f[R] and \f[B]\f[CB]\-\-slurp\f[B]\f[R]) to load a file (as opposed to standard input). .TP \f[I]Compatibility\f[R] Unlike \f[B]\f[CB]jq\f[B]\f[R], jaq does not verify that the file is valid UTF\-8. That permits loading arbitrary binary files; these can be processed as byte strings via \f[B]\f[CB]tobytes\f[B]\f[R]. .SS \f[B]\f[CB]\-\-args\f[B]\f[R] Collect remaining positional arguments into \f[B]\f[CB]$ARGS.positional\f[B]\f[R]. .PP If this option is given, then all further arguments that would have been interpreted as input files are instead collected into an array at \f[B]\f[CB]$ARGS.positional\f[B]\f[R]. .PP For example: .IP .EX $ touch tmp.json && jaq \[aq]$ARGS.positional\[aq] tmp.json \-\-args foo \-nc bar \-\- baz \-j qux && rm tmp.json [\[dq]foo\[dq],\[dq]bar\[dq],\[dq]baz\[dq],\[dq]\-j\[dq],\[dq]qux\[dq]] .EE .PP Note that here, \f[B]\f[CB]tmp.json\f[B]\f[R] and \f[B]\f[CB]\-nc\f[B]\f[R] are \f[B]not\f[R] collected into the array \[em] the former because it comes \f[B]before\f[R] \f[B]\f[CB]\-\-args\f[B]\f[R], and the latter because it would not have been interpreted as input file. However, \f[B]\f[CB]\-j\f[B]\f[R] is collected into the array because it comes after \f[B]\f[CB]\-\-\f[B]\f[R], which leads every argument after it to be interpreted as input file. .SS MISCELLANEA .SS \f[B]\f[CB]\-e\f[B]\f[R], \f[B]\f[CB]\-\-exit\-status\f[B]\f[R] Use the last output value as exit status code. .PP This enables the use of the exit codes 1 and 4, which are not used otherwise. .PP jaq uses the following exit codes: .IP \[bu] 2 0: No errors. .IP \[bu] 2 1: The last output value is \f[B]\f[CB]false\f[B]\f[R] or \f[B]\f[CB]null\f[B]\f[R]. .IP \[bu] 2 2: I/O or CLI error, e.g. file not found or unknown CLI option. .IP \[bu] 2 3: Filter parse/compilation error. .IP \[bu] 2 4: The filter did not yield any output. .IP \[bu] 2 5: Any other error, e.g. call to the filter \f[B]\f[CB]error\f[B]\f[R]. .PP The filters \f[B]\f[CB]halt\f[B]\f[R] and \f[B]\f[CB]halt_error\f[B]\f[R] can be used to exit jaq with arbitrary exit codes. .PP For example: .IP .EX $ jaq \-n empty; echo $? 0 $ jaq \-n false >/dev/null; echo $? 0 $ jaq \-en false >/dev/null; echo $? 1 $ jaq . does_not_exist.json 2>/dev/null; echo $? 2 $ jaq \-\-foo 2>/dev/null; echo $? 2 $ jaq \[aq]+\[aq] 2>/dev/null; echo $? 3 $ jaq \-en empty; echo $? 4 $ jaq \-n error 2>/dev/null; echo $? 5 $ jaq \-n \[aq]halt(9)\[aq]; echo $? 9 .EE .SS \f[B]\f[CB]\-h\f[B]\f[R], \f[B]\f[CB]\-\-help\f[B]\f[R] Print summary of CLI options. .SS \f[B]\f[CB]\-V\f[B]\f[R], \f[B]\f[CB]\-\-version\f[B]\f[R] Print jaq version. .SS UNSUPPORTED The following command\-line options are supported by \f[B]\f[CB]jq\f[B]\f[R], but not by jaq: .IP \[bu] 2 \f[B]\f[CB]\-\-ascii\-output\f[B]\f[R], \f[B]\f[CB]\-a\f[B]\f[R] .IP \[bu] 2 \f[B]\f[CB]\-\-unbuffered\f[B]\f[R] .IP \[bu] 2 \f[B]\f[CB]\-\-stream\f[B]\f[R] .IP \[bu] 2 \f[B]\f[CB]\-\-stream\-errors\f[B]\f[R] .IP \[bu] 2 \f[B]\f[CB]\-\-seq\f[B]\f[R] .IP \[bu] 2 \f[B]\f[CB]\-\-jsonargs\f[B]\f[R] .SH CORE LANGUAGE The jq language is a lazy, functional streaming programming language originally designed by Stephen Dolan. The jq language is Turing\-complete and can therefore be used to write any program that can be written in any other programming language. jq programs can be executed with several interpreters, including \f[B]\f[CB]jq\f[B]\f[R], \f[B]\f[CB]gojq\f[B]\f[R], \f[B]\f[CB]fq\f[B]\f[R], and \f[B]\f[CB]jaq\f[B]\f[R]. .PP A program written in the jq language is called a jq program or \f[I]filter\f[R]. A filter is a function that takes an input value and yields a stream of output values. By convention, we write \f[B]\f[CB]f\f[B]\f[R] and \f[B]\f[CB]g\f[B]\f[R] to denote arbitrary filters. .PP The stream of output values can be infinite; for example, the jq filter \f[B]\f[CB]repeat(\[dq]Hi\[dq])\f[B]\f[R] yields an infinite sequence of strings \f[B]\f[CB]\[dq]Hi\[dq]\f[B]\f[R]. .PP The following sections document all filters with built\-in syntax in jq. Examples are written like \f[B]\f[CB]1 + 2, true or false \-\-> 3 true\f[B]\f[R], which is equivalent to: .IP .EX $ jaq \-n \[aq]1 + 2, true or false\[aq] 3 true .EE .PP An \f[B]atomic\f[R] filter is a filter that is \f[I]not\f[R] a binary operator. For example, the filters \f[B]\f[CB]\-1\f[B]\f[R], \f[B]\f[CB]map(.+1)\f[B]\f[R], and \f[B]\f[CB].[0]\f[B]\f[R] are all atomic, whereas the filters \f[B]\f[CB]1 + 2\f[B]\f[R], \f[B]\f[CB]explode | .[]\f[B]\f[R], and \f[B]\f[CB].[0] += 1\f[B]\f[R] are all non\-atomic. To turn a non\-atomic filter \f[B]\f[CB]f\f[B]\f[R] into an equivalent atomic filter, surround it with parentheses, i.e. \f[B]\f[CB](f)\f[B]\f[R]. .SS VALUES This section lists all potential values that jq filters can process, and how to produce them. .TP \f[I]Compatibility\f[R] jaq extends the set of values that jq can process by byte strings and objects with non\-string values. Where jq reads and writes values by default as JSON, jaq reads and writes values by default as XJON, which is an extension of JSON. See those sections for how jaq serialises values. .SS \f[B]\f[CB]null\f[B]\f[R] The filter \f[B]\f[CB]null\f[B]\f[R] returns the \f[B]\f[CB]null\f[B]\f[R] value. .PP The \f[B]\f[CB]null\f[B]\f[R] value can be also obtained in various other ways, such as indexing a non\-existing key in an array or object, e.g. \f[B]\f[CB][] | .[0] \-\-> null\f[B]\f[R] or \f[B]\f[CB]{} | .a \-\-> null\f[B]\f[R]. .SS Booleans The filters \f[B]\f[CB]true\f[B]\f[R] and \f[B]\f[CB]false\f[B]\f[R] return the boolean values \f[B]\f[CB]true\f[B]\f[R] and \f[B]\f[CB]false\f[B]\f[R]. Booleans can also be produced by comparison operations, e.g. \f[B]\f[CB]0 == 0 \-\-> true\f[B]\f[R] or \f[B]\f[CB][] == {} \-\-> false\f[B]\f[R]. .PP Every jq value can be mapped to a \f[B]boolean value\f[R], namely \f[B]\f[CB]null\f[B]\f[R] and \f[B]\f[CB]false\f[B]\f[R] have the boolean value \f[B]\f[CB]false\f[B]\f[R], all other values have the boolean value \f[B]\f[CB]true\f[B]\f[R]. This is important for filters such as \f[B]\f[CB]if\-then\-else\f[B]\f[R] and \f[B]\f[CB]//\f[B]\f[R]. .TP \f[I]Advanced\f[R] You can get the boolean value of a value by \f[B]\f[CB]not | not\f[B]\f[R]; i.e. \f[B]\f[CB]\[dq]\[dq] | not | not \-\-> true\f[B]\f[R]. .SS Numbers Numbers are filters that return their corresponding value, e.g. \f[B]\f[CB]0 \-\-> 0\f[B]\f[R], \f[B]\f[CB]3.14 \-\-> 3.14\f[B]\f[R], and \f[B]\f[CB]2.99e6 \-\-> 2.99e6\f[B]\f[R]. Negative numbers can be constructed by applying the negation operator to a number, e.g. \f[B]\f[CB]\-1 \-\-> \-1\f[B]\f[R]. .PP Internally, jaq distinguishes integers, floating\-point numbers (floats), and decimal numbers: .IP \[bu] 2 A number without a dot (\f[B]\f[CB].\f[B]\f[R]) and without an exponent (\f[B]\f[CB]e\f[B]\f[R]/\f[B]\f[CB]E\f[B]\f[R]) is losslessly stored as integer. jaq can store and calculate with integers of arbitrary size, e.g. \f[B]\f[CB]340282366920938463463374607431768211456\f[B]\f[R] (\f[B]\f[CB]2\[ha]128\f[B]\f[R]). .IP \[bu] 2 Any non\-integer number is stored initially as decimal number, which is a string representation of the number. That means that jaq losslessly preserves any number corresponding to the regular expression above, such as \f[B]\f[CB]1.0e500\f[B]\f[R], if it occurs in a JSON file or jq filter. .IP \[bu] 2 When calculating with a decimal number, jaq converts it transparently to a 64\-bit \c .UR https://en.wikipedia.org/wiki/IEEE_754 IEEE\-754 .UE \c floating\-point number. For example, \f[B]\f[CB]1.0e500 + 1 \-\-> Infinity\f[B]\f[R], because jaq converts \f[B]\f[CB]1.0e500\f[B]\f[R] to the closest floating\-point number, which is \f[B]\f[CB]Infinity\f[B]\f[R]. .PP The rules of jaq are: .IP \[bu] 2 The sum, difference, product, and remainder of two integers is integer, e.g. \f[B]\f[CB]1 + 2 \-\-> 3\f[B]\f[R]. .IP \[bu] 2 Any other operation between two numbers yields a float, e.g. \f[B]\f[CB]10 / 2 \-\-> 5.0\f[B]\f[R] and \f[B]\f[CB]1.0 + 2 \-\-> 3.0\f[B]\f[R]. .PP You can convert an integer to a floating\-point number e.g. by adding 0.0, by multiplying with 1.0, or by dividing with 1. You can convert a floating\-point number to an integer by \f[B]\f[CB]round\f[B]\f[R], \f[B]\f[CB]floor\f[B]\f[R], or \f[B]\f[CB]ceil\f[B]\f[R], e.g. \f[B]\f[CB]1.2 | floor, round, ceil \-\-> 1 1 2\f[B]\f[R]. .TP \f[I]Compatibility\f[R] \f[B]\f[CB]jq\f[B]\f[R] uses floats for any number, meaning that it does not distinguish integers from floats. Many operations in jaq, such as array indexing, check whether the passed numbers are indeed integer. The motivation behind this is to avoid rounding errors that may silently lead to wrong results. For example, \f[B]\f[CB][0, 1, 2] | .[1] \-\-> 1\f[B]\f[R], whereas \f[B]\f[CB][0, 1, 2] | .[1.0000000000000001]\f[B]\f[R] yields an error in jaq as opposed to \f[B]\f[CB]1\f[B]\f[R] in \f[B]\f[CB]jq\f[B]\f[R]. Furthermore, \f[B]\f[CB]jq\f[B]\f[R] prints NaN as \f[B]\f[CB]null\f[B]\f[R]; e.g. \f[B]\f[CB]nan | tojson\f[B]\f[R] yields \f[B]\f[CB]null\f[B]\f[R]. In contrast, jaq prints NaN as \f[B]\f[CB]NaN\f[B]\f[R]; e.g. \f[B]\f[CB]nan | tojson \-\-> \[dq]NaN\[dq]\f[B]\f[R]. See the XJON section for details. .TP \f[I]Advanced\f[R] A number corresponds to the regular expression \f[B]\f[CB][0\-9]+(\[rs].[0\-9]+)?([eE][+\-]?[0\-9]+)?\f[B]\f[R]. .SS Text strings A text string is an array of bytes that can be constructed using the syntax \f[B]\f[CB]\[dq]...\[dq]\f[B]\f[R]. Here, \f[B]\f[CB]...\f[B]\f[R] may contain any UTF\-8 characters in the range from \f[B]\f[CB]U+0020\f[B]\f[R] to \f[B]\f[CB]U+10FFFF\f[B]\f[R], excluding \f[B]\f[CB]\[aq]\[dq]\[aq]\f[B]\f[R] and \f[B]\f[CB]\[aq]\[rs]\[aq]\f[B]\f[R]. For example, \f[B]\f[CB]\[dq]Hello 東京!\[dq] \-\-> \[dq]Hello 東京!\[dq]\f[B]\f[R]. .PP Furthermore, \f[B]\f[CB]...\f[B]\f[R] may contain the following escape sequences: .IP \[bu] 2 \f[B]\f[CB]\[rs]b\f[B]\f[R], \f[B]\f[CB]\[rs]f\f[B]\f[R], \f[B]\f[CB]\[rs]n\f[B]\f[R], \f[B]\f[CB]\[rs]r\f[B]\f[R], or \f[B]\f[CB]\[rs]t\f[B]\f[R] .IP \[bu] 2 \f[B]\f[CB]\[rs]\[dq]\f[B]\f[R] or \f[B]\f[CB]\[rs]\[rs]\f[B]\f[R] .IP \[bu] 2 \f[B]\f[CB]\[rs]uHHHH\f[B]\f[R], where \f[B]\f[CB]HHHH\f[B]\f[R] is a hexadecimal number .IP \[bu] 2 \f[B]\f[CB]\[rs](f)\f[B]\f[R], where \f[B]\f[CB]f\f[B]\f[R] is a jq filter (\f[B]string interpolation\f[R]) .PP Most characters below \f[B]\f[CB]U+0020\f[B]\f[R] can only be produced via a Unicode escape sequence, i.e. \f[B]\f[CB]\[dq]NUL = \[rs]u0000\[dq] \-\-> \[dq]NUL = \[rs]u0000\[dq]\f[B]\f[R]. .PP A string containing an interpolated filter, such as \f[B]\f[CB]\[dq]...\[rs](f)...\[dq]\f[B]\f[R], is equivalent to \f[B]\f[CB]\[dq]...\[dq] + (f | tostring) + \[dq]...\[dq]\f[B]\f[R]. For example: .IP \[bu] 2 \f[B]\f[CB]\[dq]Hello \[rs](\[dq]Alice\[dq], \[dq]Bob\[dq]) 😀!\[rs]n\[dq] \-\-> \[dq]Hello Alice 😀!\[rs]n\[dq] \[dq]Hello Bob 😀!\[rs]n\[dq]\f[B]\f[R] .IP \[bu] 2 \f[B]\f[CB]41 | \[dq]The successor of \[rs](.) is \[rs](.+1).\[dq] \-\-> \[dq]The successor of 41 is 42.\[dq]\f[B]\f[R]. .PP A string is \f[B]identifier\-like\f[R] if it matches the regular expression \f[B]\f[CB][a\-zA\-Z_][a\-zA\-Z_0\-9]*\f[B]\f[R]. .PP Strings may be prefixed with \f[B]\f[CB]\[at]x\f[B]\f[R], where \f[B]\f[CB]x\f[B]\f[R] is an identifier; e.g. \f[B]\f[CB]\[at]uri\f[B]\f[R]. In such a case, the filters of interpolated strings are piped through \f[B]\f[CB]\[at]x\f[B]\f[R] instead of \f[B]\f[CB]tostring\f[B]\f[R], i.e. \f[B]\f[CB]\[at]x \[dq]...\[rs](f)...\[dq]\f[B]\f[R] is equivalent to \f[B]\f[CB]\[at]x \[dq]...\[dq] + (f | \[at]x) + \[at]x \[dq]...\[dq]\f[B]\f[R]. When \f[B]\f[CB]\[dq]...\[dq]\f[B]\f[R] does not contain any interpolated filter, then \f[B]\f[CB]\[at]x \[dq]...\[dq]\f[B]\f[R] is equivalent to \f[B]\f[CB]\[dq]...\[dq]\f[B]\f[R]. For example, \f[B]\f[CB]\[dq]\-[]?\[dq] | \[at]uri \[dq]https://gedenkt.at/jaq/?q=\[rs](.)\[dq] \-\-> \[dq]https://gedenkt.at/jaq/?q=\-%5B%5D%3F\[dq]\f[B]\f[R]. .SS Byte strings A byte string is an array of bytes that is \f[B]not\f[R] interpreted as (UTF\-8) text. It can be produced from a text string via the filter \f[B]\f[CB]tobytes\f[B]\f[R], e.g. \f[B]\f[CB]\[dq]Hello, world! 🙂\[dq] | tobytes \-\-> b\[dq]Hello, world! \[rs]xf0\[rs]x9f\[rs]x99\[rs]x82\[dq]\f[B]\f[R]. Currently, there is no native syntax in jaq to produce a byte string directly. .PP Byte strings differ from text strings in a few regards; in particular, they can be indexed and sliced in constant time. That makes byte strings interesting e.g. for parsing binary formats. .PP For compatibility reasons, jaq considers both text strings and byte strings as strings. That means that \f[B]\f[CB]\[dq]Hello\[dq] | isstring and (tobytes | isstring) \-\-> true\f[B]\f[R]. Furthermore, a text string and a byte string that contain equivalent bytes are considered equal, e.g. \f[B]\f[CB]\[dq]Hello\[dq] | . == tobytes \-\-> true\f[B]\f[R]. .TP \f[I]Compatibility\f[R] Byte strings do not exist in \f[B]\f[CB]jq\f[B]\f[R]; however, they exist in \f[B]\f[CB]fq\f[B]\f[R]. .TP \f[I]Advanced\f[R] To find out whether a value is a byte string, we can use: .IP .EX def isbytes: isstring and try (.[0] | true) catch false; \[dq]Hello\[dq] | ., tobytes | isbytes \-\-> false true .EE This works because we can index byte strings, but not text strings. .SS Arrays An array is a finite sequence of values. .PP An empty array can be constructed with the filter \f[B]\f[CB][]\f[B]\f[R], which is a short form for \f[B]\f[CB][empty] \-\-> []\f[B]\f[R]. An array of values can be constructed using the syntax \f[B]\f[CB][f]\f[B]\f[R], where \f[B]\f[CB]f\f[B]\f[R] is a filter. The filter \f[B]\f[CB][f]\f[B]\f[R] passes its input to \f[B]\f[CB]f\f[B]\f[R] and runs it, returning an array containing all outputs of \f[B]\f[CB]f\f[B]\f[R]. If \f[B]\f[CB]f\f[B]\f[R] throws an error, then \f[B]\f[CB][f]\f[B]\f[R] returns that error instead of an array. .PP This syntax allows constructing arrays such as \f[B]\f[CB][1, 2, 3] \-\-> [1, 2, 3]\f[B]\f[R]. Here, \f[B]\f[CB]1, 2, 3\f[B]\f[R] is just a filter that yields three numbers, see concatenation. There is no dedicated array syntax \f[B]\f[CB][x1, ..., xn]\f[B]\f[R]. That means that you can use arbitrary filters in \f[B]\f[CB][f]\f[B]\f[R]; for example, \f[B]\f[CB][limit(3; repeat(0))] \-\-> [0, 0, 0]\f[B]\f[R]. You can use the input passed to \f[B]\f[CB][f]\f[B]\f[R] inside \f[B]\f[CB]f\f[B]\f[R]; for example, we can write the previous filter equivalently as \f[B]\f[CB]{count: 3, elem: 0} | [limit(.count; repeat(.elem))] \-\-> [0, 0, 0]\f[B]\f[R]. .SS Objects An object is a mapping from keys to values. .PP An empty object can be constructed with the filter \f[B]\f[CB]{}\f[B]\f[R]. An object with a single key and value can be constructed by \f[B]\f[CB]{(k): v}\f[B]\f[R], where \f[B]\f[CB]k\f[B]\f[R] and \f[B]\f[CB]v\f[B]\f[R] are both filters. For example, \f[B]\f[CB]{(\[dq]a\[dq]): 1} \-\-> {\[dq]a\[dq]: 1}\f[B]\f[R]. .PP If \f[B]\f[CB]k\f[B]\f[R] is a string such as \f[B]\f[CB]\[dq]a\[dq]\f[B]\f[R] or a variable such as \f[B]\f[CB]$k\f[B]\f[R], then you can omit the parentheses, e.g. \f[B]\f[CB]{\[dq]a\[dq]: 1}\f[B]\f[R] or \f[B]\f[CB]{$k: 1}\f[B]\f[R]. If the string is identifier\-like, then you can also omit the quotes, e.g. \f[B]\f[CB]{a: 1}\f[B]\f[R]. .PP To construct an object with multiple key\-value pairs, you can add multiple objects; e.g. \f[B]\f[CB]{(k1): v1} + ... + {(kn): vn}\f[B]\f[R]. You can write this more compactly as \f[B]\f[CB]{(k1): v1, ..., (kn): vn}\f[B]\f[R]. For example, \f[B]\f[CB]{a: 1, b: 2} \-\-> {\[dq]a\[dq]: 1, \[dq]b\[dq]: 2}\f[B]\f[R]. .PP Instead of \f[B]\f[CB]{k: .k}\f[B]\f[R] (see indexing), you can also write \f[B]\f[CB]{k}\f[B]\f[R]; e.g., \f[B]\f[CB]{a: 1, b: 2} | {a} \-\-> {\[dq]a\[dq]: 1}\f[B]\f[R]. Instead of \f[B]\f[CB]{k: $k}\f[B]\f[R], you can also write \f[B]\f[CB]{$k}\f[B]\f[R]; e.g., \f[B]\f[CB]1 as $k | {$k} \-\-> {\[dq]k\[dq]: 1}\f[B]\f[R]. .PP The filter \f[B]\f[CB]{(k): v}\f[B]\f[R] is equivalent to \f[B]\f[CB]k as $k | v as $v | {$k: $v}\f[B]\f[R]. That means that when either \f[B]\f[CB]k\f[B]\f[R] or \f[B]\f[CB]v\f[B]\f[R] yield multiple output values, an object is produced for every output combination; for example, \f[B]\f[CB]{(\[dq]a\[dq], \[dq]b\[dq]): (1, 2)} \-\-> {\[dq]a\[dq]: 1} {\[dq]a\[dq]: 2} {\[dq]b\[dq]: 1} {\[dq]b\[dq]: 2}\f[B]\f[R]. Note that here, it is necessary to surround \f[B]\f[CB]1, 2\f[B]\f[R] with parentheses, in order to clarify that \f[B]\f[CB],\f[B]\f[R] does not start a new key\-value pair. .TP \f[I]Compatibility\f[R] In jq, keys must be strings, whereas in jaq, keys can be arbitrary values. Because object keys can be arbitrary values in jaq, you can write e.g.: .IP .EX {(0): 1, \[dq]2\[dq]: 3, ([4]): 5, ({}): 6} \-\-> { 0 : 1, \[dq]2\[dq]: 3, [4] : 5, {} : 6} .EE Note that in a jq filter, non\-string keys must be surrounded with parentheses, whereas in XJON, parentheses must not be used. This yields an error in \f[B]\f[CB]jq\f[B]\f[R]. .SS PATH OPERATORS jq\[cq]s path operators retrieve parts of their input. .SS Indexing (\f[B]\f[CB].[x]\f[B]\f[R]) The indexing operator \f[B]\f[CB].[x]\f[B]\f[R] yields the \f[B]\f[CB]x\f[B]\f[R]\-th element of the input. For example: .IP \[bu] 2 \f[B]\f[CB][1, 2, 3] | .[1] \-\-> 2\f[B]\f[R] .IP \[bu] 2 \f[B]\f[CB]{a: 1, b: 2} | .[\[dq]a\[dq]] \-\-> 1\f[B]\f[R] .PP If there is no element at the index \f[B]\f[CB]x\f[B]\f[R] in the input, then this operator returns \f[B]\f[CB]null\f[B]\f[R]. For example: .IP \[bu] 2 \f[B]\f[CB][1, 2, 3] | .[3] \-\-> null\f[B]\f[R] .IP \[bu] 2 \f[B]\f[CB]{a: 1, b: 2} | .[\[dq]c\[dq]] \-\-> null\f[B]\f[R] .IP \[bu] 2 \f[B]\f[CB]null | .[0] \-\-> null\f[B]\f[R] .PP This operator treats byte string input like an array of numbers in the range 0..256. For example, \f[B]\f[CB]\[dq]\[at]ABC\[dq] | tobytes | .[0] \-\-> 64\f[B]\f[R], because the character \f[B]\f[CB]\[aq]\[at]\[aq]\f[B]\f[R] is encoded in UTF\-8 as single byte \f[B]\f[CB]64\f[B]\f[R] (\f[B]\f[CB]0x40\f[B]\f[R]). .PP For identifier\-like strings like \f[B]\f[CB]name\f[B]\f[R], you can write \f[B]\f[CB].name\f[B]\f[R] as short form for \f[B]\f[CB].[\[dq]name\[dq]]\f[B]\f[R]. For example, \f[B]\f[CB]{a: 1} | .a \-\-> 1\f[B]\f[R]. This works also for strings that are the same as reserved keywords; e.g. \f[B]\f[CB]{if: 1} | .if \-\-> 1\f[B]\f[R]. .PP For array input, you can also use negative numbers as index, which will be interpreted as index counting from the end of the array. For example, \f[B]\f[CB][1, 2, 3] | .[\-1] \-\-> 3\f[B]\f[R]. .PP If the input and the index \f[B]\f[CB]x\f[B]\f[R] are both arrays, then this returns the same as \f[B]\f[CB]indices(x)\f[B]\f[R]. For example, \f[B]\f[CB][1, 2, 0, 1, 2] | .[[1, 2]] \-\-> [0, 3]\f[B]\f[R]. .PP If the input of this operator is an array or a string and the index is an object, then this operator is equivalent to the slicing operator \f[B]\f[CB].[x.start : x.end]\f[B]\f[R]. For example: .IP \[bu] 2 \f[B]\f[CB][1, 2, 3] | .[{start: 1 }] \-\-> [2, 3]\f[B]\f[R] .IP \[bu] 2 \f[B]\f[CB][1, 2, 3] | .[{ end: \-1}] \-\-> [1, 2]\f[B]\f[R] .IP \[bu] 2 \f[B]\f[CB][1, 2, 3] | .[{start: 1, end: \-1}] \-\-> [2]\f[B]\f[R] .IP \[bu] 2 \f[B]\f[CB][1, 2, 3] | .[{ }] \-\-> [1, 2, 3]\f[B]\f[R] .PP This operator yields a value if either: .IP \[bu] 2 the input is a string or an array and the index is an object (slicing), .IP \[bu] 2 the input is a byte string or an array and the index is an integer, .IP \[bu] 2 the input and the index are both arrays, or .IP \[bu] 2 the input is \f[B]\f[CB]null\f[B]\f[R] or an object. .PP Otherwise, it yields an error. .TP \f[I]Compatibility\f[R] \f[B]\f[CB]jq\f[B]\f[R] accepts floating\-point numbers as array indices; e.g. \f[B]\f[CB][1, 2] | .[1.5]\f[B]\f[R] yields \f[B]\f[CB]2\f[B]\f[R]. In jaq, indexing an array with a floating\-point number yields an error. The same applies to the slicing operator below. \f[B]\f[CB]jq\f[B]\f[R] fails when the input is a string or an array and the index is an object that has neither \f[B]\f[CB]start\f[B]\f[R] nor \f[B]\f[CB]end\f[B]\f[R] keys, whereas jaq treats such an object like \f[B]\f[CB]{start: null, end: null}\f[B]\f[R]; that is, it creates a slice from the beginning to the end. .SS Slicing (\f[B]\f[CB].[x:y]\f[B]\f[R]) The slicing operator \f[B]\f[CB].[x:y]\f[B]\f[R] yields a slice of a string or an array, from the \f[B]\f[CB]x\f[B]\f[R]\-th element to (excluding) the \f[B]\f[CB]y\f[B]\f[R]\-th element. For example, \f[B]\f[CB][1, 2, 3] | .[1:3] \-\-> [2, 3]\f[B]\f[R], and \f[B]\f[CB]\[dq]Hello World!\[dq] | .[6:11] \-\-> \[dq]World\[dq]\f[B]\f[R]. .PP When slicing a text string, the \f[B]\f[CB]x\f[B]\f[R]\-th element refers to the \f[B]\f[CB]x\f[B]\f[R]\-th \f[B]UTF\-8 character\f[R]. For example, \f[B]\f[CB]\[dq]老虎\[dq] | .[1:2] \-\-> \[dq]虎\[dq]\f[B]\f[R]. On the other hand, when slicing a byte string, the \f[B]\f[CB]x\f[B]\f[R]\-th element refers to the \f[B]\f[CB]x\f[B]\f[R]\-th \f[B]byte\f[R]. For example, \f[B]\f[CB]\[dq]Färber\[dq] | tobytes, . | .[2:] | [., length] \-\-> [b\[dq]\[rs]xa4rber\[dq], 5] [\[dq]rber\[dq], 4]\f[B]\f[R], because the letter `ä' takes two bytes, but only one character. .PP Like the indexing operator, the slicing operator treats byte string input like an array of numbers and interprets negative indices as indices counting from the end. .PP The short form \f[B]\f[CB].[x:]\f[B]\f[R] creates a slice from the index \f[B]\f[CB]x\f[B]\f[R] to the end, and the short form \f[B]\f[CB].[:y]\f[B]\f[R] creates a slice from the beginning to (excluding) the index \f[B]\f[CB]x\f[B]\f[R]. When \f[B]\f[CB]x\f[B]\f[R] is \f[B]\f[CB]null\f[B]\f[R], it is interpreted as \f[B]\f[CB]0\f[B]\f[R], and when \f[B]\f[CB]y\f[B]\f[R] is \f[B]\f[CB]null\f[B]\f[R], it is interpreted as \f[B]\f[CB]length\f[B]\f[R]. That means that \f[B]\f[CB].[x:]\f[B]\f[R] is equivalent to \f[B]\f[CB].[x:null]\f[B]\f[R] and \f[B]\f[CB].[:y]\f[B]\f[R] is equivalent to \f[B]\f[CB].[null:y]\f[B]\f[R]. For example: .IP \[bu] 2 \f[B]\f[CB]\[dq]Hello World!\[dq] | .[ :5], .[6: ] \-\-> \[dq]Hello\[dq] \[dq]World!\[dq]\f[B]\f[R] .IP \[bu] 2 \f[B]\f[CB]\[dq]Hello World!\[dq] | .[null:5], .[6:null] \-\-> \[dq]Hello\[dq] \[dq]World!\[dq]\f[B]\f[R] .IP \[bu] 2 \f[B]\f[CB]\[dq]Hello World!\[dq] | .[null : null] \-\-> \[dq]Hello World!\[dq]\f[B]\f[R] .PP This operator yields a value if its input is a string or an array, and its indices \f[B]\f[CB]x\f[B]\f[R] and \f[B]\f[CB]y\f[B]\f[R] are either \f[B]\f[CB]null\f[B]\f[R] or integer. Otherwise, it yields an error. For example: .IP \[bu] 2 \f[B]\f[CB][] | try .[\[dq]a\[dq]:] catch \[dq]fail\[dq] \-\-> \[dq]fail\[dq]\f[B]\f[R] .IP \[bu] 2 \f[B]\f[CB]{} | try .[1:\-1] catch \[dq]fail\[dq] \-\-> \[dq]fail\[dq]\f[B]\f[R] .TP \f[I]Compatibility\f[R] jaq fails when trying to slice \f[B]\f[CB]null\f[B]\f[R], i.e. \f[B]\f[CB]null | try .[1:] catch \[dq]fail\[dq] \-\-> \[dq]fail\[dq]\f[B]\f[R], whereas this yields \f[B]\f[CB]null\f[B]\f[R] in \f[B]\f[CB]jq\f[B]\f[R]. .SS Iterating (\f[B]\f[CB].[]\f[B]\f[R]) The iteration operator \f[B]\f[CB].[]\f[B]\f[R] yields all values \f[B]\f[CB]v1 ... vn\f[B]\f[R] when given an array \f[B]\f[CB][v1, ..., vn]\f[B]\f[R] or an object \f[B]\f[CB]{k1: v1, ..., kn: vn}\f[B]\f[R]. For example, \f[B]\f[CB][1, 2, 3] | .[] \-\-> 1 2 3\f[B]\f[R] and \f[B]\f[CB]{a: 1, b: 2} | .[] \-\-> 1 2\f[B]\f[R]. .TP \f[I]Advanced\f[R] It holds that \f[B]\f[CB].[]\f[B]\f[R] has the same effect as \f[B]\f[CB].[keys_unsorted[]]\f[B]\f[R]. For example: .IP \[bu] 2 \f[B]\f[CB][1, 2, 3] | .[keys_unsorted[]] \-\-> 1 2 3\f[B]\f[R] .IP \[bu] 2 \f[B]\f[CB]{a: 1, b: 2} | .[keys_unsorted[]] \-\-> 1 2\f[B]\f[R] .SS Compound paths You can concatenate arbitrarily many path operators to an atomic filter. Such a sequence of path operators is called a \f[I]compound path\f[R]. For example, you can write \f[B]\f[CB]explode.[]\f[B]\f[R] as short form for \f[B]\f[CB]explode | .[]\f[B]\f[R]. .PP If the leading atomic filter is \f[B]\f[CB].\f[B]\f[R] (identity), you can omit it. For example, the following filters are all equivalent: .IP \[bu] 2 \f[B]\f[CB]{a: [{b: 1}]} | . | .a | .[] | .b \-\-> 1\f[B]\f[R] .IP \[bu] 2 \f[B]\f[CB]{a: [{b: 1}]} | . .a .[] .b \-\-> 1\f[B]\f[R] .IP \[bu] 2 \f[B]\f[CB]{a: [{b: 1}]} | .a .[] .b \-\-> 1\f[B]\f[R] .IP \[bu] 2 \f[B]\f[CB]{a: [{b: 1}]} .a .[] .b \-\-> 1\f[B]\f[R] .PP You can omit the leading \f[B]\f[CB].\f[B]\f[R] of path operators that have the shape \f[B]\f[CB].[...]\f[B]\f[R], unless the path operator is the head of the compound path and the leading atomic filter \f[B]\f[CB].\f[B]\f[R] has been omitted. For example, the following filters are all equivalent: .IP \[bu] 2 \f[B]\f[CB][[[1, 2, 3]]] | .[0] | .[] | .[:\-1] \-\-> [1, 2]\f[B]\f[R] .IP \[bu] 2 \f[B]\f[CB][[[1, 2, 3]]] | .[0] .[] .[:\-1] \-\-> [1, 2]\f[B]\f[R] .IP \[bu] 2 \f[B]\f[CB][[[1, 2, 3]]] | .[0] [] [:\-1] \-\-> [1, 2]\f[B]\f[R] .IP \[bu] 2 \f[B]\f[CB][[[1, 2, 3]]] [0] [] [:\-1] \-\-> [1, 2]\f[B]\f[R] .PP You can also terminate any path operator in this section with a \f[B]\f[CB]?\f[B]\f[R], which silences errors from that operator. For example, \f[B]\f[CB].[]\f[B]\f[R] yields an error if the input is neither an array nor an object, but \f[B]\f[CB].[]?\f[B]\f[R] silences such errors, yielding no output instead. Examples: .IP \[bu] 2 \f[B]\f[CB][1, {a: 2 }, {a: 3 }] | .[].a? \-\-> 2 3\f[B]\f[R] .IP \[bu] 2 \f[B]\f[CB][1, [2, 3 ], [4, 5 ]] | .[][]? \-\-> 2 3 4 5\f[B]\f[R] .IP \[bu] 2 \f[B]\f[CB] 1, {a: [2]}, {a: [3]} | .a?[] \-\-> 2 3\f[B]\f[R] .TP \f[I]Advanced\f[R] When you combine the techniques above, be aware that the filters \f[B]\f[CB]x\f[B]\f[R] and \f[B]\f[CB]y\f[B]\f[R] in \f[B]\f[CB].[x]\f[B]\f[R] and \f[B]\f[CB].[x:y]\f[B]\f[R] are executed on the \f[B]original\f[R] input and are \f[B]not\f[R] influenced by error suppression with \f[B]\f[CB]?\f[B]\f[R]. That means that \f[B]\f[CB]f[][x]?[y:z]\f[B]\f[R] is equivalent to \f[B]\f[CB]f as $f | x as $x | y as $y | z as $z | $f | .[] | .[$x]? | .[$y:$z]\f[B]\f[R]. .SS NULLARY A nullary filter does not take any arguments. .SS Identity (\f[B]\f[CB].\f[B]\f[R]) The filter \f[B]\f[CB].\f[B]\f[R] yields its input as single output. For example, \f[B]\f[CB]1 | . \-\-> 1\f[B]\f[R]. .SS Recursion (\f[B]\f[CB]..\f[B]\f[R]) The filter \f[B]\f[CB]..\f[B]\f[R] yields its input and all recursively contained values. For example: .IP .EX {\[dq]a\[dq]: 1, \[dq]b\[dq]: [2, [\[dq]3\[dq]]]} | .. \-\-> {\[dq]a\[dq]: 1, \[dq]b\[dq]: [2, [\[dq]3\[dq]]]} 1 [2, [\[dq]3\[dq]]] 2 [\[dq]3\[dq]] \[dq]3\[dq] .EE .PP It yields the same outputs as \f[B]\f[CB]recurse\f[B]\f[R]. .SS UNARY A unary filter takes a single argument. .SS Negation (\f[B]\f[CB]\-\f[B]\f[R]) The prefix operator \f[B]\f[CB]\-f\f[B]\f[R] runs the atomic filter \f[B]\f[CB]f\f[B]\f[R] and negates its outputs. For example, \f[B]\f[CB]\-1 \-\-> \-1\f[B]\f[R] and \f[B]\f[CB]\-(1, 2) \-\-> \-1 \-2\f[B]\f[R]. .SS Error suppression (\f[B]\f[CB]?\f[B]\f[R]) The postfix operator \f[B]\f[CB]f?\f[B]\f[R] runs the atomic filter \f[B]\f[CB]f\f[B]\f[R] and returns all its outputs until (excluding) the first error. For example, \f[B]\f[CB](1, error, 2)? \-\-> 1\f[B]\f[R]. .PP This operator is equivalent to \f[B]\f[CB]try f\f[B]\f[R] (see \f[B]\f[CB]try\-catch\f[B]\f[R]). For example, \f[B]\f[CB]try (1, error, 2) \-\-> 1\f[B]\f[R]. .TP \f[I]Advanced\f[R] We can see that error suppression has a higher precedence than negation by \f[B]\f[CB]try \-[]? catch \-1 \-\-> \-1\f[B]\f[R], which shows us that \f[B]\f[CB]\-[]?\f[B]\f[R] yields the same as \f[B]\f[CB]\-([]?)\f[B]\f[R], which is equivalent to \f[B]\f[CB]\-[]\f[B]\f[R] and yields an error. If negation would have a higher precedence, then \f[B]\f[CB]\-[]?\f[B]\f[R] would be equivalent to \f[B]\f[CB](\-[])?\f[B]\f[R]; however, that filter yields no output, as we can see by \f[B]\f[CB](\-[])? \-\-> \f[B]\f[R]. .SS BINARY (COMPLEX) A binary filter takes two arguments. .PP All binary operators that contain the characters \f[B]\f[CB]|\f[B]\f[R] or \f[B]\f[CB]=\f[B]\f[R] are right\-associative. All other binary operators are left\-associative. That means that for example, \f[B]\f[CB]f | g | h\f[B]\f[R] is equivalent to \f[B]\f[CB]f | (g | h)\f[B]\f[R], whereas \f[B]\f[CB]f \- g \- h\f[B]\f[R] is equivalent to \f[B]\f[CB](f \- g) \- h\f[B]\f[R]. .PP This section lists all binary infix filters sorted by increasing precedence. .SS Composition (\f[B]\f[CB]|\f[B]\f[R]) The filter \f[B]\f[CB]f | g\f[B]\f[R] runs \f[B]\f[CB]f\f[B]\f[R], and for every output \f[B]\f[CB]y\f[B]\f[R] of \f[B]\f[CB]f\f[B]\f[R], it runs \f[B]\f[CB]g\f[B]\f[R] with \f[B]\f[CB]y\f[B]\f[R] as input and yields its outputs. For example, \f[B]\f[CB](1, 2) | (., 3) \-\-> 1 3 2 3\f[B]\f[R]. .PP If either \f[B]\f[CB]f\f[B]\f[R] or \f[B]\f[CB]g\f[B]\f[R] yields an error, then \f[B]\f[CB]f | g\f[B]\f[R] yields that error, followed by nothing. For example, \f[B]\f[CB](1, 2) | (., error)\f[B]\f[R] yields the same as \f[B]\f[CB]1, error\f[B]\f[R]. .SS Concatenation (\f[B]\f[CB],\f[B]\f[R]) The filter \f[B]\f[CB]f, g\f[B]\f[R] yields the concatenation of the outputs of \f[B]\f[CB]f\f[B]\f[R] and \f[B]\f[CB]g\f[B]\f[R]. For example, \f[B]\f[CB]1, 2 \-\-> 1 2\f[B]\f[R]. .SS Variable binding (\f[B]\f[CB]as $x |\f[B]\f[R]) The filter \f[B]\f[CB]f as $x | g\f[B]\f[R] runs \f[B]\f[CB]f\f[B]\f[R], and for every output \f[B]\f[CB]x\f[B]\f[R] of \f[B]\f[CB]f\f[B]\f[R], it binds the value of \f[B]\f[CB]x\f[B]\f[R] to the \f[B]variable\f[R] \f[B]\f[CB]$x\f[B]\f[R]. Here, \f[B]\f[CB]x\f[B]\f[R] is an identifier. It then runs \f[B]\f[CB]g\f[B]\f[R] \f[B]on the original input\f[R], replacing any reference to \f[B]\f[CB]$x\f[B]\f[R] in \f[B]\f[CB]g\f[B]\f[R] by the value \f[B]\f[CB]x\f[B]\f[R]. For example, \f[B]\f[CB]\[dq]Hello\[dq] | length as $x | . + \[dq] has length \[rs]($x)\[dq] \-\-> \[dq]Hello has length 5\[dq]\f[B]\f[R]. .PP Variables can be shadowed, such as \f[B]\f[CB]0 as $x | (1 as $x | $x), $x \-\-> 1 0\f[B]\f[R]. .TP \f[I]Advanced\f[R] The filter \f[B]\f[CB]... as $x | ...\f[B]\f[R] is interpreted like \f[B]\f[CB]... as $x | (...)\f[B]\f[R], where the parentheses extend as far as possible to the right. That means that for example: .IP \[bu] 2 \f[B]\f[CB] 0 as $x | 1 | $x \-\-> 0\f[B]\f[R] is interpreted like .IP \[bu] 2 \f[B]\f[CB] 0 as $x | (1 | $x) \-\-> 0\f[B]\f[R], not like .IP \[bu] 2 \f[B]\f[CB](0 as $x) | (1 | $x)\f[B]\f[R], which does not compile. You could say that the precedence of \f[B]\f[CB]as $x |\f[B]\f[R] is lower than any other operator to its \f[I]right\f[R]. However, to its \f[I]left\f[R], the regular precedences apply. That means that: .IP \[bu] 2 \f[B]\f[CB] 1, 2 as $x | [$x] \-\-> 1 [2]\f[B]\f[R] is interpreted like .IP \[bu] 2 \f[B]\f[CB] 1, (2 as $x | [$x]) \-\-> 1 [2]\f[B]\f[R], not like .IP \[bu] 2 \f[B]\f[CB](1, 2) as $x | [$x] \-\-> [1] [2]\f[B]\f[R]. .SS Plain assignment (\f[B]\f[CB]=\f[B]\f[R]) The filter \f[B]\f[CB]f = g\f[B]\f[R] runs \f[B]\f[CB]g\f[B]\f[R] with its input, and for every output \f[B]\f[CB]y\f[B]\f[R] of \f[B]\f[CB]g\f[B]\f[R], it returns a copy of the input whose values at the positions given by \f[B]\f[CB]f\f[B]\f[R] are replaced by \f[B]\f[CB]y\f[B]\f[R]. For example: .IP .EX [1, 2, 3] | .[0] = (length, 4) \-\-> [3, 2, 3] [4, 2, 3] .EE .SS Update assignment (\f[B]\f[CB]|=\f[B]\f[R]) The filter \f[B]\f[CB]f |= g\f[B]\f[R] returns a copy of its input where each value \f[B]\f[CB]v\f[B]\f[R] at a position given by \f[B]\f[CB]f\f[B]\f[R] is replaced by the output of \f[B]\f[CB]g\f[B]\f[R] run with input \f[B]\f[CB]v\f[B]\f[R]. For example, \f[B]\f[CB][1, 2, 3] | .[] |= .*2 \-\-> [2, 4, 6]\f[B]\f[R]. .PP When \f[B]\f[CB]g\f[B]\f[R] yields \f[B]no\f[R] outputs, then the value at the position is deleted; for example, \f[B]\f[CB][1, 2, 3] | .[0] |= empty \-\-> [2, 3]\f[B]\f[R] and \f[B]\f[CB]{a: 1, b: 2} | .a |= empty \-\-> {\[dq]b\[dq]: 2}\f[B]\f[R]. .TP \f[I]Advanced\f[R] When \f[B]\f[CB]g\f[B]\f[R] yields \f[B]multiple\f[R] outputs, then it depends on the input type and on \f[B]\f[CB]f\f[B]\f[R] whether more than one output of \f[B]\f[CB]g\f[B]\f[R] is considered. For example, the following updates consider multiple outputs: .IP \[bu] 2 \f[B]\f[CB]1 | . |= (., .*2) \-\-> 1 2\f[B]\f[R] .IP \[bu] 2 \f[B]\f[CB][1, 2, 3] | .[ ] |= (., .*2) \-\-> [1, 2, 2, 4, 3, 6]\f[B]\f[R] On the other hand, the following updates consider only the first output: .IP \[bu] 2 \f[B]\f[CB][1, 2, 3] | .[0] |= (., .*2) \-\-> [1, 2, 3]\f[B]\f[R] .IP \[bu] 2 \f[B]\f[CB]{a: 1, b: 2} | .a |= (., .*2) \-\-> {\[dq]a\[dq]: 1, \[dq]b\[dq]: 2}\f[B]\f[R] .SS Arithmetic update assignment (\f[B]\f[CB]+=\f[B]\f[R], \f[B]\f[CB]\-=\f[B]\f[R], \&...) The filters \f[B]\f[CB]f += g\f[B]\f[R], \f[B]\f[CB]f \-= g\f[B]\f[R], \f[B]\f[CB]f *= g\f[B]\f[R], \f[B]\f[CB]f /= g\f[B]\f[R], \f[B]\f[CB]f %= g\f[B]\f[R], and \f[B]\f[CB]f //= g\f[B]\f[R] are short\-hand forms for \f[B]\f[CB]f = . + g\f[B]\f[R], \&... For example: .IP .EX [1, 2, 3] | .[0] += (length, 4) \-\-> [4, 2, 3] [5, 2, 3] .EE .SS Alternation (\f[B]\f[CB]//\f[B]\f[R]) The filter \f[B]\f[CB]f // g\f[B]\f[R] runs \f[B]\f[CB]f\f[B]\f[R] and yields all its outputs whose boolean value is \f[B]\f[CB]true\f[B]\f[R]; that is, all outputs that are neither \f[B]\f[CB]null\f[B]\f[R] nor \f[B]\f[CB]false\f[B]\f[R]. If \f[B]\f[CB]f\f[B]\f[R] yields no such outputs, then this filter yields the outputs of \f[B]\f[CB]g\f[B]\f[R]. For example: .IP \[bu] 2 \f[B]\f[CB](null, 1, false, 2) // (3, 4) \-\-> 1 2\f[B]\f[R] .IP \[bu] 2 \f[B]\f[CB](null, false) // (3, 4) \-\-> 3 4\f[B]\f[R] .IP \[bu] 2 \f[B]\f[CB]empty // 3 \-\-> 3\f[B]\f[R] .SS Logic (\f[B]\f[CB]or\f[B]\f[R], \f[B]\f[CB]and\f[B]\f[R]) The filter \f[B]\f[CB]f or g\f[B]\f[R] (disjunction) evaluates \f[B]\f[CB]f\f[B]\f[R] and returns \f[B]\f[CB]true\f[B]\f[R] if its boolean value is \f[B]\f[CB]true\f[B]\f[R], else it returns the boolean values of \f[B]\f[CB]g\f[B]\f[R]. The filter \f[B]\f[CB]f and g\f[B]\f[R] (conjunction) evaluates \f[B]\f[CB]f\f[B]\f[R] and returns \f[B]\f[CB]false\f[B]\f[R] if its boolean value is \f[B]\f[CB]false\f[B]\f[R], else it returns the boolean values of \f[B]\f[CB]g\f[B]\f[R]. .PP For example: .IP .EX (true, false) or (true, false) \-\-> true true false .EE .IP .EX (true, false) and (true, false) \-\-> true false false .EE .PP The filter \f[B]\f[CB]f and g\f[B]\f[R] has higher precedence than \f[B]\f[CB]f or g\f[B]\f[R]. .TP \f[I]Advanced\f[R] We can see the higher precedence of \f[B]\f[CB]and\f[B]\f[R] by \f[B]\f[CB]false and true or true \-\-> true\f[B]\f[R], which yields the same as \f[B]\f[CB](false and true) or true \-\-> true\f[B]\f[R], but not the same as \f[B]\f[CB]false and (true or true) \-\-> false\f[B]\f[R]. To find this formula, I used the following program: .IP .EX def bool: true, false; {x: bool, y: bool, z: bool} | select( ((.x and .y) or .z ) != ( .x and (.y or .z)) ) \-\-> { \[dq]x\[dq]: false, \[dq]y\[dq]: true, \[dq]z\[dq]: true } { \[dq]x\[dq]: false, \[dq]y\[dq]: false, \[dq]z\[dq]: true } .EE .PP It holds that \f[B]\f[CB]f or g\f[B]\f[R] is equivalent to \f[B]\f[CB]f as $x | $x or g\f[B]\f[R]; similar for \f[B]\f[CB]and\f[B]\f[R]. .SS BINARY (SIMPLE) Every simple binary operator such as \f[B]\f[CB]+\f[B]\f[R] in this section fulfills the property that \f[B]\f[CB]f + g\f[B]\f[R] is equivalent to \f[B]\f[CB]f as $x | g as $y | $x + $y\f[B]\f[R]. For example, \f[B]\f[CB](1, 2) + (1, 3) \-\-> 2 4 3 5\f[B]\f[R] and \f[B]\f[CB](1, 2) * (1, 3) \-\-> 1 3 2 6\f[B]\f[R]. This property does not hold for the complex binary filters above. .TP \f[I]Compatibility\f[R] In \f[B]\f[CB]jq\f[B]\f[R], a slightly different property holds, namely that \f[B]\f[CB]f + g\f[B]\f[R] is equivalent to \f[B]\f[CB]g as $y | f as $x | $x + $y\f[B]\f[R]. That means that in \f[B]\f[CB]jq\f[B]\f[R], \f[B]\f[CB](1, 2) + (1, 3)\f[B]\f[R] yields \f[B]\f[CB]2 3 4 5\f[B]\f[R]. As a result, in jaq, \f[B]\f[CB](1,2) * (3,4) \-\-> 3 4 6 8\f[B]\f[R] and \f[B]\f[CB]{a: (1,2), b: (3,4)} | .a * .b \-\-> 3 4 6 8\f[B]\f[R] yield the same outputs, whereas \f[B]\f[CB]jq\f[B]\f[R] yields \f[B]\f[CB]3 6 4 8\f[B]\f[R] for the former example. .SS Equality (\f[B]\f[CB]==\f[B]\f[R], \f[B]\f[CB]!=\f[B]\f[R]) The operator \f[B]\f[CB]$x == $y\f[B]\f[R] returns \f[B]\f[CB]true\f[B]\f[R] if the two values \f[B]\f[CB]$x\f[B]\f[R] and \f[B]\f[CB]$y\f[B]\f[R] are equal, else \f[B]\f[CB]false\f[B]\f[R]. Similarly, \f[B]\f[CB]$x != $y\f[B]\f[R] returns the negation of \f[B]\f[CB]$x == $y\f[B]\f[R], i.e. \f[B]\f[CB]$x == $y | not\f[B]\f[R]. .PP Interesting cases include: .IP \[bu] 2 NaN does not equal any value, including itself; i.e. \f[B]\f[CB]nan == nan \-\-> false\f[B]\f[R] .IP \[bu] 2 An integer \f[B]\f[CB]i\f[B]\f[R] equals a float \f[B]\f[CB]f\f[B]\f[R] if \f[B]\f[CB]f\f[B]\f[R] is finite and \f[B]\f[CB]i\f[B]\f[R] converted to a float is equal to \f[B]\f[CB]f\f[B]\f[R]; i.e. \f[B]\f[CB]1 == 1.0 \-\-> true\f[B]\f[R]. .IP \[bu] 2 Arrays are equal if they have the same values; i.e. \f[B]\f[CB][1, 2, 3] == [1, 2, 3]\f[B]\f[R], but \f[B]\f[CB][3, 2, 1] != [1, 2, 3]\f[B]\f[R]. .IP \[bu] 2 Objects are equal if they have the same keys and for every key, the associated value is equal; i.e. \f[B]\f[CB]{a: 1, b: 2} == {b: 2, a: 1} \-\-> true\f[B]\f[R] .TP \f[I]Advanced\f[R] There are values that are equal, yet yield different results when fed to the same filter. For example: .IP .EX {a: 1, b: 2} as $x | {b: 2, a: 1} as $y | $x == $y, ($x | tojson) == ($y | tojson) \-\-> true false .EE .SS Ordering (\f[B]\f[CB]<\f[B]\f[R], \f[B]\f[CB]>\f[B]\f[R], \f[B]\f[CB]<=\f[B]\f[R], \f[B]\f[CB]>=\f[B]\f[R]) The operator \f[B]\f[CB]$x < $y\f[B]\f[R] returns \f[B]\f[CB]true\f[B]\f[R] if \f[B]\f[CB]$x\f[B]\f[R] is smaller than \f[B]\f[CB]$y\f[B]\f[R]. Similarly: .IP \[bu] 2 \f[B]\f[CB]$x > $y\f[B]\f[R] is equivalent to \f[B]\f[CB]$y < $x\f[B]\f[R], .IP \[bu] 2 \f[B]\f[CB]$x <= $y\f[B]\f[R] is equivalent to \f[B]\f[CB]$x < $y or $x == $y\f[B]\f[R], and .IP \[bu] 2 \f[B]\f[CB]$x >= $y\f[B]\f[R] is equivalent to \f[B]\f[CB]$x > $y or $x == $y\f[B]\f[R]. .PP Values are ordered as follows: .IP \[bu] 2 \f[B]\f[CB]null\f[B]\f[R] .IP \[bu] 2 Booleans: \f[B]\f[CB]false < true \-\-> true\f[B]\f[R] .IP \[bu] 2 Numbers: .RS 2 .IP \[bu] 2 \f[B]\f[CB]NaN\f[B]\f[R] is smaller than any other number, including itself; i.e. \f[B]\f[CB]nan < nan \-\-> true\f[B]\f[R] .IP \[bu] 2 \f[B]\f[CB]\-Infinity\f[B]\f[R], e.g. \f[B]\f[CB]\-infinite < \-99999999999999999999999999 \-\-> true\f[B]\f[R] .IP \[bu] 2 Finite numbers, e.g. \f[B]\f[CB]0 < 1 \-\-> true\f[B]\f[R] .IP \[bu] 2 \f[B]\f[CB]Infinity\f[B]\f[R], e.g. \f[B]\f[CB]infinite > 99999999999999999999999999 \-\-> true\f[B]\f[R] .RE .IP \[bu] 2 Strings: lexicographic ordering by underlying bytes, e.g. \f[B]\f[CB]\[dq]Hello\[dq] < \[dq]Hello World\[dq] \-\-> true\f[B]\f[R] and \f[B]\f[CB]\[dq]\[at]B\[dq] < \[dq]A\[dq] \-\-> true\f[B]\f[R]. .IP \[bu] 2 Arrays: lexicographic ordering, e.g. \f[B]\f[CB][1, 2] < [1, 2, 3] \-\-> true\f[B]\f[R] and \f[B]\f[CB][0, 2] < [1] \-\-> true\f[B]\f[R]. .IP \[bu] 2 Objects: An object \f[B]\f[CB]$x\f[B]\f[R] is smaller than an object \f[B]\f[CB]$y\f[B]\f[R] either if: .RS 2 .IP \[bu] 2 the keys of \f[B]\f[CB]$x\f[B]\f[R] are smaller than the keys of \f[B]\f[CB]$y\f[B]\f[R] or .IP \[bu] 2 the keys of \f[B]\f[CB]$x\f[B]\f[R] are equal to the keys of \f[B]\f[CB]$y\f[B]\f[R] and the values of \f[B]\f[CB]$x\f[B]\f[R] are smaller than the values of \f[B]\f[CB]$y\f[B]\f[R]. .RE .TP \f[I]Advanced\f[R] More precisely, an object \f[B]\f[CB]$x\f[B]\f[R] is smaller than an object \f[B]\f[CB]$y\f[B]\f[R] if: .IP .EX ($x | to_entries | sort_by(.key)) as $ex | ($y | to_entries | sort_by(.key)) as $ey | [$ex[].key] < [$ey[].key] or [$ex[].key] == [$ey[].key] and [$ex[].value] < [$ey[].value] .EE .SS Addition / subtraction (\f[B]\f[CB]+\f[B]\f[R], \f[B]\f[CB]\-\f[B]\f[R]) The filter \f[B]\f[CB]$x + $y\f[B]\f[R] adds two values as follows: .IP \[bu] 2 \f[B]\f[CB]null + $x\f[B]\f[R] and \f[B]\f[CB]$x + null\f[B]\f[R] yields \f[B]\f[CB]$x\f[B]\f[R]. .IP \[bu] 2 Adding numbers yields their sum, which is integer if both numbers are integer, else a floating\-point number. For example, \f[B]\f[CB]1 + 2 \-\-> 3\f[B]\f[R] and \f[B]\f[CB]1 + 2.0 \-\-> 3.0\f[B]\f[R]. .IP \[bu] 2 Adding strings or arrays concatenates them, i.e. \f[B]\f[CB]\[dq]Hello, \[dq] + \[dq]World!\[dq] \-\-> \[dq]Hello, World!\[dq]\f[B]\f[R] and \f[B]\f[CB][1, 2] + [3, 4] \-\-> [1, 2, 3, 4]\f[B]\f[R]. .IP \[bu] 2 Adding objects yields their \f[B]union\f[R]. If a key is present in both objects, then the resulting object will contain the key with the value of the object on the \f[B]right\f[R]; i.e. \f[B]\f[CB]{a: 1, b: 2} + {b: 3, c: 4} \-\-> {\[dq]a\[dq]: 1, \[dq]b\[dq]: 3, \[dq]c\[dq]: 4}\f[B]\f[R]. .IP \[bu] 2 Adding anything else yields an error. .PP The filter \f[B]\f[CB]$x \- $y\f[B]\f[R] subtracts \f[B]\f[CB]$y\f[B]\f[R] from \f[B]\f[CB]$x\f[B]\f[R] as follows: .IP \[bu] 2 Subtracting numbers yields their difference, similar to addition. .IP \[bu] 2 Subtracting arrays yields the left array with all elements contained in the right array removed; i.e. \f[B]\f[CB][1, 2, 3, 4] \- [2, 4] \-\-> [1, 3]\f[B]\f[R]. .IP \[bu] 2 Subtracting anything else yields an error. .SS Multiplication / division (\f[B]\f[CB]*\f[B]\f[R], \f[B]\f[CB]/\f[B]\f[R]) The filter \f[B]\f[CB]$x * $y\f[B]\f[R] multiplies two values as follows: .IP \[bu] 2 Multiplying numbers yields their product, similar to addition. .IP \[bu] 2 Multiplying a string with an integer \f[B]\f[CB]$n\f[B]\f[R] yields the \f[B]\f[CB]$n\f[B]\f[R]\-fold concatenation of the string, i.e. \f[B]\f[CB]\[dq]abc\[dq] * 3 \-\-> \[dq]abcabcabc\[dq]\f[B]\f[R]. If \f[B]\f[CB]$n <= 0\f[B]\f[R], then this yields \f[B]\f[CB]null\f[B]\f[R], i.e. \f[B]\f[CB]0 * \[dq]abc\[dq] \-\-> null\f[B]\f[R]. .IP \[bu] 2 Multiplying two objects merges them recursively. In particular, \f[B]\f[CB]$x * {k: v, ...}\f[B]\f[R] yields \f[B]\f[CB]($x + {k: $x[k] * v}) * {...}\f[B]\f[R] if both \f[B]\f[CB]v\f[B]\f[R] and \f[B]\f[CB]$x[k]\f[B]\f[R] are objects, else \f[B]\f[CB]($x + {k: v}) * {...}\f[B]\f[R]. For example, \f[B]\f[CB]{a: {b: 0, c: 2}, e: 4} * {a: {b: 1, d: 3}, f: 5} \-\-> {\[dq]a\[dq]: {\[dq]b\[dq]: 1, \[dq]c\[dq]: 2, \[dq]d\[dq]: 3}, \[dq]e\[dq]: 4, \[dq]f\[dq]: 5}\f[B]\f[R]. .IP \[bu] 2 Multiplying anything else yields an error. .PP The filter \f[B]\f[CB]$x / $y\f[B]\f[R] divides two values as follows: .IP \[bu] 2 Dividing a number by a number yields their quotient as floating\-point number. To perform this operation, both arguments are first converted to floating\-point numbers. For example, \f[B]\f[CB]1 / 2 \-\-> 0.5\f[B]\f[R]. .IP \[bu] 2 Dividing a string by a string \f[B]splits\f[R] \f[B]\f[CB]$x\f[B]\f[R] by \f[B]\f[CB]$y\f[B]\f[R], yielding an array of strings. For example, \f[B]\f[CB]\[dq]foobarfoobazfoo\[dq] / \[dq]foo\[dq] \-\-> [\[dq]\[dq], \[dq]bar\[dq], \[dq]baz\[dq], \[dq]\[dq]]\f[B]\f[R]. If \f[B]\f[CB]$y\f[B]\f[R] is empty, then \f[B]\f[CB]$x / $y\f[B]\f[R] yields an array with each character of the input as separate string. For example, \f[B]\f[CB]\[dq]🧑‍🔬 is 🤔\[dq] / \[dq]\[dq] \-\-> [\[dq]🧑\[dq],\[dq]‍\[dq],\[dq]🔬\[dq],\[dq] \[dq],\[dq]i\[dq],\[dq]s\[dq],\[dq] \[dq],\[dq]🤔\[dq]]\f[B]\f[R]. .TP \f[I]Advanced\f[R] You can round\-trip string division with \f[B]\f[CB]join($y)\f[B]\f[R]. For example: .IP \[bu] 2 \f[B]\f[CB]\[dq]foobarfoobazfoo\[dq] / \[dq]foo\[dq] | join(\[dq]foo\[dq]) \-\-> \[dq]foobarfoobazfoo\[dq]\f[B]\f[R] .IP \[bu] 2 \f[B]\f[CB]\[dq]🧑‍🔬 is 🤔\[dq] / \[dq]\[dq] | join(\[dq]\[dq]) \-\-> \[dq]🧑‍🔬 is 🤔\[dq]\f[B]\f[R] .TP \f[I]Compatibility\f[R] In jq, division by 0 yields an error, whereas in jaq, \f[B]\f[CB]n / 0\f[B]\f[R] yields \f[B]\f[CB]nan\f[B]\f[R] if \f[B]\f[CB]n == 0\f[B]\f[R], \f[B]\f[CB] infinite\f[B]\f[R] if \f[B]\f[CB]n > 0\f[B]\f[R], and \f[B]\f[CB]\-infinite\f[B]\f[R] if \f[B]\f[CB]n < 0\f[B]\f[R]. jaq\[cq]s behaviour is closer to the IEEE standard for floating\-point arithmetic (IEEE 754). .SS Modulus (\f[B]\f[CB]%\f[B]\f[R]) The filter \f[B]\f[CB]$x % $y\f[B]\f[R] calculates the modulus of two numbers, and fails for anything else. For example, \f[B]\f[CB]5 % 2 \-\-> 1\f[B]\f[R]. Any of the two numbers can also be a floating\-point number; however, the result of this may be unexpected. For example, \f[B]\f[CB]5.1 % 2 \-\-> 1.0999999999999996\f[B]\f[R] and \f[B]\f[CB]5.5 % 2 \-\-> 1.5\f[B]\f[R]. .SS KEYWORDS This section lists all filters that start with a reserved keyword. .SS if\-then\-else The filter \f[B]\f[CB]if p then f else g end\f[B]\f[R] runs the filter \f[B]\f[CB]p\f[B]\f[R] with its input. For every output of \f[B]\f[CB]p\f[B]\f[R], if its boolean value is \f[B]\f[CB]true\f[B]\f[R], the outputs of \f[B]\f[CB]f\f[B]\f[R] run with the original input are returned, else the outputs of \f[B]\f[CB]g\f[B]\f[R] run with the original input are returned. .PP Examples: .IP \[bu] 2 \f[B]\f[CB]if true then 0 else 1 end \-\-> 0\f[B]\f[R] .IP \[bu] 2 \f[B]\f[CB]if [], null then 0 else 1 end \-\-> 0 1\f[B]\f[R] .PP There exists a longer form of this filter, namely \f[B]\f[CB]if p1 then f1 elif p2 then f2 ... else g end\f[B]\f[R]. This is equivalent to \f[B]\f[CB]if p1 then f1 else (if p2 then f2 else (... else g end) end) end\f[B]\f[R]. .PP When the \f[B]\f[CB]else g\f[B]\f[R] part is omitted, it is equivalent to \f[B]\f[CB]else .\f[B]\f[R]; for example, \f[B]\f[CB]0 | if false then .+1 end \-\-> 0\f[B]\f[R]. .SS try\-catch The filter \f[B]\f[CB]try f catch g\f[B]\f[R] runs the atomic filter \f[B]\f[CB]f\f[B]\f[R] with its input, and returns its outputs until (excluding) the first error. If \f[B]\f[CB]f\f[B]\f[R] yields an error, then the atomic filter \f[B]\f[CB]g\f[B]\f[R] is run with the error value as input, and its outputs are returned. .PP Examples: .IP \[bu] 2 \f[B]\f[CB]try (1, error(42), 2) catch (. + 1) \-\-> 1 43\f[B]\f[R] .IP \[bu] 2 \f[B]\f[CB]try (1, 2) catch (. + 1) \-\-> 1 2\f[B]\f[R] .PP A short form of this filter is \f[B]\f[CB]try f\f[B]\f[R], which is equivalent to \f[B]\f[CB]try f catch empty\f[B]\f[R] as well as to \f[B]\f[CB]f?\f[B]\f[R] (error suppression). .SS label\-break The filter \f[B]\f[CB]label $x | f\f[B]\f[R] binds the label \f[B]\f[CB]$x\f[B]\f[R] in \f[B]\f[CB]f\f[B]\f[R], runs \f[B]\f[CB]f\f[B]\f[R] and yields its outputs. If the evaluation of \f[B]\f[CB]f\f[B]\f[R] calls \f[B]\f[CB]break $x\f[B]\f[R], then the evaluation of \f[B]\f[CB]label $x | f\f[B]\f[R] is stopped and returns no more outputs. For example, \f[B]\f[CB]label $x | 1, break $x, 2 \-\-> 1\f[B]\f[R]. .PP Labels are distinct from variables, which means that \f[B]\f[CB]0 as $x | label $x | $x, break $x \-\-> 0\f[B]\f[R]. .PP Like variables, labels can be shadowed; e.g. \f[B]\f[CB]label $x | 1, (label $x | 2, break $x, 3), 4, break $x, 5 \-\-> 1 2 4\f[B]\f[R]. .PP It is possible to \f[B]\f[CB]break\f[B]\f[R] from a filter argument; e.g. \f[B]\f[CB]def f(g): 1, g, 2; label $x | f(break $x) \-\-> 1\f[B]\f[R]. .SS reduce / foreach The filters \f[B]\f[CB]reduce xs as $x (init; update)\f[B]\f[R] and \f[B]\f[CB]foreach xs as $x (init; update; project)\f[B]\f[R] both run the atomic filter \f[B]\f[CB]xs\f[B]\f[R] on its input. Suppose that the outputs of \f[B]\f[CB]xs\f[B]\f[R] are \f[B]\f[CB]x1\f[B]\f[R], \&..., \f[B]\f[CB]xn\f[B]\f[R]. Then the filters are equivalent to: .IP .EX reduce x1, ..., xn as $x (init; update) := init | x1 as $x | update | ... | xn as $x | update .EE .IP .EX foreach x1, ..., xn as $x (init; update; project) := init | ( x1 as $x | update | project, ( ... ( xn as $x | update | project, ( empty ))...)) .EE .PP Here, both \f[B]\f[CB]update\f[B]\f[R] and \f[B]\f[CB]project\f[B]\f[R] have access to the current \f[B]\f[CB]$x\f[B]\f[R]. .PP The filter \f[B]\f[CB]foreach xs as $x (init; update)\f[B]\f[R] is equivalent to \f[B]\f[CB]foreach xs as $x (init; update; .)\f[B]\f[R]. .PP As example, we can calculate the sum and the cumulative sum using \f[B]\f[CB]reduce\f[B]\f[R] and \f[B]\f[CB]foreach\f[B]\f[R], respectively: .IP \[bu] 2 \f[B]\f[CB]reduce (1, 2, 3) as $x (0; . + $x) \-\-> 6\f[B]\f[R] .IP \[bu] 2 \f[B]\f[CB]foreach (1, 2, 3) as $x (0; . + $x) \-\-> 1 3 6\f[B]\f[R] .IP \[bu] 2 \f[B]\f[CB]foreach (1, 2, 3) as $x (0; . + $x; [$x, .]) \-\-> [1, 1] [2, 3] [3, 6]\f[B]\f[R] .PP Let us expand the first and the last example using the equivalences above to see what is calculated: .IP .EX # reduce (1, 2, 3) as $x (0; . + $x) 0 | 1 as $x | . + $x # 1 | 2 as $x | . + $x # 3 | 3 as $x | . + $x # 6 \-\-> 6 .EE .IP .EX # foreach (1, 2, 3) as $x (0; . + $x; [$x, .]) 0 | ( 1 as $x | . + $x | [$x, .], # [1, 1] ( 2 as $x | . + $x | [$x, .], # [2, 3] ( 3 as $x | . + $x | [$x, .], # [3, 6] ( empty )))) \-\-> [1, 1] [2, 3] [3, 6] .EE .PP We can also reverse a list via \f[B]\f[CB][1, 2, 3] | reduce .[] as $x ([]; [$x] + .) \-\-> [3, 2, 1]\f[B]\f[R]. (However, note that this has quadratic runtime and is thus quite inefficient.) .PP Note that when \f[B]\f[CB]xs\f[B]\f[R] yields no outputs, then \f[B]\f[CB]reduce\f[B]\f[R] yields \f[B]\f[CB]init\f[B]\f[R], whereas \f[B]\f[CB]foreach\f[B]\f[R] yields no output. For example: .IP \[bu] 2 \f[B]\f[CB]reduce empty as $x (0; . + $x) \-\-> 0\f[B]\f[R] and .IP \[bu] 2 \f[B]\f[CB]foreach empty as $x (0; . + $x) \-\->\f[B]\f[R] (no output). .TP \f[I]Compatibility\f[R] The execution of \f[B]\f[CB]reduce\f[B]\f[R] and \f[B]\f[CB]foreach\f[B]\f[R] differs between \f[B]\f[CB]jq\f[B]\f[R] and jaq when \f[B]\f[CB]update\f[B]\f[R] yields multiple outputs. However, the precise behaviour of \f[B]\f[CB]jq\f[B]\f[R] in that case is quite difficult to describe. The interpretation of \f[B]\f[CB]reduce\f[B]\f[R]/\f[B]\f[CB]foreach\f[B]\f[R] in jaq has the following advantages over jq: .IP \[bu] 2 It deals very naturally with filters that yield multiple outputs. In contrast, jq discriminates outputs of \f[B]\f[CB]f\f[B]\f[R], because it recurses only on the last of them, although it outputs all of them. .IP \[bu] 2 It makes the implementation of \f[B]\f[CB]reduce\f[B]\f[R] and \f[B]\f[CB]foreach\f[B]\f[R] special cases of the same code, reducing the potential for bugs. .TP \f[I]Advanced\f[R] Consider the following example for an \f[B]\f[CB]update\f[B]\f[R] yielding multiple values: \f[B]\f[CB]foreach (5, 10) as $x (1; .+$x, \-.) \-\-> 6 16 \-6 \-1 9 1\f[B]\f[R] in jaq, whereas it yields \f[B]\f[CB]6 \-1 9 1\f[B]\f[R] in jq. We can see that both jq and jaq yield the values resulting from the first iteration (where \f[B]\f[CB]$x\f[B]\f[R] is 5), namely \f[B]\f[CB]1 | 5 as $x | (.+$x, \-.) \-\-> 6 \-1\f[B]\f[R]. However, jq performs the second iteration (where \f[B]\f[CB]$x\f[B]\f[R] is 10) \f[B]only on the last value\f[R] returned from the first iteration, namely \f[B]\f[CB]\-1\f[B]\f[R], yielding the values \f[B]\f[CB]\-1 | 10 as $x | (.+$x, \-.) \-\-> 9 1\f[B]\f[R]. jaq yields these values too, but it also performs the second iteration on all other values returned from the first iteration, namely \f[B]\f[CB]6\f[B]\f[R], yielding the values \f[B]\f[CB] 6 | 10 as $x | (.+$x, \-.) \-\-> 16 \-6\f[B]\f[R]. .SS def The filter \f[B]\f[CB]def x: f; g\f[B]\f[R] binds the filter \f[B]\f[CB]f\f[B]\f[R] to a filter with the name \f[B]\f[CB]x\f[B]\f[R]. Here, \f[B]\f[CB]x\f[B]\f[R] is an identifier. The filter \f[B]\f[CB]g\f[B]\f[R] can contain calls to the filter \f[B]\f[CB]x\f[B]\f[R], and any such calls will be replaced by the filter \f[B]\f[CB]f\f[B]\f[R]. .PP For example, we can define a filter \f[B]\f[CB]iter\f[B]\f[R] by \f[B]\f[CB]def iter: .[];\f[B]\f[R] and use it subsequently by \f[B]\f[CB]def iter: .[]; [1, 2, 3] | iter \-\-> 1 2 3\f[B]\f[R]. This is equivalent to writing \f[B]\f[CB][1, 2, 3] | .[] \-\-> 1 2 3\f[B]\f[R]. .PP Definitions can be chained and nested. For example: .IP .EX def foo: def bar: 1; def baz: 2; bar + baz; foo \-\-> 3 .EE .PP Here, we chained the definitions of \f[B]\f[CB]bar\f[B]\f[R] and \f[B]\f[CB]baz\f[B]\f[R]. These definitions are only visible inside the definition of \f[B]\f[CB]foo\f[B]\f[R]; that means that at the place where we call \f[B]\f[CB]foo\f[B]\f[R], we can use neither \f[B]\f[CB]bar\f[B]\f[R] nor \f[B]\f[CB]baz\f[B]\f[R]. .PP Definitions can be recursive, meaning that they call themselves. For example, \f[B]\f[CB]def f: 0, f; f\f[B]\f[R] yields an infinite sequence of \f[B]\f[CB]0\f[B]\f[R] values. An example of a non\-terminating filter is \f[B]\f[CB]def r: r; r\f[B]\f[R]. Finally, the following filter yields an infinite stream of integers starting from its input: .IP .EX def ints_from: ., (. + 1 | ints_from); 1 | limit(3; ints_from) \-\-> 1 2 3 .EE .PP Definitions can also take \f[B]arguments\f[R]: The filter \f[B]\f[CB]def x(x1; ...; xn): f; g\f[B]\f[R] binds the filter \f[B]\f[CB]f\f[B]\f[R] to a filter with the name \f[B]\f[CB]x\f[B]\f[R] and the arity \f[B]\f[CB]n\f[B]\f[R]. Here, \f[B]\f[CB]x1\f[B]\f[R] to \f[B]\f[CB]xn\f[B]\f[R] are identifiers that are the arguments of \f[B]\f[CB]x\f[B]\f[R], and \f[B]\f[CB]f\f[B]\f[R] can contain references to these arguments. The filter \f[B]\f[CB]g\f[B]\f[R] can contain calls of the shape \f[B]\f[CB]x(g1; ...; gn)\f[B]\f[R], where \f[B]\f[CB]g1\f[B]\f[R] to \f[B]\f[CB]gn\f[B]\f[R] are filters. Any such calls will be replaced by the filter \f[B]\f[CB]f\f[B]\f[R], where every argument \f[B]\f[CB]xi\f[B]\f[R] is replaced by its corresponding filter \f[B]\f[CB]gi\f[B]\f[R]. .PP For example, the filter \f[B]\f[CB]map(f)\f[B]\f[R] in the standard library is defined by \f[B]\f[CB]def map(f): [.[] | f]\f[B]\f[R]. We can use it via \f[B]\f[CB][1, 2, 3] | map( .+1) \-\-> [2, 3, 4]\f[B]\f[R], which is equivalent to \f[B]\f[CB][1, 2, 3] | [.[] | .+1] \-\-> [2, 3, 4]\f[B]\f[R]. .PP We can use variables as arguments of definitions. For example, we can write \f[B]\f[CB]def singleton($x): [$x]\f[B]\f[R] as short form of \f[B]\f[CB]def singleton(x): x as $x | [$x]\f[B]\f[R]. Note that this is not the same as \f[B]\f[CB]def singleton(x): [x]\f[B]\f[R]: .IP \[bu] 2 \f[B]\f[CB]def singleton($x): [$x]; singleton(1, 2, 3) \-\-> [1] [2] [3]\f[B]\f[R] .IP \[bu] 2 \f[B]\f[CB]def singleton( x): [ x]; singleton(1, 2, 3) \-\-> [1, 2, 3]\f[B]\f[R] .PP Arguments of definitions may capture variables, labels, and other definitions. For example: .IP .EX def iter_map(f): .[] | f; def double: .+.; 3 as $threshold | label $lbl | [1, 2, 3] | iter_map(if . < $threshold then double else break $lbl end) \-\-> 2 4 .EE .PP Here, the argument to \f[B]\f[CB]iter_map\f[B]\f[R] captures the definition \f[B]\f[CB]double\f[B]\f[R], the variable \f[B]\f[CB]$threshold\f[B]\f[R], and the label \f[B]\f[CB]$lbl\f[B]\f[R]. .TP \f[I]Advanced\f[R] We can always transform a definition with variable arguments to an equivalent definition without variable arguments. For that, suppose that \f[B]\f[CB]$x\f[B]\f[R] is the rightmost variable argument in a definition \f[B]\f[CB]def x(...; $x; ...): g\f[B]\f[R]. We can replace it by \f[B]\f[CB]def x(...; x; ...): x as $x | g\f[B]\f[R]. For example, consider the definition \f[B]\f[CB]def f($x1; x2; $x3; x4): g\f[B]\f[R]. This is equivalent to \f[B]\f[CB]def f(x1; x2; x3; x4): x1 as $x1 | x3 as $x3 | g\f[B]\f[R]. .SH STANDARD LIBRARY This section lists all named filters that are available by default in any jq module. These filters are also known as \[lq]builtins\[rq]. .SS BASIC .SS \f[B]\f[CB]error\f[B]\f[R], \f[B]\f[CB]error(f)\f[B]\f[R] The filter \f[B]\f[CB]error(f)\f[B]\f[R] throws an error for every output of \f[B]\f[CB]f\f[B]\f[R], with the output as payload. The filter \f[B]\f[CB]error\f[B]\f[R] is equivalent to \f[B]\f[CB]error(.)\f[B]\f[R]. It is possible to use \f[B]\f[CB]error(f)\f[B]\f[R] also on the left\-hand side of assignments. .PP Examples: .IP \[bu] 2 \f[B]\f[CB]error(empty) \-\->\f[B]\f[R] (no output) .IP \[bu] 2 \f[B]\f[CB]try error(41) catch (. + 1) \-\-> 42\f[B]\f[R] .IP \[bu] 2 \f[B]\f[CB]try (41 | error ) catch (. + 1) \-\-> 42\f[B]\f[R] .IP \[bu] 2 \f[B]\f[CB]try (error(41) = 1) catch (. + 1) \-\-> 42\f[B]\f[R] .SS \f[B]\f[CB]length\f[B]\f[R] The output of the filter \f[B]\f[CB]length\f[B]\f[R] depends on its input type: .IP \[bu] 2 \f[B]\f[CB]null\f[B]\f[R]: \f[B]\f[CB]0\f[B]\f[R], i.e. \f[B]\f[CB]null | length \-\-> 0\f[B]\f[R] .IP \[bu] 2 boolean: error, i.e. \f[B]\f[CB]true | try length catch \[dq]fail\[dq] \-\-> \[dq]fail\[dq]\f[B]\f[R] .IP \[bu] 2 number: the absolute value of the number, i.e. \f[B]\f[CB]\-1, 1 | length \-\-> 1 1\f[B]\f[R] .IP \[bu] 2 text string: the number of characters, i.e. \f[B]\f[CB]\[dq]ゼノギアス\[dq] | length \-\-> 5\f[B]\f[R] .IP \[bu] 2 byte string: the number of bytes, i.e. \f[B]\f[CB]\[dq]ゼノギアス\[dq] | tobytes | length \-\-> 15\f[B]\f[R] .IP \[bu] 2 array: the number of values, i.e. \f[B]\f[CB][1, [2, 3], 4] | length \-\-> 3\f[B]\f[R] .IP \[bu] 2 object: the number of key\-value pairs, i.e. \f[B]\f[CB]{a: 0, b: 1} | length \-\-> 2\f[B]\f[R] .SS \f[B]\f[CB]keys\f[B]\f[R], \f[B]\f[CB]keys_unsorted\f[B]\f[R] The filter \f[B]\f[CB]keys_unsorted\f[B]\f[R] yields an array that contains all keys if the input is an object or all indices if the input is an array. The filter \f[B]\f[CB]keys\f[B]\f[R] is equivalent to \f[B]\f[CB]keys_unsorted | sort\f[B]\f[R]. For example: .IP \[bu] 2 \f[B]\f[CB]{c: 1, b: 2, a: 1} | keys_unsorted \-\-> [\[dq]c\[dq], \[dq]b\[dq], \[dq]a\[dq]]\f[B]\f[R] .IP \[bu] 2 \f[B]\f[CB]{c: 1, b: 2, a: 1} | keys \-\-> [\[dq]a\[dq], \[dq]b\[dq], \[dq]c\[dq]]\f[B]\f[R] .IP \[bu] 2 \f[B]\f[CB][1, 2, 3] | keys_unsorted \-\-> [0, 1, 2]\f[B]\f[R] .IP \[bu] 2 \f[B]\f[CB][1, 2, 3] | keys \-\-> [0, 1, 2]\f[B]\f[R] .TP \f[I]Advanced\f[R] The filter \f[B]\f[CB]keys_unsorted\f[B]\f[R] is equivalent to \f[B]\f[CB]to_entries | map(.key)\f[B]\f[R] and \f[B]\f[CB][path(.[])[]]\f[B]\f[R]. For example: .IP \[bu] 2 \f[B]\f[CB]{a: 1, b: 2} | keys_unsorted \-\-> [\[dq]a\[dq], \[dq]b\[dq]]\f[B]\f[R] .IP \[bu] 2 \f[B]\f[CB]{a: 1, b: 2} | to_entries | map(.key) \-\-> [\[dq]a\[dq], \[dq]b\[dq]]\f[B]\f[R] .IP \[bu] 2 \f[B]\f[CB]{a: 1, b: 2} | [path(.[])[]] \-\-> [\[dq]a\[dq], \[dq]b\[dq]]\f[B]\f[R] .SS \f[B]\f[CB]to_entries\f[B]\f[R], \f[B]\f[CB]from_entries\f[B]\f[R], \f[B]\f[CB]with_entries(f)\f[B]\f[R] The filter \f[B]\f[CB]to_entries\f[B]\f[R] takes as input an array or an object. It converts them to an array of objects of the shape \f[B]\f[CB]{key: k, value: v}\f[B]\f[R], such that \f[B]\f[CB].[k]\f[B]\f[R] on the original input yields \f[B]\f[CB]v\f[B]\f[R]. For example: .IP \[bu] 2 \f[B]\f[CB][ 1, 2] | to_entries \-\-> [{\[dq]key\[dq]: 0 , \[dq]value\[dq]: 1}, {\[dq]key\[dq]: 1 , \[dq]value\[dq]: 2}]\f[B]\f[R] .IP \[bu] 2 \f[B]\f[CB]{a: 1, b: 2} | to_entries \-\-> [{\[dq]key\[dq]: \[dq]a\[dq], \[dq]value\[dq]: 1}, {\[dq]key\[dq]: \[dq]b\[dq], \[dq]value\[dq]: 2}]\f[B]\f[R] .PP The filter \f[B]\f[CB]from_entries\f[B]\f[R] constructs an object from an array of entries as given by \f[B]\f[CB]to_entries\f[B]\f[R]. For example, \f[B]\f[CB]{a: 1, b: 2} | to_entries | from_entries \-\-> {\[dq]a\[dq]: 1, \[dq]b\[dq]: 2}\f[B]\f[R]. .PP The filter \f[B]\f[CB]with_entries(f)\f[B]\f[R] is equivalent to \f[B]\f[CB]to_entries | map(f) | from_entries\f[B]\f[R]. For example, \f[B]\f[CB]{\[dq]a\[dq]: 1, \[dq]b\[dq]: 2} | with_entries(.key |= ascii_upcase) \-\-> {\[dq]A\[dq]: 1, \[dq]B\[dq]: 2}\f[B]\f[R] .SS STREAM CONSUMERS .SS \f[B]\f[CB]first\f[B]\f[R], \f[B]\f[CB]first(f)\f[B]\f[R], \f[B]\f[CB]last\f[B]\f[R], \f[B]\f[CB]last(f)\f[B]\f[R] The filter \f[B]\f[CB]first(f)\f[B]\f[R] yields the first output of \f[B]\f[CB]f\f[B]\f[R] if there is one, else nothing. For example, \f[B]\f[CB]first(1, 2, 3) \-\-> 1\f[B]\f[R] and \f[B]\f[CB]first(empty) \-\->\f[B]\f[R] (no output). .PP This filter stops evaluating \f[B]\f[CB]f\f[B]\f[R] after the first output, meaning that it yields an output even if \f[B]\f[CB]f\f[B]\f[R] yields infinitely many outputs. For example, \f[B]\f[CB]first(repeat(0)) \-\-> 0\f[B]\f[R] and \f[B]\f[CB]first(1, def f: f; f) \-\-> 1\f[B]\f[R]. .PP Similarly, \f[B]\f[CB]last(f)\f[B]\f[R] yields the last output of \f[B]\f[CB]f\f[B]\f[R] if there is one, else nothing. If \f[B]\f[CB]f\f[B]\f[R] yields an error, then the first error of \f[B]\f[CB]f\f[B]\f[R] is yielded. For example, \f[B]\f[CB]last(1, 2, 3) \-\-> 3\f[B]\f[R], \f[B]\f[CB]last(empty) \-\->\f[B]\f[R] (no output), and \f[B]\f[CB]try last(1, error(\[dq]fail\[dq]), 3) catch . \-\-> \[dq]fail\[dq]\f[B]\f[R]. .PP The filters \f[B]\f[CB]first\f[B]\f[R] and \f[B]\f[CB]last\f[B]\f[R] are short forms for \f[B]\f[CB]first(.[])\f[B]\f[R] and \f[B]\f[CB]last(.[])\f[B]\f[R], respectively. You can use them to retrieve the first/last element of an array, such as \f[B]\f[CB][1, 2, 3] | first, last \-\-> 1 3\f[B]\f[R]. .SS \f[B]\f[CB]limit($n; f)\f[B]\f[R] The filter \f[B]\f[CB]limit($n; f)\f[B]\f[R] yields the first \f[B]\f[CB]$n\f[B]\f[R] outputs of \f[B]\f[CB]f\f[B]\f[R]. If \f[B]\f[CB]$n <= 0\f[B]\f[R], it yields no outputs. For example: .IP \[bu] 2 \f[B]\f[CB]limit( 3; 1, 2 ) \-\-> 1 2\f[B]\f[R] .IP \[bu] 2 \f[B]\f[CB]limit( 3; 1, 2, 3, 4) \-\-> 1 2 3\f[B]\f[R] .IP \[bu] 2 \f[B]\f[CB]limit(\-1; 1, 2 ) \-\->\f[B]\f[R] (no output) .TP \f[I]Compatibility\f[R] When \f[B]\f[CB]$n < 0\f[B]\f[R], \f[B]\f[CB]jq\f[B]\f[R] yields an error instead. .SS \f[B]\f[CB]skip($n; f)\f[B]\f[R] The filter \f[B]\f[CB]skip($n; f)\f[B]\f[R] yields all outputs after the first \f[B]\f[CB]$n\f[B]\f[R] outputs of \f[B]\f[CB]f\f[B]\f[R]. If \f[B]\f[CB]$n <= 0\f[B]\f[R], it yields all outputs of \f[B]\f[CB]f\f[B]\f[R]. For example: .IP \[bu] 2 \f[B]\f[CB]skip( 3; 1, 2 ) \-\->\f[B]\f[R] (no output) .IP \[bu] 2 \f[B]\f[CB]skip( 1; 1, 2, 3, 4) \-\-> 2 3 4\f[B]\f[R] .IP \[bu] 2 \f[B]\f[CB]skip(\-1; 1, 2 ) \-\-> 1 2\f[B]\f[R] .SS \f[B]\f[CB]nth($i)\f[B]\f[R], \f[B]\f[CB]nth($i; f)\f[B]\f[R] The filter \f[B]\f[CB]nth($i; f)\f[B]\f[R] yields the \f[B]\f[CB]$i\f[B]\f[R]\-th output of \f[B]\f[CB]f\f[B]\f[R]. If \f[B]\f[CB]f\f[B]\f[R] yields less than \f[B]\f[CB]$i\f[B]\f[R] outputs, then this filter yields no output. For example: .IP \[bu] 2 \f[B]\f[CB]nth(0; 1, 2, 3) \-\-> 1\f[B]\f[R] .IP \[bu] 2 \f[B]\f[CB]nth(2; 1, 2, 3) \-\-> 3\f[B]\f[R] .IP \[bu] 2 \f[B]\f[CB]nth(3; 1, 2, 3) \-\->\f[B]\f[R] (no output) .PP The filter \f[B]\f[CB]nth($i)\f[B]\f[R] is a short form for \f[B]\f[CB].[$i]\f[B]\f[R]; e.g. \f[B]\f[CB][1, 2, 3] | nth(0) \-\-> 1\f[B]\f[R]. .SS \f[B]\f[CB]isempty(f)\f[B]\f[R] The filter \f[B]\f[CB]isempty(f)\f[B]\f[R] yields \f[B]\f[CB]true\f[B]\f[R] if \f[B]\f[CB]f\f[B]\f[R] yields no outputs, else \f[B]\f[CB]false\f[B]\f[R]. If the first output of \f[B]\f[CB]f\f[B]\f[R] is an error, \f[B]\f[CB]isempty(f)\f[B]\f[R] yields that error instead. For example: .IP \[bu] 2 \f[B]\f[CB]isempty( empty) \-\-> true\f[B]\f[R] .IP \[bu] 2 \f[B]\f[CB]isempty(1, 2) \-\-> false\f[B]\f[R] .IP \[bu] 2 \f[B]\f[CB]isempty(1, error) \-\-> false\f[B]\f[R] .IP \[bu] 2 \f[B]\f[CB]try isempty(error, 1) catch \[dq]fail\[dq] \-\-> \[dq]fail\[dq]\f[B]\f[R] .SS \f[B]\f[CB]any\f[B]\f[R], \f[B]\f[CB]any(p)\f[B]\f[R], \f[B]\f[CB]any(f; p)\f[B]\f[R] The filter \f[B]\f[CB]any(f; p)\f[B]\f[R] yields \f[B]\f[CB]true\f[B]\f[R] if any output of \f[B]\f[CB]f | p\f[B]\f[R] has the boolean value \f[B]\f[CB]true\f[B]\f[R], else \f[B]\f[CB]false\f[B]\f[R]. For example: .IP \[bu] 2 \f[B]\f[CB]any(0, 1, 2; . == 42) \-\-> false\f[B]\f[R] .IP \[bu] 2 \f[B]\f[CB]any(0, 1, 2; . == 42, . == 2) \-\-> true\f[B]\f[R] .PP The filters \f[B]\f[CB]any(p)\f[B]\f[R] and \f[B]\f[CB]any\f[B]\f[R] are short forms of \f[B]\f[CB]any(.[]; p)\f[B]\f[R] and \f[B]\f[CB]any(.)\f[B]\f[R], respectively. For example: .IP \[bu] 2 \f[B]\f[CB][1, 2, 3] | any(. % 2 == 0) \-\-> true\f[B]\f[R] .IP \[bu] 2 \f[B]\f[CB][false, true] | any \-\-> true\f[B]\f[R] .SS \f[B]\f[CB]all\f[B]\f[R], \f[B]\f[CB]all(p)\f[B]\f[R], \f[B]\f[CB]all(f; p)\f[B]\f[R] The filter \f[B]\f[CB]all(f; p)\f[B]\f[R] yields \f[B]\f[CB]true\f[B]\f[R] if all outputs of \f[B]\f[CB]f | p\f[B]\f[R] have the boolean value \f[B]\f[CB]true\f[B]\f[R], else \f[B]\f[CB]false\f[B]\f[R]. For example: .IP \[bu] 2 \f[B]\f[CB]all(0, 1, 2; . > 0) \-\-> false\f[B]\f[R] .IP \[bu] 2 \f[B]\f[CB]all(0, 1, 2; . >= 0) \-\-> true\f[B]\f[R] .PP The filters \f[B]\f[CB]all(p)\f[B]\f[R] and \f[B]\f[CB]all\f[B]\f[R] are defined analogously to \f[B]\f[CB]any(p)\f[B]\f[R] and \f[B]\f[CB]any\f[B]\f[R]. .SS \f[B]\f[CB]add\f[B]\f[R], \f[B]\f[CB]add(f)\f[B]\f[R] The filter \f[B]\f[CB]add(f)\f[B]\f[R] yields the sum of all elements yielded by \f[B]\f[CB]f\f[B]\f[R], or \f[B]\f[CB]null\f[B]\f[R] if \f[B]\f[CB]f\f[B]\f[R] yields no outputs. For example: .IP \[bu] 2 \f[B]\f[CB]add(1, 2, 3) \-\-> 6\f[B]\f[R] .IP \[bu] 2 \f[B]\f[CB]add(empty) \-\-> null\f[B]\f[R] .PP The filter \f[B]\f[CB]add\f[B]\f[R] is a short form of \f[B]\f[CB]add(.[])\f[B]\f[R]. You can use it to add all values of an array or object: .IP \[bu] 2 \f[B]\f[CB][1, 2, 3] | add \-\-> 6\f[B]\f[R] .IP \[bu] 2 \f[B]\f[CB]{a: 1, b: 2} | add \-\-> 3\f[B]\f[R] .TP \f[I]Advanced\f[R] The filter \f[B]\f[CB]add(f)\f[B]\f[R] is equivalent to \f[B]\f[CB]reduce f as $x (null; . + $x)\f[B]\f[R]. For example: \f[B]\f[CB]reduce (1, 2, 3) as $x (null; . + $x) \-\-> 6\f[B]\f[R]. .SS STREAM GENERATORS .SS \f[B]\f[CB]empty\f[B]\f[R] The filter \f[B]\f[CB]empty\f[B]\f[R] yields no output. .TP \f[I]Advanced\f[R] This filter is defined as \f[B]\f[CB]({}[] as $x | .)\f[B]\f[R]. While a simpler filter like \f[B]\f[CB][][]\f[B]\f[R] also yields no outputs, this rather contrived\-looking definition guarantees that \f[B]\f[CB]empty\f[B]\f[R] can be used on the left\-hand side of assignments. This comes into play when you use \f[B]\f[CB]select(p)\f[B]\f[R], which uses \f[B]\f[CB]empty\f[B]\f[R] under the hood. .SS \f[B]\f[CB]range($upto)\f[B]\f[R], \f[B]\f[CB]range($from; $upto)\f[B]\f[R], \f[B]\f[CB]range($from; $upto; $step)\f[B]\f[R] The filter \f[B]\f[CB]range($from; $upto; $step)\f[B]\f[R] adds \f[B]\f[CB]$step\f[B]\f[R] to \f[B]\f[CB]$from\f[B]\f[R] until it exceeds \f[B]\f[CB]$upto\f[B]\f[R]. For example: .IP \[bu] 2 \f[B]\f[CB]range(1; 9; 2) \-\-> 1 3 5 7\f[B]\f[R] .IP \[bu] 2 \f[B]\f[CB]range(1; 10; 2) \-\-> 1 3 5 7 9\f[B]\f[R] .IP \[bu] 2 \f[B]\f[CB]range(9; 1; \-2) \-\-> 9 7 5 3\f[B]\f[R] .IP \[bu] 2 \f[B]\f[CB]range(9; 0; \-2) \-\-> 9 7 5 3 1\f[B]\f[R] .PP The filter \f[B]\f[CB]range($from; $upto)\f[B]\f[R] is a short form of \f[B]\f[CB]range($from; $upto; 1)\f[B]\f[R] and the filter \f[B]\f[CB]range($upto)\f[B]\f[R] is a short form of \f[B]\f[CB]range(0; $upto)\f[B]\f[R]. For example: .IP \[bu] 2 \f[B]\f[CB]range(5) \-\-> 0 1 2 3 4\f[B]\f[R] .IP \[bu] 2 \f[B]\f[CB]range(2; 5) \-\-> 2 3 4\f[B]\f[R] .TP \f[I]Compatibility\f[R] In \f[B]\f[CB]jq\f[B]\f[R], \f[B]\f[CB]range/1\f[B]\f[R] and \f[B]\f[CB]range/2\f[B]\f[R] are more restrictive versions of \f[B]\f[CB]range/3\f[B]\f[R] that prohibit non\-numeric arguments. .TP \f[I]Advanced\f[R] The filter is equivalent to: .IP .EX def range($from; $to; $by): $from | if $by > 0 then while(. < $to; . + $by) elif $by < 0 then while(. > $to; . + $by) else while(. != $to; . + $by) end; range(1; 10; 2) \-\-> 1 3 5 7 9 .EE For that reason, we can also use it with other values than numbers: .IP \[bu] 2 \f[B]\f[CB]range(\[dq]\[dq]; \[dq]aaa\[dq]; \[dq]a\[dq]) \-\-> \[dq]\[dq] \[dq]a\[dq] \[dq]aa\[dq]\f[B]\f[R] .IP \[bu] 2 \f[B]\f[CB]range([]; [1, 1, 1]; [1]) \-\-> [] [1] [1, 1]\f[B]\f[R] This makes it quite easy to accidentally create an infinite sequence, e.g. by \f[B]\f[CB]range(\[dq]\[dq]; \[dq]b\[dq]; \[dq]a\[dq])\f[B]\f[R]. .SS \f[B]\f[CB]recurse\f[B]\f[R], \f[B]\f[CB]recurse(f)\f[B]\f[R] The filter \f[B]\f[CB]recurse(f)\f[B]\f[R] is equivalent to \f[B]\f[CB]., (f | recurse(f))\f[B]\f[R]. It first outputs its input, then runs \f[B]\f[CB]f\f[B]\f[R] and \f[B]\f[CB]recurse(f)\f[B]\f[R] on its outputs. This is useful to create infinite sequences. You can create a finite sequence by having \f[B]\f[CB]f\f[B]\f[R] return \f[B]\f[CB]empty\f[B]\f[R], e.g. via \f[B]\f[CB]select\f[B]\f[R]. For example: .IP \[bu] 2 \f[B]\f[CB]0 | limit(5; recurse(.+1)) \-\-> 0 1 2 3 4\f[B]\f[R] .IP \[bu] 2 \f[B]\f[CB]0 | recurse(.+1 | select(. < 5)) \-\-> 0 1 2 3 4\f[B]\f[R] .PP The filter \f[B]\f[CB]recurse(f; p)\f[B]\f[R] is equivalent to \f[B]\f[CB]recurse(f | select(p))\f[B]\f[R]. That means that it recurses only on outputs of \f[B]\f[CB]f\f[B]\f[R] for which \f[B]\f[CB]p\f[B]\f[R] yields a \f[B]\f[CB]true\f[B]\f[R] output. For example: .IP \[bu] 2 \f[B]\f[CB]0 | recurse(.+1; . < 5) \-\-> 0 1 2 3 4\f[B]\f[R] .PP The filter \f[B]\f[CB]recurse\f[B]\f[R] is a short form for \f[B]\f[CB]recurse(.[]?)\f[B]\f[R]. It returns all values recursively contained in the input, e.g. \f[B]\f[CB][1, [2], {a: 3}] | recurse \-\-> [1, [2], {\[dq]a\[dq]: 3}] 1 [2] 2 {\[dq]a\[dq]:3} 3\f[B]\f[R]. It yields the same outputs as \f[B]\f[CB]..\f[B]\f[R] (recursion). .TP \f[I]Advanced\f[R] We can write a Fibonacci generator as follows: .IP .EX def fib: def next: [.[1], add]; [0, 1] | recurse(next)[1]; limit(5; fib) \-\-> 1 1 2 3 5 .EE The \f[B]\f[CB]next\f[B]\f[R] filter takes an array with the two previous values (\f[B]\f[CB].[0], .[1]\f[B]\f[R]), and yields a new array containing the second previous value (\f[B]\f[CB].[1]\f[B]\f[R]) as well as the sum of the previous two values (\f[B]\f[CB]add\f[B]\f[R]). .SS \f[B]\f[CB]repeat(f)\f[B]\f[R] The filter \f[B]\f[CB]repeat(f)\f[B]\f[R] runs \f[B]\f[CB]f\f[B]\f[R] and yields its outputs over and over again. For example, \f[B]\f[CB]2 | limit(7; repeat(1, ., 3)) \-\-> 1 2 3 1 2 3 1\f[B]\f[R]. .TP \f[I]Advanced\f[R] This filter does not cache the outputs of \f[B]\f[CB]f\f[B]\f[R]. .SS \f[B]\f[CB]while(p; f)\f[B]\f[R], \f[B]\f[CB]until(p; f)\f[B]\f[R] The filter \f[B]\f[CB]while(p; f)\f[B]\f[R] yields its input and applies \f[B]\f[CB]f\f[B]\f[R] to it, while \f[B]\f[CB]p\f[B]\f[R] returns true. .PP The filter \f[B]\f[CB]until(p; f)\f[B]\f[R] applies \f[B]\f[CB]f\f[B]\f[R] to its input until \f[B]\f[CB]p\f[B]\f[R] returns true, at which point the filter returns its input. .PP Examples: .IP \[bu] 2 \f[B]\f[CB]0 | while(. <= 3; . + 1) \-\-> 0 1 2 3\f[B]\f[R] .IP \[bu] 2 \f[B]\f[CB]0 | until(. >= 3; . + 1) \-\-> 3\f[B]\f[R] .SS SELECTION The filters in this section classify their inputs or output them selectively. .SS \f[B]\f[CB]select(p)\f[B]\f[R] The filter \f[B]\f[CB]select(p)\f[B]\f[R] yields its input for each true output of \f[B]\f[CB]p\f[B]\f[R]. For example, \f[B]\f[CB](0, 1, \-1, 2, \-2) | select(. >= 0) \-\-> 0 1 2\f[B]\f[R]. .SS \f[B]\f[CB]nulls\f[B]\f[R], \f[B]\f[CB]booleans\f[B]\f[R], \f[B]\f[CB]numbers\f[B]\f[R], \f[B]\f[CB]strings\f[B]\f[R], \f[B]\f[CB]arrays\f[B]\f[R], \f[B]\f[CB]objects\f[B]\f[R] Any of these filters yields its input if it is of the given type, else nothing. For example: .IP \[bu] 2 \f[B]\f[CB]null, true, 0, \[dq]Hi!\[dq], [1, 2], {a: 1} | nulls \-\-> null\f[B]\f[R] .IP \[bu] 2 \f[B]\f[CB]null, true, 0, \[dq]Hi!\[dq], [1, 2], {a: 1} | booleans \-\-> true\f[B]\f[R] .IP \[bu] 2 \f[B]\f[CB]null, true, 0, \[dq]Hi!\[dq], [1, 2], {a: 1} | numbers \-\-> 0\f[B]\f[R] .IP \[bu] 2 \f[B]\f[CB]null, true, 0, \[dq]Hi!\[dq], [1, 2], {a: 1} | strings \-\-> \[dq]Hi!\[dq]\f[B]\f[R] .IP \[bu] 2 \f[B]\f[CB]null, true, 0, \[dq]Hi!\[dq], [1, 2], {a: 1} | arrays \-\-> [1, 2]\f[B]\f[R] .IP \[bu] 2 \f[B]\f[CB]null, true, 0, \[dq]Hi!\[dq], [1, 2], {a: 1} | objects \-\-> {\[dq]a\[dq]: 1}\f[B]\f[R] .TP \f[I]Advanced\f[R] These filters are equivalent to \f[B]\f[CB]select(. == null)\f[B]\f[R], \f[B]\f[CB]select(isboolean)\f[B]\f[R], \&..., \f[B]\f[CB]select(isobject)\f[B]\f[R]. .SS \f[B]\f[CB]isboolean\f[B]\f[R], \f[B]\f[CB]isnumber\f[B]\f[R], \f[B]\f[CB]isstring\f[B]\f[R], \f[B]\f[CB]isarray\f[B]\f[R], \f[B]\f[CB]isobject\f[B]\f[R] For every filter in this section, like \f[B]\f[CB]isboolean\f[B]\f[R], \&..., \f[B]\f[CB]isobject\f[B]\f[R], there is a corresponding filter in the previous section like, \f[B]\f[CB]booleans\f[B]\f[R], \&..., \f[B]\f[CB]objects\f[B]\f[R]. Any of these filters yields \f[B]\f[CB]true\f[B]\f[R] if its corresponding filter in the previous section yields some output, else \f[B]\f[CB]false\f[B]\f[R]. For example: .IP \[bu] 2 \f[B]\f[CB]null | isboolean \-\-> false\f[B]\f[R], because \f[B]\f[CB]null | booleans \-\->\f[B]\f[R] (no output). .IP \[bu] 2 \f[B]\f[CB]true | isboolean \-\-> true \f[B]\f[R], because \f[B]\f[CB]true | booleans \-\-> true\f[B]\f[R]. .TP \f[I]Compatibility\f[R] \f[B]\f[CB]jq\f[B]\f[R] does not implement these filters. .SS \f[B]\f[CB]normals\f[B]\f[R], \f[B]\f[CB]finites\f[B]\f[R] These filters return its input if \f[B]\f[CB]isnormal\f[B]\f[R] or \f[B]\f[CB]isfinite\f[B]\f[R] is \f[B]\f[CB]true\f[B]\f[R], respectively, else \f[B]\f[CB]false\f[B]\f[R]. .SS \f[B]\f[CB]values\f[B]\f[R], \f[B]\f[CB]iterables\f[B]\f[R], \f[B]\f[CB]scalars\f[B]\f[R] The filter \f[B]\f[CB]values\f[B]\f[R] yields its input if it is \f[B]not\f[R] \f[B]\f[CB]null\f[B]\f[R], else nothing. .PP If a value is either an array or an object, it is said to be \f[B]iterable\f[R]; otherwise, it is said to be \f[B]scalar\f[R]. (The iteration filter \f[B]\f[CB].[]\f[B]\f[R] succeeds on any iterable value, whereas it fails on any scalar.) .PP The filters \f[B]\f[CB]iterables\f[B]\f[R] and \f[B]\f[CB]scalars\f[B]\f[R] yield their input if it is iterable or scalar, respectively, else nothing. .PP Examples: .IP \[bu] 2 \f[B]\f[CB]null, true, 0, \[dq]Hi!\[dq], [1, 2], {a: 1} | values \-\-> true 0 \[dq]Hi!\[dq] [1, 2] {\[dq]a\[dq]: 1}\f[B]\f[R] .IP \[bu] 2 \f[B]\f[CB]null, true, 0, \[dq]Hi!\[dq], [1, 2], {a: 1} | scalars \-\-> null true 0 \[dq]Hi!\[dq]\f[B]\f[R] .IP \[bu] 2 \f[B]\f[CB]null, true, 0, \[dq]Hi!\[dq], [1, 2], {a: 1} | iterables \-\-> [1, 2] {\[dq]a\[dq]: 1}\f[B]\f[R] .SS \f[B]\f[CB]isnan\f[B]\f[R], \f[B]\f[CB]isinfinite\f[B]\f[R], \f[B]\f[CB]isfinite\f[B]\f[R], \f[B]\f[CB]isnormal\f[B]\f[R] The filter \f[B]\f[CB]isnan\f[B]\f[R] yields \f[B]\f[CB]true\f[B]\f[R] if its input is \f[B]\f[CB]NaN\f[B]\f[R], else \f[B]\f[CB]false\f[B]\f[R]. Note that it is \f[B]not\f[R] equivalent to \f[B]\f[CB]. == nan\f[B]\f[R], because \f[B]\f[CB]nan\f[B]\f[R] is not equal to itself; see equality. .PP The filter \f[B]\f[CB]isinfinite\f[B]\f[R] yields \f[B]\f[CB]true\f[B]\f[R] if its input is either \f[B]\f[CB]Infinity\f[B]\f[R] or \f[B]\f[CB]\-Infinity\f[B]\f[R], else \f[B]\f[CB]false\f[B]\f[R]. .PP The filter \f[B]\f[CB]isfinite\f[B]\f[R] yields \f[B]\f[CB]true\f[B]\f[R] if its input is a number that is not infinite, else \f[B]\f[CB]false\f[B]\f[R]. .PP The filter \f[B]\f[CB]isnormal\f[B]\f[R] yields \f[B]\f[CB]true\f[B]\f[R] if its input is a number that is neither \f[B]\f[CB]0\f[B]\f[R], \f[B]\f[CB]NaN\f[B]\f[R], nor infinite. .PP Examples: .IP \[bu] 2 \f[B]\f[CB]nan | isnan, isinfinite, isfinite, isnormal \-\-> true false true false\f[B]\f[R] .IP \[bu] 2 \f[B]\f[CB]infinite | isnan, isinfinite, isfinite, isnormal \-\-> false true false false\f[B]\f[R] .IP \[bu] 2 \f[B]\f[CB]0 | isnan, isinfinite, isfinite, isnormal \-\-> false false true false\f[B]\f[R] .IP \[bu] 2 \f[B]\f[CB]1 | isnan, isinfinite, isfinite, isnormal \-\-> false false true true\f[B]\f[R] .SS \f[B]\f[CB]type\f[B]\f[R] The filter \f[B]\f[CB]type\f[B]\f[R] returns the type of its input value as string. For example: .IP \[bu] 2 \f[B]\f[CB]null | type \-\-> \[dq]null\[dq]\f[B]\f[R] .IP \[bu] 2 \f[B]\f[CB]false | type \-\-> \[dq]boolean\[dq]\f[B]\f[R] .IP \[bu] 2 \f[B]\f[CB]0 | type \-\-> \[dq]number\[dq]\f[B]\f[R] .IP \[bu] 2 \f[B]\f[CB]\[dq]foo\[dq] | type \-\-> \[dq]string\[dq]\f[B]\f[R] .IP \[bu] 2 \f[B]\f[CB][1] | type \-\-> \[dq]array\[dq]\f[B]\f[R] .IP \[bu] 2 \f[B]\f[CB]{} | type \-\-> \[dq]object\[dq]\f[B]\f[R] .PP Note that both text strings and byte strings both have the same type \f[B]\f[CB]\[dq]string\[dq]\f[B]\f[R]. .TP \f[I]Advanced\f[R] The \f[B]\f[CB]type\f[B]\f[R] filter can be relatively slow to run; if you use it for simple comparisons such as \f[B]\f[CB]type == \[dq]string\[dq]\f[B]\f[R], then you can also use filters like \f[B]\f[CB]isstring\f[B]\f[R]. .SS MEMBERSHIP .SS \f[B]\f[CB]contains($x)\f[B]\f[R], \f[B]\f[CB]inside($x)\f[B]\f[R] The filter \f[B]\f[CB]contains($x)\f[B]\f[R] yields \f[B]\f[CB]true\f[B]\f[R] if any of the following conditions holds, else \f[B]\f[CB]false\f[B]\f[R]. .IP \[bu] 2 The input is a string and \f[B]\f[CB]$x\f[B]\f[R] is a substring of it. .IP \[bu] 2 The input is an array, \f[B]\f[CB]$x\f[B]\f[R] is an array, and for every value \f[B]\f[CB]v\f[B]\f[R] in \f[B]\f[CB]$x\f[B]\f[R], there is some value in the input that \f[B]\f[CB]contains(v)\f[B]\f[R]. .IP \[bu] 2 The input is an object, \f[B]\f[CB]$x\f[B]\f[R] is an object, and for every key\-value pair \f[B]\f[CB]{k: v}\f[B]\f[R] in \f[B]\f[CB]$x\f[B]\f[R], there is a value for the key \f[B]\f[CB]k\f[B]\f[R] in the input that \f[B]\f[CB]contains(v)\f[B]\f[R]. .IP \[bu] 2 The input is \f[B]\f[CB]null\f[B]\f[R], boolean, or a number, and \f[B]\f[CB]$x\f[B]\f[R] is equal to the input. .PP Examples: .IP \[bu] 2 \f[B]\f[CB]\[dq]Hello, world!\[dq] | contains(\[dq]world\[dq]) \-\-> true\f[B]\f[R] .IP \[bu] 2 \f[B]\f[CB][1, 2, 3] | contains([1, 3]) \-\-> true\f[B]\f[R] .IP \[bu] 2 \f[B]\f[CB][[1, 2], 3] | contains([3, [1]]) \-\-> true\f[B]\f[R] .IP \[bu] 2 \f[B]\f[CB]{a: 1, b: 2} | contains({a: 1}) \-\-> true\f[B]\f[R] .IP \[bu] 2 \f[B]\f[CB]{a: [1, 2]} | contains({a: [1]}) \-\-> true\f[B]\f[R] .IP \[bu] 2 \f[B]\f[CB]0 | contains(0) \-\-> true\f[B]\f[R] .PP The filter \f[B]\f[CB]inside($x)\f[B]\f[R] is a flipped version of \f[B]\f[CB]contains\f[B]\f[R]. For example, \f[B]\f[CB]\[dq]world\[dq] | inside(\[dq]Hello, world\[dq]) \-\-> true\f[B]\f[R]. .TP \f[I]Advanced\f[R] The filter \f[B]\f[CB]inside($x)\f[B]\f[R] is equivalent to \f[B]\f[CB]. as $i | $x | contains($i)\f[B]\f[R]. .SS \f[B]\f[CB]indices($x)\f[B]\f[R] The filter \f[B]\f[CB]indices($x)\f[B]\f[R] yields the following: .IP \[bu] 2 If the input and \f[B]\f[CB]$x\f[B]\f[R] are either both strings or both arrays, then it yields the indices \f[B]\f[CB]i\f[B]\f[R] for which \f[B]\f[CB].[i:][:$x | length] == $x\f[B]\f[R]; e.g. \f[B]\f[CB]\[dq]Alice, Bob, and Carol\[dq] | indices(\[dq], \[dq]) \-\-> [5, 10]\f[B]\f[R] and \f[B]\f[CB][0, 1, 2, 3, 1, 2, 3] | indices([1, 2]) \-\-> [1, 4]\f[B]\f[R]. .IP \[bu] 2 If the input is an array and \f[B]\f[CB]$x\f[B]\f[R] is not an array, then it yields the indices \f[B]\f[CB]i\f[B]\f[R] for which \f[B]\f[CB].[i] == $x\f[B]\f[R]; e.g. \f[B]\f[CB][0, 1, 2, 3, 1, 2, 3] | indices(1) \-\-> [1, 4]\f[B]\f[R]. .IP \[bu] 2 Otherwise, it yields an error. .PP This means that \f[B]\f[CB][[1, 2], 3] | indices([1, 2]) \-\-> []\f[B]\f[R], because the input array has neither \f[B]\f[CB]1\f[B]\f[R] nor \f[B]\f[CB]2\f[B]\f[R], just \f[B]\f[CB][1, 2]\f[B]\f[R] and \f[B]\f[CB]3\f[B]\f[R]. .TP \f[I]Advanced\f[R] We can verify the property given above: .IP .EX def verify($x): all(indices($x)[] as $i | .[$i:][:$x | length]; . == $x); (\[dq]Alice, Bob, and Carol\[dq] | verify(\[dq], \[dq] )), ([0, 1, 2, 3, 1, 2, 3] | verify([1, 2])) \-\-> true true .EE .SS \f[B]\f[CB]index($x)\f[B]\f[R], \f[B]\f[CB]rindex($x)\f[B]\f[R] The filters \f[B]\f[CB]index($x)\f[B]\f[R] and \f[B]\f[CB]rindex($x)\f[B]\f[R] are shorthand for \f[B]\f[CB]indices($x) | first\f[B]\f[R] and \f[B]\f[CB]indices($x) | last\f[B]\f[R], respectively. For example: .IP \[bu] 2 \f[B]\f[CB]\[dq]Alice, Bob, and Carol\[dq] | index(\[dq], \[dq]) \-\-> 5\f[B]\f[R] .IP \[bu] 2 \f[B]\f[CB][0, 1, 2, 3, 1, 2, 3] | rindex([1, 2]) \-\-> 4\f[B]\f[R] .IP \[bu] 2 \f[B]\f[CB]\[dq]Hello world!\[dq] | index(\[dq], \[dq]) \-\-> null\f[B]\f[R] .IP \[bu] 2 \f[B]\f[CB][0, 1, 2] | rindex(3) \-\-> null\f[B]\f[R] .SS \f[B]\f[CB]has($k)\f[B]\f[R], \f[B]\f[CB]in($x)\f[B]\f[R] The filter \f[B]\f[CB]has($k)\f[B]\f[R] yields \f[B]\f[CB]true\f[B]\f[R] if \f[B]\f[CB].[$k]\f[B]\f[R] points to data in the input, else \f[B]\f[CB]false\f[B]\f[R]. For example: .IP \[bu] 2 \f[B]\f[CB][1, 2, 3] | has( 0 , 3 ) \-\-> true false\f[B]\f[R] .IP \[bu] 2 \f[B]\f[CB]{a: 1, b: 2} | has(\[dq]a\[dq], \[dq]c\[dq]) \-\-> true false\f[B]\f[R] .PP The filter \f[B]\f[CB]in($x)\f[B]\f[R] is a flipped version of \f[B]\f[CB]has\f[B]\f[R], just like \f[B]\f[CB]inside\f[B]\f[R] is a flipped version of \f[B]\f[CB]contains\f[B]\f[R]. For example, \f[B]\f[CB]\[dq]a\[dq] | in({a: 1, b: 2}) \-\-> true\f[B]\f[R]. .TP \f[I]Compatibility\f[R] Whenever \f[B]\f[CB]has($k)\f[B]\f[R] in \f[B]\f[CB]jq\f[B]\f[R] returns \f[B]\f[CB]true\f[B]\f[R], jaq also returns \f[B]\f[CB]true\f[B]\f[R]. However, when \f[B]\f[CB]has($k)\f[B]\f[R] yields \f[B]\f[CB]true\f[B]\f[R] in jaq, it may also yield \f[B]\f[CB]false\f[B]\f[R] or an error in \f[B]\f[CB]jq\f[B]\f[R]: .IP \[bu] 2 \f[B]\f[CB][1, 2, 3] | has(\-1, \-2, \-3) \-\-> true true true\f[B]\f[R] (\f[B]\f[CB]false false false\f[B]\f[R] in \f[B]\f[CB]jq\f[B]\f[R]) .IP \[bu] 2 \f[B]\f[CB][1, 2, 3] | has({start: 1}) \-\-> true\f[B]\f[R] (error in \f[B]\f[CB]jq\f[B]\f[R]) This difference arises because in \f[B]\f[CB]jq\f[B]\f[R], \f[B]\f[CB]has($k)\f[B]\f[R] has a much weaker relationship with \f[B]\f[CB].[$k]\f[B]\f[R] than in jaq. The following properties hold in both \f[B]\f[CB]jq\f[B]\f[R] and jaq: .IP \[bu] 2 \f[B]\f[CB][1, 2, 3] | .[\-1, \-2, \-3] \-\-> 3 2 1\f[B]\f[R] .IP \[bu] 2 \f[B]\f[CB][1, 2, 3] | .[{start: 1}] \-\-> [2, 3]\f[B]\f[R] .TP \f[I]Advanced\f[R] For \f[B]\f[CB]null\f[B]\f[R], \f[B]\f[CB]has($k)\f[B]\f[R] always yields \f[B]\f[CB]false\f[B]\f[R]; e.g., \f[B]\f[CB]null | has(1) \-\-> false\f[B]\f[R]. For booleans, numbers, and text strings, \f[B]\f[CB]has($k)\f[B]\f[R] always yields an error; e.g. \f[B]\f[CB]true | try has(1) catch \-1 \-\-> \-1\f[B]\f[R]. For byte strings, arrays, and objects, \f[B]\f[CB]has($k)\f[B]\f[R] yields \f[B]\f[CB]true\f[B]\f[R] for the following values of \f[B]\f[CB]$k\f[B]\f[R]: .IP \[bu] 2 \f[B]\f[CB]\[dq]\[dq] | tobytes | all(has(range(\-length; length)); .) \-\-> true\f[B]\f[R] .IP \[bu] 2 \f[B]\f[CB][1, 2, 3] | all(has(range(\-length; length)); .) \-\-> true\f[B]\f[R] .IP \[bu] 2 \f[B]\f[CB]{a: 1, b: 2} | all(has(keys[] ); .) \-\-> true\f[B]\f[R] .SS UPDATES .SS \f[B]\f[CB]map(f)\f[B]\f[R], \f[B]\f[CB]map_values(f)\f[B]\f[R] The filter \f[B]\f[CB]map(f)\f[B]\f[R] obtains all values of the input (via \f[B]\f[CB].[]\f[B]\f[R]), applies \f[B]\f[CB]f\f[B]\f[R] to the values, and collects all results into an array. For example: .IP \[bu] 2 \f[B]\f[CB][1, 2, 3] | map(., .*2) \-\-> [1, 2, 2, 4, 3, 6]\f[B]\f[R]. .IP \[bu] 2 \f[B]\f[CB]{a: 1, b: 2} | map(., .*2) \-\-> [1, 2, 2, 4]\f[B]\f[R]. .IP \[bu] 2 \f[B]\f[CB][1, 2, 3, 4] | map(select(. % 2 == 0)) \-\-> [2, 4]\f[B]\f[R]. .PP The filter \f[B]\f[CB]map_values(f)\f[B]\f[R] has the same effect as \f[B]\f[CB]map(f)\f[B]\f[R] when the input is an array, but when the input is an object, \f[B]\f[CB]map_values(f)\f[B]\f[R] also outputs an object. For example: .IP \[bu] 2 \f[B]\f[CB][1, 2, 3, 4] | map_values(.*2) \-\-> [2, 4, 6, 8]\f[B]\f[R] .IP \[bu] 2 \f[B]\f[CB]{a: 1, b: 2} | map_values(.*2) \-\-> {\[dq]a\[dq]: 2, \[dq]b\[dq]: 4}\f[B]\f[R] .TP \f[I]Advanced\f[R] The filter \f[B]\f[CB]map(f)\f[B]\f[R] is equivalent to \f[B]\f[CB][.[] | f]\f[B]\f[R] and the filter \f[B]\f[CB]map_values(f)\f[B]\f[R] is equivalent to \f[B]\f[CB].[] |= f\f[B]\f[R]. .SS \f[B]\f[CB]walk(f)\f[B]\f[R] The filter \f[B]\f[CB]walk(f)\f[B]\f[R] recursively updates its input with \f[B]\f[CB]f\f[B]\f[R]. For example: .IP \[bu] 2 \f[B]\f[CB][[1, 2], [3]] | walk(numbers += 1) \-\-> [[2, 3], [4]]\f[B]\f[R] .TP \f[I]Advanced\f[R] In jaq, \f[B]\f[CB]walk(f)\f[B]\f[R] is defined as \f[B]\f[CB].. |= f\f[B]\f[R], whereas in \f[B]\f[CB]jq\f[B]\f[R], a definition similar to the following is used: .IP .EX def walk(f): def rec: (.[]? |= rec) | f; rec; .EE This is a more efficient version of: .IP .EX def walk(f): (.[]? |= walk(f)) | f; .EE We can show that in jaq, \f[B]\f[CB].. |= f\f[B]\f[R] and \f[B]\f[CB]jq\f[B]\f[R]\[cq]s definition of \f[B]\f[CB]walk(f)\f[B]\f[R] are equivalent. For this, we will use equivalences about pathless updates. First, let us recall that \f[B]\f[CB].. |= f\f[B]\f[R] is equivalent to the following in jaq: .IP .EX def rec_up: (.[]? | rec_up), .; rec_up |= f .EE We can thus unfold \f[B]\f[CB].. |= f\f[B]\f[R]: .IP .EX \&.. |= f === (unfolding .. |= f) rec_up |= f === (unfolding rec_up) ((.[]? | rec_up), .) |= f === (because (l, r) |= f === (l |= f) | (r |= f)) ((.[]? | rec_up) |= f) | (. |= f) === (because . |= f === f) ((.[]? | rec_up) |= f) | f === (because (l | r) |= f === l |= (r |= f)) (.[]? |= (rec_up |= f)) | f === (because rec_up |= f === .. |= f) (.[]? |= (.. |= f)) | f .EE We can see thus that \f[B]\f[CB].. |= f\f[B]\f[R] is equivalent to \f[B]\f[CB](.[]? |= (.. |= f)) | f\f[B]\f[R]. In the same sense, \f[B]\f[CB]walk(f)\f[B]\f[R] is equivalent to \f[B]\f[CB](.[]? |= walk(f)) | f\f[B]\f[R]. We can conclude that \f[B]\f[CB].. |= f\f[B]\f[R] is equivalent to \f[B]\f[CB]walk(f)\f[B]\f[R]. Note, however, that this equivalence does \f[B]not\f[R] hold in \f[B]\f[CB]jq\f[B]\f[R], because \f[B]\f[CB]jq\f[B]\f[R]\[cq]s updates work differently than jaq\[cq]s. The difference shows in particular when \f[B]\f[CB]f\f[B]\f[R] returns multiple values. .SS \f[B]\f[CB]del(f)\f[B]\f[R] The filter \f[B]\f[CB]del(f)\f[B]\f[R] deletes values at the locations given by \f[B]\f[CB]f\f[B]\f[R]. It is equivalent to \f[B]\f[CB]f |= empty\f[B]\f[R]. For example: .IP \[bu] 2 \f[B]\f[CB][1, 2, 3, 4] | del(.[] | select(. % 2 == 0)) \-\-> [1, 3]\f[B]\f[R] .IP \[bu] 2 \f[B]\f[CB][1, 2, 3] | del(.[1]) \-\-> [1, 3]\f[B]\f[R] .IP \[bu] 2 \f[B]\f[CB][1, 2, 3] | del(.[1:]) \-\-> [1]\f[B]\f[R] .IP \[bu] 2 \f[B]\f[CB]{a: 1, b: 2} | del(.a) \-\-> {\[dq]b\[dq]: 2}\f[B]\f[R] .SS PATHS .SS \f[B]\f[CB]path(f)\f[B]\f[R] The filter \f[B]\f[CB]path(f)\f[B]\f[R] records for each output of \f[B]\f[CB]f\f[B]\f[R] its position in the input, and yields that position as a \f[B]path\f[R]. A path is an array that may contain indices or \[lq]slice objects\[rq]. The latter must contain a \f[B]\f[CB]\[dq]start\[dq]\f[B]\f[R] and/or an \f[B]\f[CB]\[dq]end\[dq]\f[B]\f[R] key with an integer value. For example: .IP \[bu] 2 \f[B]\f[CB][{a: 1}, {a: 2}] | path(.[].a) \-\-> [0, \[dq]a\[dq]] [1, \[dq]a\[dq]]\f[B]\f[R] .IP \[bu] 2 \f[B]\f[CB][1, 2, 3] | path(.[1:][:\-1]) \-\-> [{\[dq]start\[dq]: 1}, {\[dq]end\[dq]: \-1}]\f[B]\f[R] .IP \[bu] 2 \f[B]\f[CB][1, 2, 3] | path(.[1: \-1]) \-\-> [{\[dq]start\[dq]: 1, \[dq]end\[dq]: \-1}]\f[B]\f[R] .PP If \f[B]\f[CB]f\f[B]\f[R] returns values that do not point to the input, then \f[B]\f[CB]path(f)\f[B]\f[R] yields an error. .IP \[bu] 2 \f[B]\f[CB]try path(0 ) catch \[dq]fail\[dq] \-\-> \[dq]fail\[dq]\f[B]\f[R] .IP \[bu] 2 \f[B]\f[CB]try path(. as $x | $x) catch \[dq]fail\[dq] \-\-> \[dq]fail\[dq]\f[B]\f[R] .TP \f[I]Advanced\f[R] The filter \f[B]\f[CB]path(f)\f[B]\f[R] is at the heart of how \f[B]\f[CB]jq\f[B]\f[R] executes assignments such as \f[B]\f[CB]p |= u\f[B]\f[R], whereas jaq pursues a different, \[lq]pathless\[rq] approach. See the section on path\-based updates for details on how \f[B]\f[CB]path(f)\f[B]\f[R] is calculated. .SS \f[B]\f[CB]paths\f[B]\f[R], \f[B]\f[CB]paths(p)\f[B]\f[R] The filter \f[B]\f[CB]paths\f[B]\f[R] yields the paths to all ancestor values of the input. It is equivalent to \f[B]\f[CB]skip(1; path(..))\f[B]\f[R]. .PP The filter \f[B]\f[CB]paths(p)\f[B]\f[R] yields the paths to all ancestor values of the input for which \f[B]\f[CB]p\f[B]\f[R] yields true. .PP Examples: .IP \[bu] 2 \f[B]\f[CB][1, {a: 2}] | paths \-\-> [0] [1] [1, \[dq]a\[dq]]\f[B]\f[R] .IP \[bu] 2 \f[B]\f[CB][1, {a: 2}] | paths(isnumber) \-\-> [0] [1, \[dq]a\[dq]]\f[B]\f[R] .IP \[bu] 2 \f[B]\f[CB][1, {a: 2}] | paths(isobject) \-\-> [1] \f[B]\f[R] .TP \f[I]Advanced\f[R] We have that \f[B]\f[CB]paths\f[B]\f[R] is equivalent to \f[B]\f[CB]paths(true)\f[B]\f[R]. Furthermore, \f[B]\f[CB]paths(p)\f[B]\f[R] is equivalent to: .IP .EX def paths(p): paths as $path | if getpath($path) | p then $path else empty end; [1, {a: 2}] | paths(isnumber) \-\-> [0] [1, \[dq]a\[dq]] .EE .SS \f[B]\f[CB]getpath($path)\f[B]\f[R] The filter \f[B]\f[CB]getpath($path)\f[B]\f[R] is the inverse filter for \f[B]\f[CB]path(f)\f[B]\f[R]. If \f[B]\f[CB]path(f)\f[B]\f[R] yields no error, then \f[B]\f[CB]getpath(path(f))\f[B]\f[R] yields the same outputs as \f[B]\f[CB]f\f[B]\f[R]. For example: .IP \[bu] 2 \f[B]\f[CB][{a: 1}, {a: 2}] | getpath([0, \[dq]a\[dq]], [1, \[dq]a\[dq]]) \-\-> 1 2\f[B]\f[R] .IP \[bu] 2 \f[B]\f[CB][1, 2, 3] | getpath([{\[dq]start\[dq]: 1}, {\[dq]end\[dq]: \-1}]) \-\-> [2]\f[B]\f[R] .IP \[bu] 2 \f[B]\f[CB][1, 2, 3] | getpath([{\[dq]start\[dq]: 1, \[dq]end\[dq]: \-1}]) \-\-> [2]\f[B]\f[R] .SS \f[B]\f[CB]setpath($path; $v)\f[B]\f[R] The filter \f[B]\f[CB]setpath($path; $v)\f[B]\f[R] sets the value at \f[B]\f[CB]$path\f[B]\f[R] to \f[B]\f[CB]$v\f[B]\f[R]. It is equivalent to \f[B]\f[CB]getpath($path) = $v\f[B]\f[R]. For example: .IP \[bu] 2 \f[B]\f[CB][[1, 2], [3, 4]] | setpath([1, 0]; 5) \-\-> [[1, 2], [5, 4]]\f[B]\f[R] .SS \f[B]\f[CB]delpaths($paths)\f[B]\f[R] The filter \f[B]\f[CB]delpaths($paths)\f[B]\f[R] takes an array of paths and deletes all corresponding values in the order given by the array. For example: .IP \[bu] 2 \f[B]\f[CB][1, 2, 3] | delpaths([[0]]) \-\-> [2, 3]\f[B]\f[R] .IP \[bu] 2 \f[B]\f[CB][{a: 1, b: 2}, 3] | delpaths([[0, \[dq]b\[dq]], [1]]) \-\-> [{\[dq]a\[dq]: 1}]\f[B]\f[R] .TP \f[I]Compatibility\f[R] In \f[B]\f[CB]jq\f[B]\f[R], the \f[B]\f[CB]$paths\f[B]\f[R] are interpreted relative to the \f[I]original\f[R] input value, whereas in jaq, they are interpreted relative to the \f[I]current\f[R] value. For example, \f[B]\f[CB][1, 2, 3] | delpaths([[0], [0]]) \-\-> [3]\f[B]\f[R] in jaq, because it first deletes the \f[B]\f[CB]0\f[B]\f[R]\-th element \f[B]\f[CB]1\f[B]\f[R] (yielding \f[B]\f[CB][2, 3]\f[B]\f[R]), then it deletes the \f[B]\f[CB]0\f[B]\f[R]\-th element \f[B]\f[CB]2\f[B]\f[R] (yielding \f[B]\f[CB][3]\f[B]\f[R]). Here, \f[B]\f[CB]jq\f[B]\f[R] yields \f[B]\f[CB][2, 3]\f[B]\f[R], because the \f[B]\f[CB]0\f[B]\f[R]\-th element always refers to the \f[B]\f[CB]0\f[B]\f[R]\-th element of the original input, which is \f[B]\f[CB]1\f[B]\f[R]. To use \f[B]\f[CB]delpaths\f[B]\f[R] in an interoperable fashion, use \f[B]\f[CB]$paths\f[B]\f[R] such that: .IP \[bu] 2 Paths to descendants come before paths to their ancestors. .IP \[bu] 2 Paths to array elements to the right come before paths to elements to the left. For example, \f[B]\f[CB]..\f[B]\f[R] returns \f[I]ancestors\f[R] before descendants and array elements to the \f[I]left\f[R] before elements to the right. To use the output of \f[B]\f[CB]..\f[B]\f[R] in \f[B]\f[CB]delpaths\f[B]\f[R], it suffices to reverse the order of its outputs: .IP \[bu] 2 \f[B]\f[CB][\[dq]a\[dq], 0, \[dq]b\[dq], 1] | delpaths([path(.. | strings)] | reverse) \-\-> [0, 1 ]\f[B]\f[R] (right) .IP \[bu] 2 \f[B]\f[CB][\[dq]a\[dq], 0, \[dq]b\[dq], 1] | delpaths([path(.. | strings)] ) \-\-> [0, \[dq]b\[dq]]\f[B]\f[R] (wrong) .SS \f[B]\f[CB]pick(f)\f[B]\f[R] The filter \f[B]\f[CB]pick(f)\f[B]\f[R] constructs an object that contains only those parts of the input that \f[B]\f[CB]f\f[B]\f[R] returns. For example: .IP \[bu] 2 \f[B]\f[CB]{a: {b: 1, c: 2}, d: 3} | pick(. ) \-\-> {\[dq]a\[dq]: {\[dq]b\[dq]: 1, \[dq]c\[dq]: 2}, \[dq]d\[dq]: 3}\f[B]\f[R] .IP \[bu] 2 \f[B]\f[CB]{a: {b: 1, c: 2}, d: 3} | pick(.a.c ) \-\-> {\[dq]a\[dq]: { \[dq]c\[dq]: 2} }\f[B]\f[R] .IP \[bu] 2 \f[B]\f[CB]{a: {b: 1, c: 2}, d: 3} | pick(.a.c, .d) \-\-> {\[dq]a\[dq]: { \[dq]c\[dq]: 2}, \[dq]d\[dq]: 3}\f[B]\f[R] .TP \f[I]Compatibility\f[R] In \f[B]\f[CB]jq\f[B]\f[R], \f[B]\f[CB]pick(f)\f[B]\f[R] also supports paths to arrays; for example: .IP \[bu] 2 \f[B]\f[CB][1, 2, 3] | pick(.[0 ])\f[B]\f[R] yields \f[B]\f[CB][1]\f[B]\f[R] .IP \[bu] 2 \f[B]\f[CB][1, 2, 3] | pick(.[1 ])\f[B]\f[R] yields \f[B]\f[CB][null, 2]\f[B]\f[R] .IP \[bu] 2 \f[B]\f[CB][1, 2, 3] | pick(.[1:])\f[B]\f[R] yields \f[B]\f[CB][2, 3]\f[B]\f[R] While implementing this functionality in jaq, I found many corner cases that would have made the proper documentation of this filter very complex. I also found a few surprising behaviours in \f[B]\f[CB]jq\f[B]\f[R], e.g. that \f[B]\f[CB][1, 2, 3] | pick(.[\-1])\f[B]\f[R] yields an error. In the end, I decided to support only the simpler and well\-understandable subset of paths to objects. .TP \f[I]Advanced\f[R] We have the property that \f[B]\f[CB]pick(f, g)\f[B]\f[R] is equivalent to \f[B]\f[CB]pick(f) * pick(g)\f[B]\f[R]. .SS BOOLEANS .SS \f[B]\f[CB]true\f[B]\f[R], \f[B]\f[CB]false\f[B]\f[R] The filters \f[B]\f[CB]true\f[B]\f[R] and \f[B]\f[CB]false\f[B]\f[R] yield the values \f[B]\f[CB]true\f[B]\f[R] and \f[B]\f[CB]false\f[B]\f[R], respectively: .IP \[bu] 2 \f[B]\f[CB]true \-\-> true\f[B]\f[R] .IP \[bu] 2 \f[B]\f[CB]false \-\-> false\f[B]\f[R] .SS \f[B]\f[CB]not\f[B]\f[R] The filter \f[B]\f[CB]not\f[B]\f[R] converts its input to its boolean value and returns its negation. For example: .IP \[bu] 2 \f[B]\f[CB]true | not \-\-> false\f[B]\f[R] .IP \[bu] 2 \f[B]\f[CB]false | not \-\-> true\f[B]\f[R] .IP \[bu] 2 \f[B]\f[CB]\[dq]foo\[dq] | not \-\-> false\f[B]\f[R] .TP \f[I]Advanced\f[R] The filter \f[B]\f[CB]not\f[B]\f[R] is equivalent to \f[B]\f[CB]if . then false else true end\f[B]\f[R]. We can obtain the boolean value of a value by \f[B]\f[CB]not | not\f[B]\f[R]; i.e. \f[B]\f[CB]\[dq]\[dq] | not | not \-\-> true\f[B]\f[R]. .SS \f[B]\f[CB]toboolean\f[B]\f[R] The filter \f[B]\f[CB]toboolean\f[B]\f[R] is for booleans what \f[B]\f[CB]tonumber\f[B]\f[R] is for numbers. For example: .IP \[bu] 2 \f[B]\f[CB] true | toboolean \-\-> true\f[B]\f[R] .IP \[bu] 2 \f[B]\f[CB] \[dq]true\[dq] | toboolean \-\-> true\f[B]\f[R] .IP \[bu] 2 \f[B]\f[CB]\[dq][true]\[dq] | try toboolean catch \[dq]fail\[dq] \-\-> \[dq]fail\[dq]\f[B]\f[R] .SS NUMBERS .SS \f[B]\f[CB]tonumber\f[B]\f[R] The filter \f[B]\f[CB]tonumber\f[B]\f[R] takes as input either a number or a string. If the input is a number, it is returned unchanged; if the input is a string, it is parsed to a number, failing if this does not succeed. For example: .IP \[bu] 2 \f[B]\f[CB] 42 | tonumber \-\-> 42\f[B]\f[R] .IP \[bu] 2 \f[B]\f[CB] \[dq]42\[dq] | tonumber \-\-> 42\f[B]\f[R] .IP \[bu] 2 \f[B]\f[CB]\[dq][42]\[dq] | try tonumber catch \[dq]fail\[dq] \-\-> \[dq]fail\[dq]\f[B]\f[R] .SS \f[B]\f[CB]infinite\f[B]\f[R], \f[B]\f[CB]nan\f[B]\f[R] The filters \f[B]\f[CB]infinite\f[B]\f[R] and \f[B]\f[CB]nan\f[B]\f[R] yield the floating\-point numbers \f[B]\f[CB]Infinity\f[B]\f[R] and \f[B]\f[CB]NaN\f[B]\f[R]: .IP \[bu] 2 \f[B]\f[CB]infinite \-\-> Infinity\f[B]\f[R] .IP \[bu] 2 \f[B]\f[CB]nan | isnan \-\-> true\f[B]\f[R] (we cannot test for equality with \f[B]\f[CB]NaN\f[B]\f[R] here, because \f[B]\f[CB]nan == nan \-\-> false\f[B]\f[R]) .TP \f[I]Advanced\f[R] We can also produce \f[B]\f[CB]Infinity\f[B]\f[R] and \f[B]\f[CB]NaN\f[B]\f[R] by: .IP \[bu] 2 \f[B]\f[CB]1 / 0 \-\-> Infinity\f[B]\f[R] .IP \[bu] 2 \f[B]\f[CB]0 / 0 | isnan \-\-> true\f[B]\f[R] .SS \f[B]\f[CB]abs\f[B]\f[R] The filter \f[B]\f[CB]abs\f[B]\f[R] yields the negation of the input if the input is smaller than \f[B]\f[CB]0\f[B]\f[R], else it yields the input. Note that due to this definition, strings, arrays, and objects are also returned unchanged, because they are larger than \f[B]\f[CB]0\f[B]\f[R]; see ordering. .PP Examples: .IP \[bu] 2 \f[B]\f[CB]\-2.0, \-1, 0, 1, 2.0 | abs \-\-> 2.0 1 0 1 2.0\f[B]\f[R] .IP \[bu] 2 \f[B]\f[CB]\[dq]foo\[dq], [], {} | abs \-\-> \[dq]foo\[dq] [] {}\f[B]\f[R] .SS \f[B]\f[CB]floor\f[B]\f[R], \f[B]\f[CB]round\f[B]\f[R], \f[B]\f[CB]ceil\f[B]\f[R] The filters \f[B]\f[CB]floor\f[B]\f[R], \f[B]\f[CB]round\f[B]\f[R] and \f[B]\f[CB]ceil\f[B]\f[R] round a number to its closest smaller integer, to its closest integer, and to its closest larger integer, respectively. For example: .IP \[bu] 2 \f[B]\f[CB] 0.5 | floor, round, ceil \-\-> 0 1 1\f[B]\f[R] .IP \[bu] 2 \f[B]\f[CB] 0.4 | floor, round, ceil \-\-> 0 0 1\f[B]\f[R] .IP \[bu] 2 \f[B]\f[CB] 0.0 | floor, round, ceil \-\-> 0 0 0\f[B]\f[R] .IP \[bu] 2 \f[B]\f[CB]\-0.4 | floor, round, ceil \-\-> \-1 0 0\f[B]\f[R] .IP \[bu] 2 \f[B]\f[CB]\-0.5 | floor, round, ceil \-\-> \-1 \-1 0\f[B]\f[R] .IP \[bu] 2 \f[B]\f[CB]0, 1 | round \-\-> 0 1\f[B]\f[R] .IP \[bu] 2 \f[B]\f[CB]nan | round | isnan \-\-> true\f[B]\f[R] .IP \[bu] 2 \f[B]\f[CB]infinite | round \-\-> Infinity\f[B]\f[R] .SS Math jaq implements many mathematical functions via \c .UR https://docs.rs/libm \f[B]\f[CB]libm\f[B]\f[R] .UE \c \&. If not specified otherwise, these filters take and return floating\-point numbers. .PP Zero\-argument filters: .IP \[bu] 2 \f[B]\f[CB]acos\f[B]\f[R] .IP \[bu] 2 \f[B]\f[CB]acosh\f[B]\f[R] .IP \[bu] 2 \f[B]\f[CB]asin\f[B]\f[R] .IP \[bu] 2 \f[B]\f[CB]asinh\f[B]\f[R] .IP \[bu] 2 \f[B]\f[CB]atan\f[B]\f[R] .IP \[bu] 2 \f[B]\f[CB]atanh\f[B]\f[R] .IP \[bu] 2 \f[B]\f[CB]cbrt\f[B]\f[R] .IP \[bu] 2 \f[B]\f[CB]cos\f[B]\f[R] .IP \[bu] 2 \f[B]\f[CB]cosh\f[B]\f[R] .IP \[bu] 2 \f[B]\f[CB]erf\f[B]\f[R] .IP \[bu] 2 \f[B]\f[CB]erfc\f[B]\f[R] .IP \[bu] 2 \f[B]\f[CB]exp\f[B]\f[R] .IP \[bu] 2 \f[B]\f[CB]exp10\f[B]\f[R] .IP \[bu] 2 \f[B]\f[CB]exp2\f[B]\f[R] .IP \[bu] 2 \f[B]\f[CB]expm1\f[B]\f[R] .IP \[bu] 2 \f[B]\f[CB]fabs\f[B]\f[R] .IP \[bu] 2 \f[B]\f[CB]frexp\f[B]\f[R], which returns pairs of (float, integer). .IP \[bu] 2 \f[B]\f[CB]gamma\f[B]\f[R] .IP \[bu] 2 \f[B]\f[CB]ilogb\f[B]\f[R], which returns integers. .IP \[bu] 2 \f[B]\f[CB]j0\f[B]\f[R] .IP \[bu] 2 \f[B]\f[CB]j1\f[B]\f[R] .IP \[bu] 2 \f[B]\f[CB]lgamma\f[B]\f[R] .IP \[bu] 2 \f[B]\f[CB]log\f[B]\f[R] .IP \[bu] 2 \f[B]\f[CB]log10\f[B]\f[R] .IP \[bu] 2 \f[B]\f[CB]log1p\f[B]\f[R] .IP \[bu] 2 \f[B]\f[CB]log2\f[B]\f[R] .IP \[bu] 2 \f[B]\f[CB]logb\f[B]\f[R] .IP \[bu] 2 \f[B]\f[CB]modf\f[B]\f[R], which returns pairs of (float, float). .IP \[bu] 2 \f[B]\f[CB]nearbyint\f[B]\f[R] .IP \[bu] 2 \f[B]\f[CB]pow10\f[B]\f[R] .IP \[bu] 2 \f[B]\f[CB]rint\f[B]\f[R] .IP \[bu] 2 \f[B]\f[CB]significand\f[B]\f[R] .IP \[bu] 2 \f[B]\f[CB]sin\f[B]\f[R] .IP \[bu] 2 \f[B]\f[CB]sinh\f[B]\f[R] .IP \[bu] 2 \f[B]\f[CB]sqrt\f[B]\f[R] .IP \[bu] 2 \f[B]\f[CB]tan\f[B]\f[R] .IP \[bu] 2 \f[B]\f[CB]tanh\f[B]\f[R] .IP \[bu] 2 \f[B]\f[CB]tgamma\f[B]\f[R] .IP \[bu] 2 \f[B]\f[CB]trunc\f[B]\f[R] .IP \[bu] 2 \f[B]\f[CB]y0\f[B]\f[R] .IP \[bu] 2 \f[B]\f[CB]y1\f[B]\f[R] .PP Two\-argument filters that ignore \f[B]\f[CB].\f[B]\f[R]: .IP \[bu] 2 \f[B]\f[CB]atan2\f[B]\f[R] .IP \[bu] 2 \f[B]\f[CB]copysign\f[B]\f[R] .IP \[bu] 2 \f[B]\f[CB]drem\f[B]\f[R] .IP \[bu] 2 \f[B]\f[CB]fdim\f[B]\f[R] .IP \[bu] 2 \f[B]\f[CB]fmax\f[B]\f[R] .IP \[bu] 2 \f[B]\f[CB]fmin\f[B]\f[R] .IP \[bu] 2 \f[B]\f[CB]fmod\f[B]\f[R] .IP \[bu] 2 \f[B]\f[CB]hypot\f[B]\f[R] .IP \[bu] 2 \f[B]\f[CB]jn\f[B]\f[R], which takes an integer as first argument. .IP \[bu] 2 \f[B]\f[CB]ldexp\f[B]\f[R], which takes an integer as second argument. .IP \[bu] 2 \f[B]\f[CB]nextafter\f[B]\f[R] .IP \[bu] 2 \f[B]\f[CB]nexttoward\f[B]\f[R] .IP \[bu] 2 \f[B]\f[CB]pow\f[B]\f[R] .IP \[bu] 2 \f[B]\f[CB]remainder\f[B]\f[R] .IP \[bu] 2 \f[B]\f[CB]scalb\f[B]\f[R] .IP \[bu] 2 \f[B]\f[CB]scalbln\f[B]\f[R], which takes as integer as second argument. .IP \[bu] 2 \f[B]\f[CB]yn\f[B]\f[R], which takes an integer as first argument. .PP Three\-argument filters that ignore \f[B]\f[CB].\f[B]\f[R]: .IP \[bu] 2 \f[B]\f[CB]fma\f[B]\f[R] .PP Examples: .IP \[bu] 2 \f[B]\f[CB](3.141592 | sin) < (\-5 | pow10) \-\-> true\f[B]\f[R] establishes that \f[B]\f[CB]sin(pi)\f[B]\f[R] is smaller than \f[B]\f[CB]10\[ha]\-5\f[B]\f[R]. .IP \[bu] 2 \f[B]\f[CB]fmax(2; 3) \-\-> 3.0\f[B]\f[R] .IP \[bu] 2 \f[B]\f[CB]fma(2; 3; 4) \-\-> 10.0\f[B]\f[R] .SS ARRAYS .SS \f[B]\f[CB]sort\f[B]\f[R], \f[B]\f[CB]sort_by(f)\f[B]\f[R] The filter \f[B]\f[CB]sort\f[B]\f[R] takes an array and sorts it. For example: .IP .EX [true, 1, \[dq]abc\[dq], [1], {\[dq]a\[dq]: 1}, null, false, 0, \[dq]ABC\[dq], [], {}] | sort \-\-> [null, false, true, 0, 1, \[dq]ABC\[dq], \[dq]abc\[dq], [], [1], {}, {\[dq]a\[dq]: 1}] .EE .PP The filter \f[B]\f[CB]sort_by(f)\f[B]\f[R] evaluates the filter \f[B]\f[CB]f\f[B]\f[R] for each value in the input array, and sorts the values by the output of \f[B]\f[CB]f\f[B]\f[R]. For example: .IP \[bu] 2 \f[B]\f[CB][0, 1, 2, 3] | sort_by(. % 2) \-\-> [0, 2, 1, 3]\f[B]\f[R] .IP \[bu] 2 \f[B]\f[CB][{a: 1, b: 2}, {a: 0, b: 3}] | sort_by(. ) \-\-> [{\[dq]a\[dq]: 0, \[dq]b\[dq]: 3}, {\[dq]a\[dq]: 1, \[dq]b\[dq]: 2}]\f[B]\f[R] .IP \[bu] 2 \f[B]\f[CB][{a: 1, b: 2}, {a: 0, b: 3}] | sort_by(.a) \-\-> [{\[dq]a\[dq]: 0, \[dq]b\[dq]: 3}, {\[dq]a\[dq]: 1, \[dq]b\[dq]: 2}]\f[B]\f[R] .IP \[bu] 2 \f[B]\f[CB][{a: 1, b: 2}, {a: 0, b: 3}] | sort_by(.b) \-\-> [{\[dq]a\[dq]: 1, \[dq]b\[dq]: 2}, {\[dq]a\[dq]: 0, \[dq]b\[dq]: 3}]\f[B]\f[R] .TP \f[I]Advanced\f[R] We have the following correspondences: .IP \[bu] 2 \f[B]\f[CB]sort_by\f[B]\f[R] is equivalent to \f[B]\f[CB]sort_by(.)\f[B]\f[R]. .IP \[bu] 2 \f[B]\f[CB]sort_by(f)\f[B]\f[R] is equivalent to \f[B]\f[CB]sort_by([f])\f[B]\f[R]. .SS \f[B]\f[CB]group_by(f)\f[B]\f[R] The filter \f[B]\f[CB]group_by(f)\f[B]\f[R] sorts its input array by \f[B]\f[CB]f\f[B]\f[R], then groups all values for which \f[B]\f[CB]f\f[B]\f[R] produced identical outputs into the same array. For example: .IP \[bu] 2 \f[B]\f[CB][\[dq]foo\[dq], \[dq]\[dq], \[dq]bar\[dq], \[dq]quux\[dq], \[dq]baz\[dq]] | group_by(length) \-\-> [[\[dq]\[dq]], [\[dq]foo\[dq], \[dq]bar\[dq], \[dq]baz\[dq]], [\[dq]quux\[dq]]]\f[B]\f[R] .IP \[bu] 2 \f[B]\f[CB][1, 2, 3, 4] | group_by(. % 2) \-\-> [[2, 4], [1, 3]]\f[B]\f[R] .SS \f[B]\f[CB]unique\f[B]\f[R], \f[B]\f[CB]unique_by(f)\f[B]\f[R] The filter \f[B]\f[CB]unique_by(f)\f[B]\f[R] sorts its input array by \f[B]\f[CB]f\f[B]\f[R]. If \f[B]\f[CB]f\f[B]\f[R] produces the same outputs for multiple values in the array, only the first is kept. For example: .IP \[bu] 2 \f[B]\f[CB][\[dq]foo\[dq], \[dq]\[dq], \[dq]bar\[dq], \[dq]quux\[dq], \[dq]baz\[dq]] | unique_by(length) \-\-> [\[dq]\[dq], \[dq]foo\[dq], \[dq]quux\[dq]]\f[B]\f[R] .IP \[bu] 2 \f[B]\f[CB][1, 2, 3, 4] | unique_by(. % 2) \-\-> [2, 1]\f[B]\f[R] .PP The filter \f[B]\f[CB]unique\f[B]\f[R] is equivalent to \f[B]\f[CB]unique_by(.)\f[B]\f[R]. It sorts the input array and removes any duplicates; e.g. \f[B]\f[CB][3, 2, 1, 3, 4] | unique \-\-> [1, 2, 3, 4]\f[B]\f[R]. .SS \f[B]\f[CB]min\f[B]\f[R], \f[B]\f[CB]max\f[B]\f[R], \f[B]\f[CB]min_by(f)\f[B]\f[R], \f[B]\f[CB]max_by(f)\f[B]\f[R] The filters \f[B]\f[CB]min\f[B]\f[R] and \f[B]\f[CB]max\f[B]\f[R] yield the smallest and largest element of an array, respectively. For example: .IP \[bu] 2 \f[B]\f[CB][1, 2, 3] | min \-\-> 1\f[B]\f[R] .IP \[bu] 2 \f[B]\f[CB][1, 2, 3] | max \-\-> 3\f[B]\f[R] .PP The filters \f[B]\f[CB]min_by(f)\f[B]\f[R] and \f[B]\f[CB]max_by(f)\f[B]\f[R] evaluate the filter \f[B]\f[CB]f\f[B]\f[R] for each value in the input array, and yield the value for which \f[B]\f[CB]f\f[B]\f[R] produces the smallest or largest output, respectively. For example: .IP \[bu] 2 \f[B]\f[CB][\[dq]abc\[dq], [1, 2], {\[dq]a\[dq]: 1}] | min_by(length) \-\-> {\[dq]a\[dq]: 1}\f[B]\f[R] .IP \[bu] 2 \f[B]\f[CB][\[dq]abc\[dq], [1, 2], {\[dq]a\[dq]: 1}] | max_by(length) \-\-> \[dq]abc\[dq]\f[B]\f[R] .PP You can yield multiple values in \f[B]\f[CB]f\f[B]\f[R] to break ties such as: .IP \[bu] 2 \f[B]\f[CB][\[dq]abc\[dq], [1, 2], {\[dq]a\[dq]: 1, \[dq]b\[dq]: 3}] | min_by(length, add?) \-\-> [1, 2]\f[B]\f[R] .TP \f[I]Advanced\f[R] We have the following correspondences: .IP \[bu] 2 \f[B]\f[CB]min\f[B]\f[R] and \f[B]\f[CB]max\f[B]\f[R] are equivalent to \f[B]\f[CB]min_by(.)\f[B]\f[R] and \f[B]\f[CB]max_by(.)\f[B]\f[R], respectively. .IP \[bu] 2 \f[B]\f[CB]min_by(f)\f[B]\f[R] and \f[B]\f[CB]max_by(f)\f[B]\f[R] are equivalent to \f[B]\f[CB]min_by([f])\f[B]\f[R] and \f[B]\f[CB]max_by([f])\f[B]\f[R], respectively. .SS \f[B]\f[CB]reverse\f[B]\f[R] The filter \f[B]\f[CB]reverse\f[B]\f[R] takes an array and reverses it. For example, \f[B]\f[CB][1, 2, 3] | reverse \-\-> [3, 2, 1]\f[B]\f[R]. .SS \f[B]\f[CB]transpose\f[B]\f[R] The filter \f[B]\f[CB]transpose\f[B]\f[R] takes an array of arrays and yields its transposition. .PP Examples: .IP \[bu] 2 \f[B]\f[CB][[1 , 2, 3], [4, 5, 6]] | transpose \-\-> [[1, 4], [2, 5], [3, 6]]\f[B]\f[R] .IP \[bu] 2 \f[B]\f[CB][[1], [2, 3], [4, 5, 6]] | transpose \-\-> [[1, 2, 4], [null, 3, 5], [null, null, 6]]\f[B]\f[R] .TP \f[I]Advanced\f[R] More precisely, \f[B]\f[CB]transpose\f[B]\f[R] yields an array \f[B]\f[CB]$t\f[B]\f[R] that contains \f[B]\f[CB]map(length) | max\f[B]\f[R] arrays of length \f[B]\f[CB]length\f[B]\f[R], such that \f[B]\f[CB]$t[x][y] == .[y][x]\f[B]\f[R] for every \f[B]\f[CB]x\f[B]\f[R] and \f[B]\f[CB]y\f[B]\f[R]. We can verify this: .IP .EX def verify: transpose as $t | ($t | length) == (map(length) | max), (range($t | length) as $x | ($t[$x] | length) == length, (range(length) as $y | $t[$x][$y] == .[$y][$x] ) ); [[1, 2, 3], [4, 5, 6]], [[1], [2, 3], [4, 5, 6]] | all(verify; .) \-\-> true true .EE .SS \f[B]\f[CB]flatten\f[B]\f[R], \f[B]\f[CB]flatten($depth)\f[B]\f[R] The filter \f[B]\f[CB]flatten\f[B]\f[R] flattens input arrays, and the filter \f[B]\f[CB]flatten($depth)\f[B]\f[R] flattens input arrays up to a certain depth. For example: .IP \[bu] 2 \f[B]\f[CB][1, [2, [3]], {a: [1, [2]]}] | flatten \-\-> [1, 2, 3 , {\[dq]a\[dq]: [1, [2]]}]\f[B]\f[R] .IP \[bu] 2 \f[B]\f[CB][1, [2, [3]], {a: [1, [2]]}] | flatten(0) \-\-> [1, [2, [3]], {\[dq]a\[dq]: [1, [2]]}]\f[B]\f[R] .IP \[bu] 2 \f[B]\f[CB][1, [2, [3]], {a: [1, [2]]}] | flatten(1) \-\-> [1, 2, [3] , {\[dq]a\[dq]: [1, [2]]}]\f[B]\f[R] .IP \[bu] 2 \f[B]\f[CB][1, [2, [3]], {a: [1, [2]]}] | flatten(2) \-\-> [1, 2, 3 , {\[dq]a\[dq]: [1, [2]]}]\f[B]\f[R] .IP \[bu] 2 \f[B]\f[CB]null, true, 0, \[dq]Hi\[dq] | flatten \-\-> [null] [true] [0] [\[dq]Hi\[dq]]\f[B]\f[R] .PP Note that \f[B]\f[CB]flatten\f[B]\f[R] does not impact arrays that are descendants of an object. .TP \f[I]Advanced\f[R] We can define \f[B]\f[CB]flatten/0\f[B]\f[R] and \f[B]\f[CB]flatten/1\f[B]\f[R] as: .IP .EX def flattens : if isarray then .[] | flattens end; def flattens($d): if isarray and $d >= 0 then .[] | flattens($d\-1) end; def flatten : [flattens ]; def flatten($d): [flattens($d)]; [1, [2, [3]], {\[dq]a\[dq]: [1, [2]]}] | flatten, flatten(0), flatten(1), flatten(2) \-\-> [1, 2, 3 , {\[dq]a\[dq]: [1, [2]]}] [1, [2, [3]], {\[dq]a\[dq]: [1, [2]]}] [1, 2, [3] , {\[dq]a\[dq]: [1, [2]]}] [1, 2, 3 , {\[dq]a\[dq]: [1, [2]]}] .EE .SS \f[B]\f[CB]bsearch($x)\f[B]\f[R] The filter \f[B]\f[CB]bsearch($x)\f[B]\f[R] takes a sorted array and performs a binary search for \f[B]\f[CB]$x\f[B]\f[R] in the array. If the array contains \f[B]\f[CB]$x\f[B]\f[R], then the filter yields a positive \f[B]\f[CB]$i\f[B]\f[R] such that \f[B]\f[CB].[$i] == $x\f[B]\f[R]; otherwise, the filter yields a negative \f[B]\f[CB]$i\f[B]\f[R] such that inserting \f[B]\f[CB]$x\f[B]\f[R] at the index \f[B]\f[CB]\-$i\-1\f[B]\f[R] in the array would preserve its the ordering. .PP Examples: .IP \[bu] 2 \f[B]\f[CB][0, 4, 8] | bsearch(8, 4, 0) \-\-> 2 1 0\f[B]\f[R] .IP \[bu] 2 \f[B]\f[CB][0, 4, 8] | bsearch(\-2, 2, 6, 10) \-\-> \-1 \-2 \-3 \-4\f[B]\f[R] .PP If the input array is not sorted, then the output of this filter is meaningless. .TP \f[I]Advanced\f[R] We can verify the property above for negative \f[B]\f[CB]$i\f[B]\f[R]. First, let us search for the value \f[B]\f[CB]6\f[B]\f[R] that is not in the input array: \f[B]\f[CB][0, 4, 8] | bsearch(6) \-\-> \-3\f[B]\f[R]. Now, the definition postulates that we can insert \f[B]\f[CB]6\f[B]\f[R] at the index \f[B]\f[CB]\-$i\-1\f[B]\f[R], which is \f[B]\f[CB]\-\-3\-1 \-\-> 2\f[B]\f[R]: \f[B]\f[CB][0, 4, 8] | .[2:2] = [6] \-\-> [0, 4, 6, 8]\f[B]\f[R]. We can see that the resulting array is sorted. .SS \f[B]\f[CB]combinations\f[B]\f[R], \f[B]\f[CB]combinations($n)\f[B]\f[R] The filter \f[B]\f[CB]combinations\f[B]\f[R] takes as input an array of arrays, such as \f[B]\f[CB][a1, ..., an]\f[B]\f[R]. It yields all combinations of the elements of the arrays \f[B]\f[CB]a1\f[B]\f[R] to \f[B]\f[CB]an\f[B]\f[R]: .IP .EX [[1, 2], [3, 4]] | combinations \-\-> [1, 3] [1, 4] [2, 3] [2, 4] .EE .PP When the input array is empty, \f[B]\f[CB]combinations\f[B]\f[R] yields an empty array; \f[B]\f[CB][] | combinations \-\-> []\f[B]\f[R]. .PP The filter \f[B]\f[CB]combinations($n)\f[B]\f[R] takes a single array \f[B]\f[CB]a1\f[B]\f[R] as input. Its output is equivalent to \f[B]\f[CB][a1, ..., a1] | combinations\f[B]\f[R], where \f[B]\f[CB]a1\f[B]\f[R] is repeated \f[B]\f[CB]$n\f[B]\f[R] times. .IP .EX [1, 2] | combinations(2) \-\-> [1, 1] [1, 2] [2, 1] [2, 2] .EE .TP \f[I]Advanced\f[R] And now for a little discourse to see how jaq implements \f[B]\f[CB]combinations\f[B]\f[R]. Given the same input data as above, \f[B]\f[CB]combinations\f[B]\f[R] yields the same as: .IP .EX [1, 2][] as $x1 | [3, 4][] as $x2 | [$x1, $x2] \-\-> [1, 3] [1, 4] [2, 3] [2, 4] .EE If we squint our eyes a little bit, then we might realise that this looks like a case for \f[B]\f[CB]reduce\f[B]\f[R]! But before we can write it like that, we have to massage it a bit further: First, instead of creating the sum at the very end, we can create the sums little by little: .IP .EX [] | [1, 2][] as $x1 | . + [$x1] | [3, 4][] as $x2 | . + [$x2] \-\-> [1, 3] [1, 4] [2, 3] [2, 4] .EE Next, we iterate over the arrays, instead of over the array elements: .IP .EX [] | [1, 2] as $a1 | . + ($a1[] | [.]) | [3, 4] as $a2 | . + ($a2[] | [.]) \-\-> [1, 3] [1, 4] [2, 3] [2, 4] .EE Now we are ready to write this via \f[B]\f[CB]reduce\f[B]\f[R]: .IP .EX reduce ([1, 2], [3, 4]) as $a ([]; . + ($a[] | [.])) \-\-> [1, 3] [1, 4] [2, 3] [2, 4] .EE This crucially hinges on jaq\[cq]s ability to use multiple outputs of \f[B]\f[CB]g\f[B]\f[R] in \f[B]\f[CB]reduce xs as $x (f; g)\f[B]\f[R]. In \f[B]\f[CB]jq\f[B]\f[R], this does not work, because \f[B]\f[CB]jq\f[B]\f[R] considers at most one output of \f[B]\f[CB]g\f[B]\f[R]. We can now pull out the data: .IP .EX [[1, 2], [3, 4]] | reduce .[] as $a ([]; . + ($a[] | [.])) \-\-> [1, 3] [1, 4] [2, 3] [2, 4] .EE There is an opportunity to improve performance here: Instead of creating an array with \f[B]\f[CB][.]\f[B]\f[R] every single time in the loop, we can just do that upfront, using an update. At the same time, we can wrap this up in a definition: .IP .EX def combinations: .[][] |= [.] | reduce .[] as $a ([]; . + $a[]); [[1, 2], [3, 4]] | combinations \-\-> [1, 3] [1, 4] [2, 3] [2, 4] .EE And that, ladies and gentleman, is how \f[B]\f[CB]combinations\f[B]\f[R] is implemented in jaq. When we measure performance, via something like \f[B]\f[CB]time $JQ \-n \[aq][limit(6; repeat([range(10)]))] | combinations | empty\[aq]\f[B]\f[R], I get that jaq takes 0.8 seconds and \f[B]\f[CB]jq\f[B]\f[R] takes 3.6 seconds, meaning that jaq is more than four times faster here. .SS TEXT STRINGS Unless stated otherwise, all filters in this section take a text string as input, and fail if the input is of any other type. .SS \f[B]\f[CB]tostring\f[B]\f[R] The filter \f[B]\f[CB]tostring\f[B]\f[R] converts its input to a string. Its output depends on the type of its input: .IP \[bu] 2 Text strings are returned unchanged, i.e. \f[B]\f[CB]\[dq]Hi\[dq] | tostring \-\-> \[dq]Hi\[dq]\f[B]\f[R]. .IP \[bu] 2 Byte strings are interpreted as text string, i.e. \f[B]\f[CB]\[dq]Hi\[dq] | tobytes | tostring \-\-> \[dq]Hi\[dq]\f[B]\f[R]. This takes constant time. .IP \[bu] 2 Any other value is formatted compactly as if output by \f[B]\f[CB]jaq \-c\f[B]\f[R]. For example: .RS 2 .IP \[bu] 2 \f[B]\f[CB]null | tostring \-\-> \[dq]null\[dq]\f[B]\f[R], .IP \[bu] 2 \f[B]\f[CB][0, 1] | tostring \-\-> \[dq][0,1]\[dq]\f[B]\f[R], .IP \[bu] 2 \f[B]\f[CB]{a: 1} | tostring \-\-> \[dq]{\[rs]\[dq]a\[rs]\[dq]:1}\[dq]\f[B]\f[R]. .RE .TP \f[I]Advanced\f[R] String interpolation without an explicit format, such as \f[B]\f[CB]\[dq]\[rs](null) and \[rs]([0, 1])\[dq] \-\-> \[dq]null and [0,1]\[dq]\f[B]\f[R], behaves as if the output of every interpolated filter was piped through \f[B]\f[CB]tostring\f[B]\f[R]. .SS \f[B]\f[CB]utf8bytelength\f[B]\f[R] The filter \f[B]\f[CB]utf8bytelength\f[B]\f[R] yields the number of bytes of the input string. It is equivalent to \f[B]\f[CB]tobytes | length\f[B]\f[R], but different from \f[B]\f[CB]length\f[B]\f[R], which counts the number of \f[B]characters\f[R]. .PP For example, \f[B]\f[CB]\[dq]ゼノギアス\[dq] | length, utf8bytelength, (tobytes | length) \-\-> 5 15 15\f[B]\f[R]. .SS \f[B]\f[CB]startswith($s)\f[B]\f[R], \f[B]\f[CB]endswith($s)\f[B]\f[R] The filter \f[B]\f[CB]startswith($s)\f[B]\f[R] yields \f[B]\f[CB]true\f[B]\f[R] if the input string starts with the string \f[B]\f[CB]$s\f[B]\f[R], else \f[B]\f[CB]false\f[B]\f[R]. Similar for \f[B]\f[CB]endswith($s)\f[B]\f[R]. For example: .IP \[bu] 2 \f[B]\f[CB]\[dq]ゼノギアス\[dq] | startswith(\[dq]ゼノ\[dq]) \-\-> true\f[B]\f[R] .IP \[bu] 2 \f[B]\f[CB]\[dq]ゼノギアス\[dq] | endswith(\[dq]ギアス\[dq]) \-\-> true\f[B]\f[R] .SS \f[B]\f[CB]trim\f[B]\f[R], \f[B]\f[CB]ltrim\f[B]\f[R], \f[B]\f[CB]rtrim\f[B]\f[R] The filters \f[B]\f[CB]ltrim\f[B]\f[R] and \f[B]\f[CB]rtrim\f[B]\f[R] remove from the input string all leading and trailing whitespace, respectively. Here, whitespace corresponds to the \f[B]\f[CB]White_Space\f[B]\f[R] Unicode property. The filter \f[B]\f[CB]trim\f[B]\f[R] is equivalent to \f[B]\f[CB]ltrim | rtrim\f[B]\f[R]. .PP For example: .IP \[bu] 2 \f[B]\f[CB]\[dq] \[rs]t\[rs]n Bonjour !   \[rs]r  \[dq] | ltrim \-\-> \[dq]Bonjour !   \[rs]r  \[dq]\f[B]\f[R] .IP \[bu] 2 \f[B]\f[CB]\[dq] \[rs]t\[rs]n Bonjour !   \[rs]r  \[dq] | rtrim \-\-> \[dq] \[rs]t\[rs]n Bonjour !\[dq]\f[B]\f[R] .PP Note that there are a few quite unusual whitespace characters in this string. .SS \f[B]\f[CB]ltrimstr($s)\f[B]\f[R], \f[B]\f[CB]rtrimstr($s)\f[B]\f[R] The filters \f[B]\f[CB]ltrimstr($s)\f[B]\f[R] and \f[B]\f[CB]rtrimstr($s)\f[B]\f[R] remove a single occurrence of \f[B]\f[CB]$s\f[B]\f[R] from the start or the end of the string, respectively. If there is no such occurrence, the original string is returned. For example: .IP \[bu] 2 \f[B]\f[CB]\[dq]foofoobar\[dq] | ltrimstr(\[dq]foo\[dq]) \-\-> \[dq]foobar\[dq]\f[B]\f[R] .IP \[bu] 2 \f[B]\f[CB]\[dq]foobarbar\[dq] | rtrimstr(\[dq]bar\[dq]) \-\-> \[dq]foobar\[dq]\f[B]\f[R] .SS \f[B]\f[CB]explode\f[B]\f[R], \f[B]\f[CB]implode\f[B]\f[R] The filter \f[B]\f[CB]explode\f[B]\f[R] yields an array containing a positive number for each valid Unicode code point of the input string and a negative number for each byte of each invalid Unicode code unit. For example: .IP .EX \[dq]Dear ☀️\[dq] + (255 | tobytes | tostring) | explode \-\-> [68,101,97,114,32,9728,65039,\-255] .EE .PP Here, we can see that \f[B]\f[CB]\[dq]☀️\[dq]\f[B]\f[R] has turned into two code points, namely \f[B]\f[CB]9728\f[B]\f[R] and \f[B]\f[CB]65039\f[B]\f[R], whereas the invalid \f[B]\f[CB]FF\f[B]\f[R] byte (= 255) has become \f[B]\f[CB]\-255\f[B]\f[R]. .PP The inverse filter of \f[B]\f[CB]explode\f[B]\f[R] is \f[B]\f[CB]implode\f[B]\f[R]: .IP .EX [68,101,97,114,32,9728,65039, \-255] | implode[:\-1] \-\-> \[dq]Dear ☀️\[dq] .EE .PP (I omitted the \f[B]\f[CB]FF\f[B]\f[R] byte at the end, because it is hard to save in a text editor.) .TP \f[I]Compatibility\f[R] \f[B]\f[CB]jq\f[B]\f[R] does not permit invalid code units in text strings, so it returns and accepts only natural numbers in \f[B]\f[CB]explode\f[B]\f[R] and \f[B]\f[CB]implode\f[B]\f[R]. .SS \f[B]\f[CB]split($s)\f[B]\f[R] This filter yields \f[B]\f[CB]. / $s\f[B]\f[R] if its input \f[B]\f[CB].\f[B]\f[R] and \f[B]\f[CB]$s\f[B]\f[R] are both strings, else it fails. See the section on division for details. .PP Note that there is also \f[B]\f[CB]split($re; $flags)\f[B]\f[R] that splits by a regex. .SS \f[B]\f[CB]join($s)\f[B]\f[R] The filter \f[B]\f[CB]join($s)\f[B]\f[R] takes as input an array \f[B]\f[CB][x1, ..., xn]\f[B]\f[R] and yields \f[B]\f[CB]\[dq]\[dq]\f[B]\f[R] if the array is empty, otherwise \f[B]\f[CB]\[dq]\[rs](x1)\[dq] + $s + ... + $s + \[dq]\[rs](xn)\[dq]\f[B]\f[R]. That is, it concatenates the string representations of the array values interspersed with \f[B]\f[CB]$s\f[B]\f[R]. .PP For example, to memorise the hierarchy of values in jq: \f[B]\f[CB][\[dq]null\[dq], \[dq]boolean\[dq], \[dq]number\[dq], \[dq]string\[dq], \[dq]array\[dq], \[dq]object\[dq]] | join(\[dq] < \[dq]) \-\-> \[dq]null < boolean < number < string < array < object\[dq]\f[B]\f[R]. .TP \f[I]Compatibility\f[R] Unlike jq, jaq does not map \f[B]\f[CB]null\f[B]\f[R] values in the array to \f[B]\f[CB]\[dq]\[dq]\f[B]\f[R], nor does it reject array or object values in the array. .SS \f[B]\f[CB]ascii_downcase\f[B]\f[R], \f[B]\f[CB]ascii_upcase\f[B]\f[R] The filters \f[B]\f[CB]ascii_downcase\f[B]\f[R] and \f[B]\f[CB]ascii_upcase\f[B]\f[R] convert all ASCII letters in the input string to their lower/upper case variants, respectively. For example: .IP \[bu] 2 \f[B]\f[CB]\[dq]Der λΠ\-Kalkül\[dq] | ascii_downcase \-\-> \[dq]der λΠ\-kalkül\[dq]\f[B]\f[R] .IP \[bu] 2 \f[B]\f[CB]\[dq]Der λΠ\-Kalkül\[dq] | ascii_upcase \-\-> \[dq]DER λΠ\-KALKüL\[dq]\f[B]\f[R] .SS TEXT STRING FORMATTING The filters in this section can be prefixed to strings to influence string interpolation. However, these filters can also be used outside of string interpolation. For example: .IP \[bu] 2 \f[B]\f[CB]\[dq]1 + 2 * 3\[dq] | \[at]uri \[dq]https://duckduckgo.com/?q=\[rs](.)\[dq] \-\-> \[dq]https://duckduckgo.com/?q=1%20%2B%202%20%2A%203\[dq]\f[B]\f[R] .IP \[bu] 2 \f[B]\f[CB]\[dq]1 + 2 * 3\[dq] | \[at]uri \-\-> \[dq]1%20%2B%202%20%2A%203\[dq]\f[B]\f[R] .PP If not indicated otherwise, all filters in this section convert their input to a string with \f[B]\f[CB]tostring\f[B]\f[R] and yield a single string output. As result, byte strings are treated like equivalent text strings; e.g. \f[B]\f[CB]\[dq]Hello world!\[dq] | (tobytes | \[at]base64) == \[at]base64 \-\-> true\f[B]\f[R]. .TP \f[I]Compatibility\f[R] Unlike in \f[B]\f[CB]jq\f[B]\f[R], you can define you own filters that start with \f[B]\f[CB]\[at]\f[B]\f[R]; for example, \f[B]\f[CB]def \[at]xml: \[at]html;\f[B]\f[R] .SS \f[B]\f[CB]\[at]text\f[B]\f[R] The filter \f[B]\f[CB]\[at]text\f[B]\f[R] is equivalent to \f[B]\f[CB]tostring\f[B]\f[R]. .SS \f[B]\f[CB]\[at]json\f[B]\f[R] The filter \f[B]\f[CB]\[at]json\f[B]\f[R] is equivalent to \f[B]\f[CB]tojson\f[B]\f[R]. .SS \f[B]\f[CB]\[at]csv\f[B]\f[R], \f[B]\f[CB]\[at]tsv\f[B]\f[R] The filters \f[B]\f[CB]\[at]csv\f[B]\f[R] and \f[B]\f[CB]\[at]tsv\f[B]\f[R] are equivalent to \f[B]\f[CB]tocsv\f[B]\f[R] and \f[B]\f[CB]totsv\f[B]\f[R], respectively. .SS \f[B]\f[CB]\[at]html\f[B]\f[R], \f[B]\f[CB]\[at]htmld\f[B]\f[R] The filter \f[B]\f[CB]\[at]html\f[B]\f[R] escapes a string so that it can be embedded in an HTML document. It replaces the following characters by HTML version: .PP .TS tab(@); l l l l l l. T{ .PP Text T}@T{ .PP \f[B]\f[CB]<\f[B]\f[R] T}@T{ .PP \f[B]\f[CB]>\f[B]\f[R] T}@T{ .PP \f[B]\f[CB]&\f[B]\f[R] T}@T{ .PP \f[B]\f[CB]\[aq]\f[B]\f[R] T}@T{ .PP \f[B]\f[CB]\[dq]\f[B]\f[R] T} T{ .PP HTML T}@T{ .PP \f[B]\f[CB]<\f[B]\f[R] T}@T{ .PP \f[B]\f[CB]>\f[B]\f[R] T}@T{ .PP \f[B]\f[CB]&\f[B]\f[R] T}@T{ .PP \f[B]\f[CB]'\f[B]\f[R] T}@T{ .PP \f[B]\f[CB]"\f[B]\f[R] T} .TE .PP The filter \f[B]\f[CB]\[at]htmld\f[B]\f[R] reverses the effect of \f[B]\f[CB]\[at]html\f[B]\f[R]. For example: .IP .EX \[dq]\[rs]\[dq]1 < 2 & 2 > 1\[rs]\[dq], that\[aq]s what he said.\[dq] | \[at]html | ., \[at]htmld \-\-> \[dq]"1 < 2 & 2 > 1", that's what he said.\[dq] \[dq]\[rs]\[dq]1 < 2 & 2 > 1\[rs]\[dq], that\[aq]s what he said.\[dq] .EE .TP \f[I]Compatibility\f[R] \f[B]\f[CB]jq\f[B]\f[R] does not support \f[B]\f[CB]\[at]htmld\f[B]\f[R]. .SS \f[B]\f[CB]\[at]base64\f[B]\f[R], \f[B]\f[CB]\[at]base64d\f[B]\f[R] The filter \f[B]\f[CB]\[at]base64\f[B]\f[R] \c .UR https://en.wikipedia.org/wiki/Base64 Base64 .UE \c \-encodes its input. The filter \f[B]\f[CB]\[at]base64d\f[B]\f[R] reverses this operation. For example: .IP .EX \[dq]Hello world!\[dq] | \[at]base64 | ., \[at]base64d \-\-> \[dq]SGVsbG8gd29ybGQh\[dq] \[dq]Hello world!\[dq] .EE .TP \f[I]Compatibility\f[R] In jaq, \f[B]\f[CB]\[at]base64d\f[B]\f[R] only succeeds if its whole input is a valid Base64 string. In contrast, \f[B]\f[CB]jq\f[B]\f[R] accepts also strings where only a part is valid Base64, thus potentially leading to hidden data corruption. See \c .UR https://github.com/01mf02/jaq/issues/282 #282 .UE \c for a detailed discussion. .SS \f[B]\f[CB]\[at]uri\f[B]\f[R], \f[B]\f[CB]\[at]urid\f[B]\f[R] The filter \f[B]\f[CB]\[at]uri\f[B]\f[R] applies \c .UR https://en.wikipedia.org/wiki/Percent-encoding percent\-encoding .UE \c \ to encode arbitrary data in a uniform resource identifier (URI). The filter \f[B]\f[CB]\[at]urid\f[B]\f[R] reverses this encoding. For example: .IP \[bu] 2 \f[B]\f[CB]\[dq]Hello, World!\[dq] | \[at]uri \-\-> \[dq]Hello%2C%20World%21\[dq]\f[B]\f[R] .IP \[bu] 2 \f[B]\f[CB]\[dq]Hello, World!\[dq] | \[at]uri | \[at]urid \-\-> \[dq]Hello, World!\[dq]\f[B]\f[R] .TP \f[I]Advanced\f[R] The HTML version of this manual is created with jaq, and \f[B]\f[CB]\[at]uri\f[B]\f[R] is used to encode the examples to create links to the jaq playground. .SS \f[B]\f[CB]\[at]sh\f[B]\f[R] The filter \f[B]\f[CB]\[at]sh\f[B]\f[R] escapes data for constructing Unix command\-line prompts. It performs different things depending on its input type: .IP \[bu] 2 \f[B]\f[CB]null\f[B]\f[R], boolean, number: Convert to string via \f[B]\f[CB]tostring\f[B]\f[R]. .IP \[bu] 2 String: Replace occurrences of \f[B]\f[CB]\[aq]\f[B]\f[R] by \f[B]\f[CB]\[aq]\[rs]\[aq]\[aq]\f[B]\f[R] and surround by \f[B]\f[CB]\[aq]\f[B]\f[R]. .IP \[bu] 2 Array of scalars: Apply \f[B]\f[CB]\[at]sh\f[B]\f[R] to elements and join the results with \f[B]\f[CB]\[dq] \[dq]\f[B]\f[R] as separator. .IP \[bu] 2 Fail for any other type of value. .PP Examples: .IP \[bu] 2 \f[B]\f[CB]null, true, 1 | \[at]sh \-\-> \[dq]null\[dq] \[dq]true\[dq] \[dq]1\[dq]\f[B]\f[R] .IP \[bu] 2 \f[B]\f[CB]\[dq]It\[aq]s green!\[dq] | \[at]sh \-\-> \[dq]\[aq]It\[aq]\[rs]\[rs]\[aq]\[aq]s green!\[aq]\[dq]\f[B]\f[R] .IP \[bu] 2 \f[B]\f[CB][\[dq]jaq\[dq], \[dq]\-n\[dq], \[dq]\-\-arg\[dq], \[dq]slogan\[dq], \[dq]It\[aq]s green!\[dq], \[dq]$slogan\[dq]] | \[at]sh \-\-> \[dq]\[aq]jaq\[aq] \[aq]\-n\[aq] \[aq]\-\-arg\[aq] \[aq]slogan\[aq] \[aq]It\[aq]\[rs]\[rs]\[aq]\[aq]s green!\[aq] \[aq]$slogan\[aq]\[dq]\f[B]\f[R] .TP \f[I]Advanced\f[R] When copy\-pasting the output of the previous example to your terminal, be sure to replace \f[B]\f[CB]\[rs]\[rs]\f[B]\f[R] by \f[B]\f[CB]\[rs]\[ga] before. That is, you should end up with \f[B]\f[R]\[cq]jaq\[cq] `\-n' `\[en]arg' `slogan' `It'\[aq]`s green!' `$slogan'\f[B]\f[CB], which you can execute in good conscience. Unescaping can be avoided by running \f[B]\f[R]jaq\f[B]\f[CB] with [\f[B]\f[R]\[en]raw\-output\f[B]\f[CB]](#\-\-raw\-output), which does not escape \f[B]\f[R]\[ga] with \f[B]\f[CB]\[rs]\[rs]\f[B]\f[R] in the first place.) .SS BYTE STRINGS .SS \f[B]\f[CB]tobytes\f[B]\f[R] The filter \f[B]\f[CB]tobytes\f[B]\f[R] converts its input to a byte string. Its output depends on the type of input: .IP \[bu] 2 Natural number in the range \f[B]\f[CB]0\f[B]\f[R] to \f[B]\f[CB]255\f[B]\f[R] (\f[B]\f[CB]0xFF\f[B]\f[R]): Yields a byte string with a single byte, e.g. \f[B]\f[CB]0 | tobytes \-\-> b\[dq]\[rs]x00\[dq]\f[B]\f[R]. .IP \[bu] 2 Text string: Yields a byte string containing the underlying bytes of the text string, e.g. \f[B]\f[CB]\[dq]Hi\[dq] | tobytes \-\-> b\[dq]Hi\[dq]\f[B]\f[R]. This takes constant time. .IP \[bu] 2 Byte string: Yields the byte string unchanged. .IP \[bu] 2 Array: Converts each element to a byte string and yields their concatenation, e.g. \f[B]\f[CB][0, \[dq]Hi\[dq], [1, 255]] | tobytes \-\-> b\[dq]\[rs]x00Hi\[rs]x01\[rs]xFF\[dq]\f[B]\f[R]. This is equivalent to \f[B]\f[CB]map(tobytes) | add\f[B]\f[R]. .IP \[bu] 2 Anything else: Yields an error. .PP This is inspired by Erlang\[cq]s \f[B]\f[CB]iolist_to_binary\f[B]\f[R] function. .TP \f[I]Compatibility\f[R] \f[B]\f[CB]jq\f[B]\f[R] does not have byte strings and thus does not have \f[B]\f[CB]tobytes\f[B]\f[R]. \f[B]\f[CB]fq\f[B]\f[R], which has pioneered the \f[B]\f[CB]tobytes\f[B]\f[R] filter, has both. .SS SERIALISATION & DESERIALISATION The filters in this section read and write data in all formats supported by jaq. See the formats section for general information about how jaq interprets these formats. .TP \f[I]Compatibility\f[R] \f[B]\f[CB]jq\f[B]\f[R] supports only JSON, so it only implements the \f[B]\f[CB]fromjson\f[B]\f[R]/\f[B]\f[CB]tojson\f[B]\f[R] filters in this section. .SS \f[B]\f[CB]fromjson\f[B]\f[R], \f[B]\f[CB]tojson\f[B]\f[R] The filter \f[B]\f[CB]fromjson\f[B]\f[R] takes a string as input, parses it to JSON values and yields them. For example: .IP .EX \[dq]null true 0 \[rs]\[dq]foo\[rs]\[dq] [1] {\[rs]\[dq]foo\[rs]\[dq]: 1}\[dq] | fromjson \-\-> null true 0 \[dq]foo\[dq] [1] { \[dq]foo\[dq] : 1} .EE .PP The filter \f[B]\f[CB]tojson\f[B]\f[R] takes an arbitrary value and outputs a string containing its JSON representation. For example: .IP .EX [null,true,0, \[dq]foo\[dq] ,[1],{ \[dq]foo\[dq] :1}] | tojson \-\-> \[dq][null,true,0,\[rs]\[dq]foo\[rs]\[dq],[1],{\[rs]\[dq]foo\[rs]\[dq]:1}]\[dq] .EE .PP Note that \f[B]\f[CB]tojson\f[B]\f[R] behaves similarly to \f[B]\f[CB]tostring\f[B]\f[R], but when its input is a string, it will also encode it to JSON, instead of returning it unchanged; i.e. \f[B]\f[CB]\[dq]Hi\[dq] | tojson \-\-> \[dq]\[rs]\[dq]Hi\[rs]\[dq]\[dq]\f[B]\f[R]. .TP \f[I]Compatibility\f[R] In \f[B]\f[CB]jq\f[B]\f[R], \f[B]\f[CB]fromjson\f[B]\f[R] yields an error when its input string contains multiple JSON values. Furthermore, in \f[B]\f[CB]jaq\f[B]\f[R], \f[B]\f[CB]tojson | fromjson\f[B]\f[R] is equivalent to identity (\f[B]\f[CB].\f[B]\f[R]), whereas in \f[B]\f[CB]jq\f[B]\f[R], this is not the case, because \f[B]\f[CB]nan | tojson | fromjson\f[B]\f[R] yields \f[B]\f[CB]null\f[B]\f[R], not \f[B]\f[CB]nan\f[B]\f[R]. .SS \f[B]\f[CB]fromyaml\f[B]\f[R], \f[B]\f[CB]toyaml\f[B]\f[R] The filter \f[B]\f[CB]fromyaml\f[B]\f[R] takes a text string and parses it as sequence of YAML documents. It can yield an arbitrary number of outputs. For example: .IP \[bu] 2 \f[B]\f[CB]\[dq]\-\-\-\[rs]n 1 \[rs]n...\[rs]n\-\-\-\[rs]n 2 \[rs]n...\[dq] | fromyaml \-\-> 1 2\f[B]\f[R] .IP \[bu] 2 \f[B]\f[CB]\[dq]\[dq] | fromyaml \-\->\f[B]\f[R] (no output) .PP The filter \f[B]\f[CB]toyaml\f[B]\f[R] always yields exactly one output, namely a text string containing the current value encoded as YAML. .SS \f[B]\f[CB]fromcbor\f[B]\f[R], \f[B]\f[CB]tocbor\f[B]\f[R] The filter \f[B]\f[CB]fromcbor\f[B]\f[R] takes a byte string and parses it as sequence of CBOR values. For example: .IP .EX [0, 1, 32, 64, 96, 128, 160, 244, 245, 246] | tobytes | fromcbor \-\-> 0 1 \-1 b\[dq]\[dq] \[dq]\[dq] [] {} false true null .EE .PP The filter \f[B]\f[CB]tocbor\f[B]\f[R] always yields exactly one output, namely a byte string containing the current value encoded as CBOR. .SS \f[B]\f[CB]fromtoml\f[B]\f[R], \f[B]\f[CB]totoml\f[B]\f[R] The filter \f[B]\f[CB]fromtoml\f[B]\f[R] takes a text string and parses it as a single TOML document. It yields always one output, because every TOML document encodes exactly one value. For example: .IP .EX \[dq] [database]\[rs]n enabled = true\[rs]n ports = [ 8000, 8001, 8002 ]\[rs]n data = [ [\[rs]\[dq]delta\[rs]\[dq], \[rs]\[dq]phi\[rs]\[dq]], [3.14] ]\[rs]n temp_targets = { cpu = 79.5, case = 72.0 }\[rs]n \[dq] | fromtoml \-\-> {\[dq]database\[dq]: { \[dq]enabled\[dq]: true, \[dq]ports\[dq]: [8000,8001,8002], \[dq]data\[dq]: [[\[dq]delta\[dq], \[dq]phi\[dq]], [3.14]], \[dq]temp_targets\[dq]: {\[dq]cpu\[dq]: 79.5, \[dq]case\[dq]: 72.0} }} .EE .PP The filter \f[B]\f[CB]totoml\f[B]\f[R] fails if the input is not an object or the input contains any jaq value not supported by TOML. It converts invalid UTF\-8 sequences like CBOR. .SS \f[B]\f[CB]fromxml\f[B]\f[R], \f[B]\f[CB]toxml\f[B]\f[R] The filter \f[B]\f[CB]fromxml\f[B]\f[R] takes a text string and parses it as sequence of XML tags. For example: .IP .EX \[dq] Hello HTML! \[dq] | fromxml \-\-> {\[dq]xmldecl\[dq]: {\[dq]version\[dq]: \[dq]1.0\[dq]}} {\[dq]t\[dq]: \[dq]html\[dq],\[dq]c\[dq]: [{ \[dq]t\[dq]: \[dq]body\[dq], \[dq]a\[dq]: {\[dq]xmlns\[dq]: \[dq]http://www.w3.org/1999/xhtml\[dq]}, \[dq]c\[dq]: [\[dq]Hello HTML!\[dq]] }]} .EE .PP The filter \f[B]\f[CB]toxml\f[B]\f[R] takes data produced in the format by \f[B]\f[CB]fromxml\f[B]\f[R] and yields a corresponding text string. .IP .EX [ {\[dq]xmldecl\[dq]: {\[dq]version\[dq]: \[dq]1.0\[dq]}}, {\[dq]t\[dq]: \[dq]html\[dq],\[dq]c\[dq]: [{ \[dq]t\[dq]: \[dq]body\[dq], \[dq]a\[dq]: {\[dq]xmlns\[dq]: \[dq]http://www.w3.org/1999/xhtml\[dq]}, \[dq]c\[dq]: [\[dq]Hello HTML!\[dq]] }]} ] | toxml \-\-> \[dq] Hello HTML! \[dq] .EE .SS \f[B]\f[CB]fromcsv\f[B]\f[R], \f[B]\f[CB]tocsv\f[B]\f[R] The filter \f[B]\f[CB]fromcsv\f[B]\f[R] takes a string and yields each CSV row as an array of values. For example, \f[B]\f[CB]\[dq]1,2\[rs]n3,4\[rs]n\[dq] | fromcsv \-\-> [1,2] [3,4]\f[B]\f[R]. .PP Strings can be written quoted or unquoted. Inside quoted strings, \f[B]\f[CB]\[dq]\[dq]\f[B]\f[R] denotes a single quote (\f[B]\f[CB]\[dq]\f[B]\f[R]). .IP \[bu] 2 \f[B]\f[CB]\[dq]plain,with space\[dq] | fromcsv \-\-> [\[dq]plain\[dq],\[dq]with space\[dq]]\f[B]\f[R] .IP \[bu] 2 \f[B]\f[CB]\[dq]\[rs]\[dq]with,comma\[rs]\[dq]\[dq] | fromcsv \-\-> [\[dq]with,comma\[dq]]\f[B]\f[R] .IP \[bu] 2 \f[B]\f[CB]\[dq]\[rs]\[dq]with\[rs]nnewline\[rs]\[dq]\[dq] | fromcsv \-\-> [\[dq]with\[rs]nnewline\[dq]]\f[B]\f[R] .IP \[bu] 2 \f[B]\f[CB]\[dq]\[rs]\[dq]with\[rs]\[dq]\[rs]\[dq]quote\[rs]\[dq]\[dq] | fromcsv \-\-> [\[dq]with\[rs]\[dq]quote\[dq]]\f[B]\f[R] .PP The booleans \f[B]\f[CB]true\f[B]\f[R] and \f[B]\f[CB]false\f[B]\f[R] are returned as such. An empty field is returned as \f[B]\f[CB]null\f[B]\f[R]: .IP \[bu] 2 \f[B]\f[CB]\[dq]true,,false\[dq] | fromcsv \-\-> [true, null, false]\f[B]\f[R] .PP Any field that is a valid XJON number is returned as such: .IP .EX \[dq]0,1,3.14,Infinity,+Infinity,\-Infinity\[dq] | fromcsv \-\-> [0,1,3.14,Infinity, Infinity,\-Infinity] .EE .PP Quoted booleans, numbers, or empty strings are always returned as strings: .PP \f[B]\f[CB]\[dq]\[rs]\[dq]true\[rs]\[dq],\[rs]\[dq]\[rs]\[dq],\[rs]\[dq]false\[rs]\[dq],\[rs]\[dq]3.14\[rs]\[dq]\[dq] | fromcsv \-\-> [\[dq]true\[dq], \[dq]\[dq], \[dq]false\[dq], \[dq]3.14\[dq]]\f[B]\f[R] .PP Rows can be terminated with LF (\f[B]\f[CB]\[dq]\[rs]n\[dq]\f[B]\f[R]) or CRLF (\f[B]\f[CB]\[dq]\[rs]r\[rs]n\[dq]\f[B]\f[R]). The last row may or may not be terminated with LF/CRLF. .IP \[bu] 2 \f[B]\f[CB]\[dq]1,2\[rs]r\[rs]n3,4\[rs]n\[dq] | fromcsv \-\-> [1,2] [3,4]\f[B]\f[R] .IP \[bu] 2 \f[B]\f[CB]\[dq]1,2\[rs]n3,4\[rs]r\[rs]n\[dq] | fromcsv \-\-> [1,2] [3,4]\f[B]\f[R] .IP \[bu] 2 \f[B]\f[CB]\[dq]1,2\[rs]n3,4\[dq] | fromcsv \-\-> [1,2] [3,4]\f[B]\f[R] .PP A few extreme cases: .IP \[bu] 2 \f[B]\f[CB]\[dq]\[dq] | fromcsv \-\-> \f[B]\f[R] (no output) .IP \[bu] 2 \f[B]\f[CB]\[dq]\[rs]n\[dq] | fromcsv \-\-> [null]\f[B]\f[R] (empty lines are interpreted as \f[B]\f[CB]null\f[B]\f[R]) .IP \[bu] 2 \f[B]\f[CB]\[dq],\[dq] | fromcsv \-\-> [null, null]\f[B]\f[R] .PP The filter \f[B]\f[CB]tocsv\f[B]\f[R] takes an array of scalars. It transforms each array element depending on its type: .IP \[bu] 2 \f[B]\f[CB]null\f[B]\f[R]: Yield \f[B]\f[CB]\[dq]\[dq]\f[B]\f[R]. .IP \[bu] 2 Boolean, number: Transform it via \f[B]\f[CB]tostring\f[B]\f[R]. .IP \[bu] 2 String: Replace occurrences of \f[B]\f[CB]\[dq]\f[B]\f[R] by \f[B]\f[CB]\[dq]\[dq]\f[B]\f[R] and surround by \f[B]\f[CB]\[dq]\f[B]\f[R]. .IP \[bu] 2 Fail for any other type of value. .PP Finally, the filter joins the transformed elements with \f[B]\f[CB]\[dq],\[dq]\f[B]\f[R] as separator. For example: .IP .EX [true, null, false, 1, \[dq]Give me \[rs]\[dq]quotes\[rs]\[dq], or die\[dq]] | tocsv \-\-> \[dq]true,,false,1,\[rs]\[dq]Give me \[rs]\[dq]\[rs]\[dq]quotes\[rs]\[dq]\[rs]\[dq], or die\[rs]\[dq]\[dq] .EE .SS \f[B]\f[CB]fromtsv\f[B]\f[R], \f[B]\f[CB]totsv\f[B]\f[R] The filter \f[B]\f[CB]fromtsv\f[B]\f[R] takes a string and yields each TSV row as an array of values. For example, \f[B]\f[CB]\[dq]1\[rs]t2\[rs]n3\[rs]t4\[rs]n\[dq] | fromtsv \-\-> [1,2] [3,4]\f[B]\f[R]. .PP The filter \f[B]\f[CB]totsv\f[B]\f[R] is similar to \f[B]\f[CB]tocsv\f[B]\f[R], with the following differences: .IP \[bu] 2 In strings, the characters \f[B]\f[CB]\[aq]\[rs]n\[aq]\f[B]\f[R], \f[B]\f[CB]\[aq]\[rs]r\[aq]\f[B]\f[R], \f[B]\f[CB]\[aq]\[rs]t\[aq]\f[B]\f[R], \f[B]\f[CB]\[aq]\[rs]\[aq]\f[B]\f[R], and \f[B]\f[CB]\[aq]\[rs]u0000\[aq]\f[B]\f[R] are replaced by strings \f[B]\f[CB]\[dq]\[rs]\[rs]n\[dq]\f[B]\f[R], \f[B]\f[CB]\[dq]\[rs]\[rs]r\[dq]\f[B]\f[R], \f[B]\f[CB]\[dq]\[rs]\[rs]t\[dq]\f[B]\f[R], \f[B]\f[CB]\[dq]\[rs]\[rs]\[rs]\[rs]\[dq]\f[B]\f[R], \f[B]\f[CB]\[dq]\[rs]\[rs]0\[dq]\f[B]\f[R]. (In raw output, these look like \f[B]\f[CB]\[rs]n\f[B]\f[R], \f[B]\f[CB]\[rs]r\f[B]\f[R], \f[B]\f[CB]\[rs]t\f[B]\f[R], \f[B]\f[CB]\[rs]\[rs]\f[B]\f[R], and \f[B]\f[CB]\[rs]0\f[B]\f[R].) The result is not surrounded by \f[B]\f[CB]\[dq]\f[B]\f[R]. .IP \[bu] 2 The transformed elements are joined with \f[B]\f[CB]\[rs]t\f[B]\f[R] (tabulator). .PP For example: .IP .EX [true, null, false, 1, \[dq]hello \[rs]\[dq]quotes\[rs]\[dq] and \[rs]n\[rs]r\[rs]t\[rs]\[rs] escapes\[dq]] | totsv \-\-> \[dq]true\[rs]t\[rs]tfalse\[rs]t1\[rs]thello \[rs]\[dq]quotes\[rs]\[dq] and \[rs]\[rs]n\[rs]\[rs]r\[rs]\[rs]t\[rs]\[rs]\[rs]\[rs] escapes\[dq] .EE .PP TSV strings are always unquoted. Encode control characters using \f[B]\f[CB]\[rs]0\f[B]\f[R], \f[B]\f[CB]\[rs]t\f[B]\f[R], \f[B]\f[CB]\[rs]r\f[B]\f[R], \f[B]\f[CB]\[rs]n\f[B]\f[R], and \f[B]\f[CB]\[rs]\[rs]\f[B]\f[R]: .IP \[bu] 2 \f[B]\f[CB]\[dq]with\[rs]\[rs]0NUL\[dq] | fromtsv \-\-> [\[dq]with\[rs]u0000NUL\[dq]]\f[B]\f[R] .IP \[bu] 2 \f[B]\f[CB]\[dq]with\[rs]\[rs]tTAB\[dq] | fromtsv \-\-> [\[dq]with\[rs]tTAB\[dq]]\f[B]\f[R] .IP \[bu] 2 \f[B]\f[CB]\[dq]with\[rs]\[rs]rCR\[dq] | fromtsv \-\-> [\[dq]with\[rs]rCR\[dq]]\f[B]\f[R] .IP \[bu] 2 \f[B]\f[CB]\[dq]with\[rs]\[rs]nLF\[dq] | fromtsv \-\-> [\[dq]with\[rs]nLF\[dq]]\f[B]\f[R] .IP \[bu] 2 \f[B]\f[CB]\[dq]with\[rs]\[rs]\[rs]\[rs]\[dq] | fromtsv \-\-> [\[dq]with\[rs]\[rs]\[dq]]\f[B]\f[R] .TP \f[I]Advanced\f[R] For round\-tripping, CSV is preferable to TSV, because in TSV output, non\-string values are undistinguishable from their string equivalents: .IP \[bu] 2 \f[B]\f[CB][1, \[dq]1\[dq], true, \[dq]true\[dq]] | tocsv | fromcsv \-\-> [1, \[dq]1\[dq], true, \[dq]true\[dq]]\f[B]\f[R] .IP \[bu] 2 \f[B]\f[CB][1, \[dq]1\[dq], true, \[dq]true\[dq]] | totsv | fromtsv \-\-> [1, 1, true, true ]\f[B]\f[R] For CSV, only the values \f[B]\f[CB][]\f[B]\f[R] and \f[B]\f[CB][null]\f[B]\f[R] are undistinguishable, i.e.: .IP \[bu] 2 \f[B]\f[CB][ ] | tocsv \-\-> \[dq]\[dq]\f[B]\f[R] .IP \[bu] 2 \f[B]\f[CB][null] | tocsv \-\-> \[dq]\[dq]\f[B]\f[R] .SS DATE & TIME The filters in this section serve to convert between different time formats, such as: .IP \[bu] 2 Unix epoch: Marks a point in time by the number of seconds passed since January 1, 1970 000000 (UTC). You can obtain the current time as Unix epoch via \f[B]\f[CB]now\f[B]\f[R]. .IP \[bu] 2 ISO\-8601 datetime string: Represents a date, a time, and a time zone as a string, such as \f[B]\f[CB]\[dq]1970\-01\-01T00:00:00Z\[dq]\f[B]\f[R] (corresponding to Unix epoch \f[B]\f[CB]0\f[B]\f[R]). .IP \[bu] 2 \[lq]Broken down time\[rq] (BDT) array: Represents a date and a time as an array of the shape \f[B]\f[CB][year, month, day, hour, minute, second, weekday, yearday]\f[B]\f[R]. All components are integers, except for \f[B]\f[CB]second\f[B]\f[R], which may be a floating\-point number. The \f[B]\f[CB]month\f[B]\f[R] is counted from \f[B]\f[CB]0\f[B]\f[R], the \f[B]\f[CB]weekday\f[B]\f[R] is counted from Sunday (which is \f[B]\f[CB]0\f[B]\f[R]), and the \f[B]\f[CB]yearday\f[B]\f[R] is the day in the year counted from \f[B]\f[CB]0\f[B]\f[R]. When a BDT array is used as input, only the first six components are considered. .PP You can convert between these representations via: .IP \[bu] 2 Unix epoch from/to ISO 8601: \f[B]\f[CB]fromdate\f[B]\f[R], \f[B]\f[CB]todate\f[B]\f[R] .IP \[bu] 2 BDT to Unix epoch: \f[B]\f[CB]mktime\f[B]\f[R] .IP \[bu] 2 Unix epoch to BDT: \f[B]\f[CB]gmtime, localtime\f[B]\f[R] .IP \[bu] 2 Unix epoch or BDT from/to custom string: \f[B]\f[CB]strptime\f[B]\f[R], \f[B]\f[CB]strftime\f[B]\f[R], \f[B]\f[CB]strflocaltime\f[B]\f[R] .PP As example, let us consider the time where the Hill Valley courthouse\[cq]s clock tower was struck by lightning, namely [Saturday, November 12, 1955, at 10:04 p.m. PST](https://en.wikipedia.org/wiki/Hill\f[I]Valley\f[R](Back\f[I]to\f[R]the\f[I]Future%29#Town\f[R]square). The corresponding date can be written in ISO 8601 as \f[B]\f[CB]\[dq]1955\-11\-12T10:04:00\-08:00\[dq]\f[B]\f[R]. We can convert that to a Unix epoch and from there to a (UTC) BDT via: .IP .EX \[dq]1955\-11\-12T22:04:00\-08:00\[dq] | fromdate | gmtime \-\-> [ 1955, 10, 13, 6, 4, 0, 0, 316 ] .EE .PP We can infer that at this moment, in UTC it was November 13 (the BDT month is \f[B]\f[CB]10\f[B]\f[R] and not \f[B]\f[CB]11\f[B]\f[R], because BDT months are counted from \f[B]\f[CB]0\f[B]\f[R]), at 060400. Furthermore, that day was a Sunday (because the \f[B]\f[CB]weekday\f[B]\f[R] is \f[B]\f[CB]0\f[B]\f[R]), which was the \f[B]\f[CB]316\f[B]\f[R]\-th day of the year (where \f[B]\f[CB]0\f[B]\f[R] is the first day). .TP \f[I]Compatibility\f[R] \f[B]\f[CB]jq\f[B]\f[R] does not allow time zone information in ISO 8601 datetime strings. .SS \f[B]\f[CB]fromdate\f[B]\f[R], \f[B]\f[CB]todate\f[B]\f[R], \f[B]\f[CB]fromdateiso8601\f[B]\f[R], \f[B]\f[CB]todateiso8601\f[B]\f[R] These filters convert between Unix time and ISO\-8601 timestamps. .PP For example, the \c .UR https://en.wikipedia.org/wiki/Apollo_13#Accident Apollo 13 accident .UE \c \ happened at 03:08 UTC on April 14, 1970. Its corresponding Unix time is \f[B]\f[CB]\[dq]1970\-04\-14T03:08:00Z\[dq] | fromdate \-\-> 8910480\f[B]\f[R]. We can get back the ISO\-8601 timestamp via \f[B]\f[CB]8910480 | todate \-\-> \[dq]1970\-04\-14T03:08:00Z\[dq]\f[B]\f[R]. .PP These filters can handle floating\-point numbers, e.g. \f[B]\f[CB]0.123456 | todate \-\-> \[dq]1970\-01\-01T00:00:00.123456Z\[dq]\f[B]\f[R] and \f[B]\f[CB]\[dq]1970\-01\-01T00:00:00.123456Z\[dq] | fromdate \-\-> 0.123456\f[B]\f[R]. In particular, \f[B]\f[CB]fromdate\f[B]\f[R] yields a floating\-point number if the time cannot be represented losslessly as an integer. .PP The filters \f[B]\f[CB]fromdateiso8601\f[B]\f[R] and \f[B]\f[CB]todateiso8601\f[B]\f[R] are synonyms of \f[B]\f[CB]fromdate\f[B]\f[R] and \f[B]\f[CB]todate\f[B]\f[R], respectively. .SS \f[B]\f[CB]strftime($fmt)\f[B]\f[R], \f[B]\f[CB]strflocaltime($fmt)\f[B]\f[R] The filters \f[B]\f[CB]strftime($fmt)\f[B]\f[R] and \f[B]\f[CB]strflocaltime($fmt)\f[B]\f[R] take as input either a number that is interpreted as Unix epoch, or a BDT array. The filters yield a string representation of the input time, using the format \f[B]\f[CB]$fmt\f[B]\f[R]. .PP If the input is a Unix epoch, both \f[B]\f[CB]strftime\f[B]\f[R] and \f[B]\f[CB]strflocaltime\f[B]\f[R] interpret it as UTC timestamp. If the input is a BDT array, then \f[B]\f[CB]strftime\f[B]\f[R] interprets input as UTC and \f[B]\f[CB]strflocaltime\f[B]\f[R] interprets input as user local time. \f[B]\f[CB]strftime\f[B]\f[R] outputs the time as UTC and \f[B]\f[CB]strflocaltime\f[B]\f[R] outputs the time as user local time. .PP For example, if the user is in the CET zone (+0100): .IP \[bu] 2 \f[B]\f[CB]0 | strftime(\[dq]%T %z (%Z)\[dq]) \-\-> \[dq]00:00:00 +0000 (UTC)\[dq]\f[B]\f[R] .IP \[bu] 2 \f[B]\f[CB][1970, 0, 1, 0, 0, 0] | strftime(\[dq]%T %z (%Z)\[dq]) \-\-> \[dq]00:00:00 +0000 (UTC)\[dq]\f[B]\f[R] .IP \[bu] 2 \f[B]\f[CB]0 | strflocaltime(\[dq]%T %z (%Z)\[dq])\f[B]\f[R] yields \f[B]\f[CB]\[dq]01:00:00 +0100 (CET)\[dq]\f[B]\f[R] .IP \[bu] 2 \f[B]\f[CB][1970, 0, 1, 0, 0, 0] | strflocaltime(\[dq]%T %z (%Z)\[dq])\f[B]\f[R] yields \f[B]\f[CB]\[dq]00:00:00 +0100 (CET)\[dq]\f[B]\f[R] .TP \f[I]Compatibility\f[R] \f[B]\f[CB]jq\f[B]\f[R] prints \f[B]\f[CB]GMT\f[B]\f[R] instead of \f[B]\f[CB]UTC\f[B]\f[R] in the examples above; however, GMT is not the same as UTC. .SS \f[B]\f[CB]strptime($fmt)\f[B]\f[R] The filter \f[B]\f[CB]strptime($fmt)\f[B]\f[R] takes a string and parses it using the format \f[B]\f[CB]$fmt\f[B]\f[R], yielding a BDT array. If no time zone is inferred from the input (e.g. via \f[B]\f[CB]%Z\f[B]\f[R]), it is assumed to be UTC. For example: .IP \[bu] 2 \f[B]\f[CB]\[dq]1970\-01\-01 00:00:00\[dq] | strptime(\[dq]%F %T\[dq]) \-\-> [1970, 0, 1, 0, 0, 0, 4, 0]\f[B]\f[R] .IP \[bu] 2 \f[B]\f[CB]\[dq]1970\-01\-01 00:00:00 Europe/Vienna\[dq] | strptime(\[dq]%F %T %Q\[dq]) \-\-> [1970, 0, 1, 0, 0, 0, 4, 0]\f[B]\f[R] .SS \f[B]\f[CB]gmtime\f[B]\f[R], \f[B]\f[CB]localtime\f[B]\f[R] The filters \f[B]\f[CB]gmtime\f[B]\f[R] and \f[B]\f[CB]localtime\f[B]\f[R] take a Unix epoch as input and yield a corresponding BDT array, containing the time in UTC (\f[B]\f[CB]gmtime\f[B]\f[R]) or in the user local time (\f[B]\f[CB]localtime\f[B]\f[R]). .PP For example, if the user is in the CET zone (+0100): .IP \[bu] 2 \f[B]\f[CB]0 | gmtime \-\-> [1970, 0, 1, 0, 0, 0, 4, 0]\f[B]\f[R] .IP \[bu] 2 \f[B]\f[CB]0 | localtime\f[B]\f[R] yields \f[B]\f[CB][1970, 0, 1, 1, 0, 0, 4, 0]\f[B]\f[R] .SS \f[B]\f[CB]mktime\f[B]\f[R] The filter \f[B]\f[CB]mktime\f[B]\f[R] takes a BDT array that is assumed to be in UTC, and yields the corresponding Unix epoch. For example, \f[B]\f[CB][1970, 0, 1, 0, 0, 0] | mktime \-\-> 0\f[B]\f[R]. .SS REGULAR EXPRESSIONS All the filters in this section, such as \f[B]\f[CB]test\f[B]\f[R], take a string as input and fail if they receive any other type of value. Furthermore, they all take two string arguments, namely the regular expression \f[B]\f[CB]$re\f[B]\f[R] and the \f[B]\f[CB]$flags\f[B]\f[R] that determine how the regular expression is interpreted. Omitting \f[B]\f[CB]$flags\f[B]\f[R] is equivalent to passing \f[B]\f[CB]\[dq]\[dq]\f[B]\f[R] as \f[B]\f[CB]$flags\f[B]\f[R]. For example, \f[B]\f[CB]test($re)\f[B]\f[R] is equivalent to \f[B]\f[CB]test($re; \[dq]\[dq])\f[B]\f[R]. .PP The supported flags are: .IP \[bu] 2 \f[B]\f[CB]g\f[B]\f[R]: global search .IP \[bu] 2 \f[B]\f[CB]n\f[B]\f[R]: ignore empty matches .IP \[bu] 2 \f[B]\f[CB]i\f[B]\f[R]: case\-insensitive .IP \[bu] 2 \f[B]\f[CB]m\f[B]\f[R]: multi\-line mode: \f[B]\f[CB]\[ha]\f[B]\f[R] and \f[B]\f[CB]$\f[B]\f[R] match begin/end of line .IP \[bu] 2 \f[B]\f[CB]s\f[B]\f[R]: single\-line mode: allow \f[B]\f[CB].\f[B]\f[R] to match \f[B]\f[CB]\[rs]n\f[B]\f[R] .IP \[bu] 2 \f[B]\f[CB]l\f[B]\f[R]: greedy .IP \[bu] 2 \f[B]\f[CB]x\f[B]\f[R]: extended mode: ignore whitespace and allow line comments (starting with \f[B]\f[CB]#\f[B]\f[R]) .TP \f[I]Compatibility\f[R] jaq uses the \c .UR https://docs.rs/regex-lite \f[B]\f[CB]regex\-lite\f[B]\f[R] .UE \c crate to compile and run regular expressions (regexes). See the crate documentation for a description of the supported regex syntax. .SS \f[B]\f[CB]test\f[B]\f[R] The filter \f[B]\f[CB]test\f[B]\f[R] yields \f[B]\f[CB]true\f[B]\f[R] if some part of the input matches the regular expression, else \f[B]\f[CB]false\f[B]\f[R]. For example: .IP \[bu] 2 \f[B]\f[CB]\[dq]jaq v3.0\[dq] | test(\[dq]v[0\-9]+\[rs]\[rs].[0\-9]+\[dq]) \-\-> true\f[B]\f[R] .IP \[bu] 2 \f[B]\f[CB]\[dq]jaq V3.0\[dq] | test(\[dq]v[0\-9]+\[rs]\[rs].[0\-9]+\[dq]) \-\-> false\f[B]\f[R] .IP \[bu] 2 \f[B]\f[CB]\[dq]jaq V3.0\[dq] | test(\[dq]v[0\-9]+\[rs]\[rs].[0\-9]+\[dq]; \[dq]i\[dq]) \-\-> true\f[B]\f[R] .SS \f[B]\f[CB]scan\f[B]\f[R] The filter \f[B]\f[CB]scan\f[B]\f[R] yields all parts of the input that match the regular expression. For example: .IP \[bu] 2 \f[B]\f[CB]\[dq]v2.0, v3.0\[dq] | scan(\[dq]v[0\-9]+\[rs]\[rs].[0\-9]+\[dq] ) \-\-> \[dq]v2.0\[dq]\f[B]\f[R] .IP \[bu] 2 \f[B]\f[CB]\[dq]v2.0, v3.0\[dq] | scan(\[dq]v[0\-9]+\[rs]\[rs].[0\-9]+\[dq]; \[dq]g\[dq]) \-\-> \[dq]v2.0\[dq] \[dq]v3.0\[dq]\f[B]\f[R] .IP \[bu] 2 \f[B]\f[CB]\[dq]V2.0\[dq] | scan(\[dq]v[0\-9]+\[rs]\[rs].[0\-9]+\[dq]) \-\->\f[B]\f[R] (no output) .SS \f[B]\f[CB]match\f[B]\f[R] The filter \f[B]\f[CB]match\f[B]\f[R] yields an object for every part of the input that matches the regular expression, containing: .IP \[bu] 2 \f[B]\f[CB]\[dq]offset\[dq]\f[B]\f[R]: the character index of the start of the match .IP \[bu] 2 \f[B]\f[CB]\[dq]length\[dq]\f[B]\f[R]: the number of characters of the match .IP \[bu] 2 \f[B]\f[CB]\[dq]string\[dq]\f[B]\f[R]: the contents of the match .IP \[bu] 2 \f[B]\f[CB]\[dq]captures\[dq]\f[B]\f[R]: an array with an object for every capture group, containing: .RS 2 .IP \[bu] 2 \f[B]\f[CB]\[dq]offset\[dq]\f[B]\f[R], .IP \[bu] 2 \f[B]\f[CB]\[dq]length\[dq]\f[B]\f[R], .IP \[bu] 2 \f[B]\f[CB]\[dq]string\[dq]\f[B]\f[R]: as above, but for the capture group instead of the whole match .IP \[bu] 2 \f[B]\f[CB]\[dq]name\[dq]\f[B]\f[R]: the name of the capture group if it has one, else this key is omitted .RE .PP Example: .IP .EX \[dq]v2.0, v3.0\[dq] | match(\[dq]v(?[0\-9]+)\[rs]\[rs].([0\-9]+)\[dq]; \[dq]g\[dq]) \-\-> { \[dq]offset\[dq]: 0, \[dq]length\[dq]: 4, \[dq]string\[dq]: \[dq]v2.0\[dq], \[dq]captures\[dq]: [ { \[dq]offset\[dq]: 1, \[dq]length\[dq]: 1, \[dq]string\[dq]: \[dq]2\[dq], \[dq]name\[dq]: \[dq]maj\[dq] }, { \[dq]offset\[dq]: 3, \[dq]length\[dq]: 1, \[dq]string\[dq]: \[dq]0\[dq] } ] } { \[dq]offset\[dq]: 6, \[dq]length\[dq]: 4, \[dq]string\[dq]: \[dq]v3.0\[dq], \[dq]captures\[dq]: [ { \[dq]offset\[dq]: 7, \[dq]length\[dq]: 1, \[dq]string\[dq]: \[dq]3\[dq], \[dq]name\[dq]: \[dq]maj\[dq] }, { \[dq]offset\[dq]: 9, \[dq]length\[dq]: 1, \[dq]string\[dq]: \[dq]0\[dq] } ] } .EE .SS \f[B]\f[CB]capture\f[B]\f[R] The filter \f[B]\f[CB]capture\f[B]\f[R] yields an object for every part of the input that matches the regular expression, containing for each named capture group an entry with the group name as key and its matched string as value. .PP Example: .IP .EX \[dq]v2.0, v3.0\[dq] | capture(\[dq]v(?[0\-9]+)\[rs]\[rs].(?[0\-9]+)\[dq]; \[dq]g\[dq]) \-\-> { \[dq]maj\[dq]: \[dq]2\[dq], \[dq]min\[dq]: \[dq]0\[dq] } { \[dq]maj\[dq]: \[dq]3\[dq], \[dq]min\[dq]: \[dq]0\[dq] } .EE .SS \f[B]\f[CB]split\f[B]\f[R], \f[B]\f[CB]splits\f[B]\f[R] The filter \f[B]\f[CB]split($re; $flags)\f[B]\f[R] yields an array of those parts of the input string that do \f[B]not\f[R] match the regular expression \f[B]\f[CB]$re\f[B]\f[R]. For example: .IP \[bu] 2 \f[B]\f[CB]\[dq]Here be\[rs]tspaces\[dq] | split(\[dq]\[rs]\[rs]s\[dq] ; \[dq]\[dq]) \-\-> [\[dq]Here\[dq], \[dq]be\[dq], \[dq]spaces\[dq]]\f[B]\f[R] .IP \[bu] 2 \f[B]\f[CB]\[dq] More\[rs]n\[rs]n\[dq] | split(\[dq]\[rs]\[rs]s+\[dq]; \[dq]\[dq]) \-\-> [\[dq]\[dq], \[dq]More\[dq], \[dq]\[dq]]\f[B]\f[R] .IP \[bu] 2 \f[B]\f[CB]\[dq]\[dq] | split(\[dq]\[rs]\[rs]s\[dq] ; \[dq]\[dq]) \-\-> [\[dq]\[dq]]\f[B]\f[R] .PP Note that \f[B]\f[CB]split($re; $flags)\f[B]\f[R] is equivalent to \f[B]\f[CB]split($re; \[dq]g\[dq] + $flags)\f[B]\f[R], meaning that the string is split not only by the first match, but by all matches. Furthermore, unlike all other filters in this section, \f[B]\f[CB]split($s)\f[B]\f[R] is \f[B]not\f[R] equivalent to \f[B]\f[CB]split($s; $flags)\f[B]\f[R], because \f[B]\f[CB]split($s)\f[B]\f[R] splits a string by a separator that is \f[B]not\f[R] interpreted as regular expression; see \f[B]\f[CB]split\f[B]\f[R]. .PP The filter \f[B]\f[CB]splits($re; $flags)\f[B]\f[R] yields the elements of the array yielded by \f[B]\f[CB]split($re; $flags)\f[B]\f[R]. For example, \f[B]\f[CB]\[dq]Here be\[rs]tspaces\[dq] | splits(\[dq]\[rs]\[rs]s\[dq]) \-\-> \[dq]Here\[dq] \[dq]be\[dq] \[dq]spaces\[dq]\f[B]\f[R]. The filter \f[B]\f[CB]splits($re)\f[B]\f[R] is equivalent to \f[B]\f[CB]splits($re; \[dq]\[dq])\f[B]\f[R]. .SS \f[B]\f[CB]sub\f[B]\f[R], \f[B]\f[CB]gsub\f[B]\f[R] The filter \f[B]\f[CB]sub($re; f; $flags)\f[B]\f[R] replaces all parts of the input string that match \f[B]\f[CB]$re\f[B]\f[R] by the output of \f[B]\f[CB]f\f[B]\f[R]. Here, \f[B]\f[CB]f\f[B]\f[R] receives an object as returned by \f[B]\f[CB]capture\f[B]\f[R]; that is, for every named capture group, it contains its name as key and its matched string as value. .PP For example: .IP .EX \[dq]Mr. 高橋 & Mrs. 嵯峨\[dq] | sub(\[dq](?(Mr|Ms|Mrs)\[rs]\[rs].) (?<name>\[rs]\[rs]S+)\[dq]; \[dq]\[rs](.name) (\[rs](.title))\[dq]; \[dq]g\[dq]) \-\-> \[dq]高橋 (Mr.) & 嵯峨 (Mrs.)\[dq] .EE .PP When the filter \f[B]\f[CB]f\f[B]\f[R] yields multiple outputs, then all potential combinations are output. For example: .IP .EX \[dq]Thanks, fine.\[dq] | sub(\[dq](?<word>\[rs]\[rs]w+)\[dq]; .word, (.word | ascii_upcase); \[dq]g\[dq]) \-\-> \[dq]Thanks, fine.\[dq] \[dq]Thanks, FINE.\[dq] \[dq]THANKS, fine.\[dq] \[dq]THANKS, FINE.\[dq] .EE .PP We have following short forms: .IP \[bu] 2 The filter \f[B]\f[CB]gsub($re; f; $flags)\f[B]\f[R] is equivalent to \f[B]\f[CB]sub($re; f; \[dq]g\[dq] + $flags)\f[B]\f[R]. .IP \[bu] 2 The filter \f[B]\f[CB]gsub($re; f)\f[B]\f[R] is equivalent to \f[B]\f[CB]gsub($re; f; \[dq]\[dq])\f[B]\f[R]. .IP \[bu] 2 The filter \f[B]\f[CB]sub($re; f)\f[B]\f[R] is equivalent to \f[B]\f[CB]sub($re; f; \[dq]\[dq])\f[B]\f[R]. .SS I/O This section contains filters that interact with the system. These filters may yield different outputs when given equal inputs. .SS \f[B]\f[CB]input\f[B]\f[R], \f[B]\f[CB]inputs\f[B]\f[R] The filter \f[B]\f[CB]inputs\f[B]\f[R] yields all the inputs in the current input file. For example: .IP .EX $ echo 1 2 3 | jaq \-nc \[aq][inputs]\[aq] [1,2,3] .EE .PP This can be useful to fold over large (potentially infinite) amounts of values; for example, to create a cumulative sum over all input integers, you can use \f[B]\f[CB]jaq \-n \[aq]foreach inputs as $x (0; .+$x)\[aq]\f[B]\f[R]. .PP The filter \f[B]\f[CB]input\f[B]\f[R] yields the next input in the current input file. .TP \f[I]Compatibility\f[R] When there is no more input value left, in \f[B]\f[CB]jq\f[B]\f[R], \f[B]\f[CB]input\f[B]\f[R] yields an error, whereas in jaq, it yields no output value. That is, in jaq, \f[B]\f[CB]input\f[B]\f[R] is equivalent to \f[B]\f[CB]first(inputs)\f[B]\f[R]. .TP \f[I]Advanced\f[R] Both \f[B]\f[CB]input\f[B]\f[R] and \f[B]\f[CB]inputs\f[B]\f[R] have a \f[B]side effect\f[R], i.e. they advance the input stream. That means that unlike most jq filters, \f[B]\f[CB]inputs\f[B]\f[R] is not referentially transparent. It is advised to use it sparingly and with caution, lest you are devoured by the evil dragons of evaluation order. .SS \f[B]\f[CB]debug\f[B]\f[R], \f[B]\f[CB]debug(f)\f[B]\f[R] The filter \f[B]\f[CB]debug(f)\f[B]\f[R] prints a debug message for every output of \f[B]\f[CB]f\f[B]\f[R] to the standard error stream (stderr), then yields its input. For example: .IP .EX $ jaq \-n \[aq]0 | debug(1, 2)\[aq] [\[dq]DEBUG:\[dq], 1] [\[dq]DEBUG:\[dq], 2] 0 .EE .PP The filter \f[B]\f[CB]debug\f[B]\f[R] is equivalent to \f[B]\f[CB]debug(.)\f[B]\f[R]. .SS \f[B]\f[CB]stderr\f[B]\f[R] The filter \f[B]\f[CB]stderr\f[B]\f[R] prints its input to the standard error stream in raw and compact mode without newline. It then yields its input. .IP .EX $ jaq \-n \[aq]\[dq]Hi\[dq] | stderr\[aq] Hi\[dq]Hi\[dq] .EE .SS \f[B]\f[CB]halt\f[B]\f[R], \f[B]\f[CB]halt($exit_code)\f[B]\f[R] The filter \f[B]\f[CB]halt($exit_code)\f[B]\f[R] terminates jaq with the given exit code. .PP The filter \f[B]\f[CB]halt\f[B]\f[R] terminates jaq with exit code 0. .IP .EX $ jaq \-n \[aq]1, halt , 2\[aq] 1 $ jaq \-n \[aq]1, halt(42), 2\[aq]; echo $? 1 42 .EE .TP \f[I]Compatibility\f[R] \f[B]\f[CB]jq\f[B]\f[R] does not implement \f[B]\f[CB]halt($exit_code)\f[B]\f[R], only \f[B]\f[CB]halt\f[B]\f[R]. .TP \f[I]Advanced\f[R] Note that not all integer values for \f[B]\f[CB]$exit_code\f[B]\f[R] work as intended on all platforms; see \c .UR https://doc.rust-lang.org/stable/std/process/fn.exit.html#platform-specific-behavior \f[B]\f[CB]std::process::exit\f[B]\f[R] .UE \c \&. As a general rule of thumb, the 8\-bit signed integers (\-128 to 127 inclusive) are safe to use and anything outside of that range \f[I]may\f[R] be silently truncated by the operating system. .SS \f[B]\f[CB]halt_error\f[B]\f[R], \f[B]\f[CB]halt_error($exit_code)\f[B]\f[R] The filter \f[B]\f[CB]halt_error($exit_code)\f[B]\f[R] prints its input via \f[B]\f[CB]stderr\f[B]\f[R]. It then quits the jaq process with the given exit code. .PP The filter \f[B]\f[CB]halt_error\f[B]\f[R] is equivalent to \f[B]\f[CB]halt_error(5)\f[B]\f[R]. .IP .EX $ jaq \-n \[aq]\[dq]Hi!\[dq] | halt_error(42)\[aq]; echo $? Hi!42 $ jaq \-n \[aq]\[dq]Hi!\[dq] | halt_error \[aq]; echo $? Hi!5 .EE .TP \f[I]Compatibility\f[R] \f[B]\f[CB]jq\f[B]\f[R] prints a newline after the input if it is not a string. .SS \f[B]\f[CB]now\f[B]\f[R] This filter yields the Unix epoch as floating\-point number. .IP .EX $ date +%s | jaq \[aq]now \- . as $dt | 0 <= $dt and $dt <= 2\[aq] true .EE .SS \f[B]\f[CB]$ENV\f[B]\f[R], \f[B]\f[CB]env\f[B]\f[R] The variable \f[B]\f[CB]$ENV\f[B]\f[R] holds an object that contains an entry for every environment variable, where the key is the name of the variable and the value is its value. For example, \f[B]\f[CB]{\[dq]EDITOR\[dq]: \[dq]vim\[dq], \[dq]SHELL\[dq]: \[dq]/usr/bin/bash\[dq]}\f[B]\f[R]. .IP .EX $ MYFLAG=42 jaq \-n \[aq]$ENV.MYFLAG\[aq] \[dq]42\[dq] .EE .PP The filter \f[B]\f[CB]env\f[B]\f[R] is equivalent to \f[B]\f[CB]$ENV\f[B]\f[R]. .SS \f[B]\f[CB]input_filename\f[B]\f[R] The filter \f[B]\f[CB]input_filename\f[B]\f[R] returns the name of the file currently read, or \f[B]\f[CB]\[dq]<stdin>\[dq]\f[B]\f[R] if standard input is currently read. .IP .EX $ jaq \-\-slurp \[aq]input_filename\[aq] \[dq]examples/benches.json\[dq] \[dq]examples/benches.json\[dq] $ echo 0 | jaq \[aq]input_filename\[aq] \[dq]<stdin>\[dq] .EE .TP \f[I]Compatibility\f[R] In jq, this filter returns the name of the file most recently read from. This can lead to subtle differences compared to jaq. For example: .IP .EX $ echo 0 | jaq \-\-null\-input \[aq](., inputs) | input_filename\[aq] \[dq]<stdin>\[dq] \[dq]<stdin>\[dq] .EE Here, jq yields \f[B]\f[CB]null \[dq]<stdin>\[dq]\f[B]\f[R]. Why? When executing the filter \f[B]\f[CB].\f[B]\f[R], jq did not read any input, so \f[B]\f[CB]input_filename\f[B]\f[R] returns \f[B]\f[CB]null\f[B]\f[R]. However, when executing \f[B]\f[CB]inputs\f[B]\f[R], jq starts reading from standard input, so \f[B]\f[CB]input_filename\f[B]\f[R] returns \f[B]\f[CB]\[dq]<stdin>\[dq]\f[B]\f[R]. In contrast, jaq considers a file as being read even when it has only been opened. .SS \f[B]\f[CB]repl\f[B]\f[R] The filter \f[B]\f[CB]repl\f[B]\f[R] starts an interactive REPL (read\-eval\-print\-loop). You can nest calls to \f[B]\f[CB]repl\f[B]\f[R]; that is, you can run \f[B]\f[CB]repl\f[B]\f[R] from inside a \f[B]\f[CB]repl\f[B]\f[R]. Use CTRL\-D to exit a REPL. .PP This filter yields no output. It writes its history to a file \f[B]\f[CB]jaq\-history\f[B]\f[R] in the user\[cq]s cache directory. .TP \f[I]Compatibility\f[R] This filter has been inspired by \f[B]\f[CB]fq\f[B]\f[R]\[cq]s \f[B]\f[CB]repl\f[B]\f[R] filter. However, unlike \f[B]\f[CB]fq\f[B]\f[R], jaq does not require to be started with the \f[B]\f[CB]\-\-repl\f[B]\f[R] flag, and it allows calls to \f[B]\f[CB]repl\f[B]\f[R] anywhere in a filter, not only last in the pipeline. \f[B]\f[CB]jq\f[B]\f[R] does not have this filter. .SS UNSUPPORTED This section lists filters present in \f[B]\f[CB]jq\f[B]\f[R], but not in jaq. .IP \[bu] 2 \c .UR https://jqlang.org/manual/#$__loc__ \f[B]\f[CB]$__loc__\f[B]\f[R] .UE \c .IP \[bu] 2 \f[B]\f[CB]modulemeta\f[B]\f[R] .IP \[bu] 2 \c .UR https://jqlang.org/manual/#have_literal_numbers \f[B]\f[CB]have_literal_numbers\f[B]\f[R] .UE \c .IP \[bu] 2 \c .UR https://jqlang.org/manual/#have_decnum \f[B]\f[CB]have_decnum\f[B]\f[R] .UE \c .IP \[bu] 2 \c .UR https://jqlang.org/manual/#$jq_build_configuration \f[B]\f[CB]$JQ_BUILD_CONFIGURATION\f[B]\f[R] .UE \c .IP \[bu] 2 \c .UR https://jqlang.org/manual/#builtins \f[B]\f[CB]builtins\f[B]\f[R] .UE \c .IP \[bu] 2 \c .UR https://jqlang.org/manual/#input_line_number \f[B]\f[CB]input_line_number\f[B]\f[R] .UE \c .PP jaq supports none of jq\[cq]s \c .UR https://jqlang.org/manual/#sql-style-operators SQL\-style operators .UE \c , mostly for aesthetic reasons (uppercase\-names) and because jq is not SQL: .IP \[bu] 2 \f[B]\f[CB]INDEX\f[B]\f[R] .IP \[bu] 2 \f[B]\f[CB]JOIN\f[B]\f[R] .IP \[bu] 2 \f[B]\f[CB]IN\f[B]\f[R] .PP jaq does not support \f[B]\f[CB]jq\f[B]\f[R]\[cq]s \c .UR https://jqlang.org/manual/#streaming \f[B]\f[CB]\-\-stream\f[B]\f[R] .UE \c option; therefore, it also does not implement the related filters: .IP \[bu] 2 \f[B]\f[CB]truncate_stream\f[B]\f[R] .IP \[bu] 2 \f[B]\f[CB]fromstream\f[B]\f[R] .IP \[bu] 2 \f[B]\f[CB]tostream\f[B]\f[R] .SH ADVANCED FEATURES .SS ASSIGNMENTS jq allows for assignments of the form \f[B]\f[CB]p |= f\f[B]\f[R], where \f[B]\f[CB]p\f[B]\f[R] is an arbitrary filter. This makes assignments in jq uniquely powerful compared to other languages. For example, a program from the jq manual that blew my mind was the following: .IP .EX (.posts[] | select(.author == \[dq]stedolan\[dq]) | .comments) += [\[dq]terrible.\[dq]] .EE .PP This iterates over all posts, selects those whose author is \[lq]stedolan\[rq], takes its comments, and adds a not very flattering comment to it. (This does not reflect my opinion about Stephen Dolan \[em] I think that he did a great job creating jq.) .PP jaq and \f[B]\f[CB]jq\f[B]\f[R] pursue different approaches to execute assignments: .IP \[bu] 2 \f[B]Path\-based\f[R]: In \f[B]\f[CB]jq\f[B]\f[R], an assignment \f[B]\f[CB]p |= f\f[B]\f[R] constructs paths to all values that match \f[B]\f[CB]p\f[B]\f[R] and applies the filter \f[B]\f[CB]f\f[B]\f[R] to these values. .IP \[bu] 2 \f[B]Pathless\f[R]: In jaq, an assignment \f[B]\f[CB]p |= f\f[B]\f[R] is transformed to a different filter that does not construct any paths. .PP For example, consider the update \f[B]\f[CB][1, 2, 3] | .[] |= .+1 \-\-> [2, 3, 4]\f[B]\f[R]: When \f[B]\f[CB]jq\f[B]\f[R] executes this, it calculates \f[B]\f[CB][1, 2, 3] | path(.[]) \-\-> [0] [1] [2]\f[B]\f[R] and applies \f[B]\f[CB].+1\f[B]\f[R] on each value at these paths. On the other hand, jaq transforms the update to \f[B]\f[CB][1, 2, 3] | [.[] | .+1] \-\-> [2, 3, 4]\f[B]\f[R] \[em] the assignment does not involve any path construction. .PP Fortunately, like in the example above, in most cases, the result of the both approaches is the same. The following sections explain the two approaches in more detail, and how to write updates that behave the same in both \f[B]\f[CB]jq\f[B]\f[R] and jaq. .SS Path\-based The path\-based update model used by \f[B]\f[CB]jq\f[B]\f[R] executes \f[B]\f[CB]p |= u\f[B]\f[R] by first collecting the paths corresponding to \f[B]\f[CB]p\f[B]\f[R], then updating the input at these paths by \f[B]\f[CB]u\f[B]\f[R]. We can approximate this behaviour by \f[B]\f[CB]getpath(path(p)) |= u\f[B]\f[R] \[em] the actual \f[B]\f[CB]jq\f[B]\f[R] update behaviour is much more complex, only sparely documented, and has changed in backwards\-incompatible ways between minor versions. .TP \f[I]Advanced\f[R] We have a few equivalences for \f[B]\f[CB]path(f)\f[B]\f[R]: .PP .TS tab(@); l l. T{ .PP \f[B]\f[CB]p\f[B]\f[R] T}@T{ .PP \f[B]\f[CB]path(p)\f[B]\f[R] T} _ T{ .PP \f[B]\f[CB].\f[B]\f[R] T}@T{ .PP \f[B]\f[CB][]\f[B]\f[R] T} T{ .PP \f[B]\f[CB]..\f[B]\f[R] T}@T{ .PP \f[B]\f[CB]path(recurse)\f[B]\f[R] T} T{ .PP \f[B]\f[CB].[]\f[B]\f[R] T}@T{ .PP \f[B]\f[CB]keys_unsorted[] | [.]\f[B]\f[R] T} T{ .PP \f[B]\f[CB].[$i]\f[B]\f[R] T}@T{ .PP \f[B]\f[CB].[$i] | [$i]\f[B]\f[R] T} T{ .PP \f[B]\f[CB].[$i: ]\f[B]\f[R] T}@T{ .PP \f[B]\f[CB].[$i:$j] | [{start: $i }]\f[B]\f[R] T} T{ .PP \f[B]\f[CB].[ :$j]\f[B]\f[R] T}@T{ .PP \f[B]\f[CB].[ :$j] | [{ end: $j}]\f[B]\f[R] T} T{ .PP \f[B]\f[CB].[$i:$j]\f[B]\f[R] T}@T{ .PP \f[B]\f[CB].[$i:$j] | [{start: $i, end: $j}]\f[B]\f[R] T} T{ .PP \f[B]\f[CB]f?\f[B]\f[R] T}@T{ .PP \f[B]\f[CB]path(try f catch empty)\f[B]\f[R] T} T{ .PP \f[B]\f[CB]f, g\f[B]\f[R] T}@T{ .PP \f[B]\f[CB]path(f), path(g)\f[B]\f[R] T} T{ .PP \f[B]\f[CB]f | g\f[B]\f[R] T}@T{ .PP \f[B]\f[CB]path(f) as $p | $p + (getpath($p) | path(g))\f[B]\f[R] T} T{ .PP \f[B]\f[CB]f // g\f[B]\f[R] T}@T{ .PP \f[B]\f[CB]path(if first(f // false) then f else g end)\f[B]\f[R] T} T{ .PP \f[B]\f[CB]f as $x | g\f[B]\f[R] T}@T{ .PP \f[B]\f[CB]f as $x | path(g)\f[B]\f[R] T} T{ .PP \f[B]\f[CB]if $p then f else g end\f[B]\f[R] T}@T{ .PP \f[B]\f[CB]if $p then path(f) else path(g) end\f[B]\f[R] T} T{ .PP \f[B]\f[CB]try f catch g\f[B]\f[R] T}@T{ .PP \f[B]\f[CB]try path(f) catch (g | error)\f[B]\f[R] T} T{ .PP \f[B]\f[CB]label $x | f\f[B]\f[R] T}@T{ .PP \f[B]\f[CB]label $x | path(f)\f[B]\f[R] T} T{ .PP \f[B]\f[CB]break $x\f[B]\f[R] T}@T{ .PP \f[B]\f[CB]break $x\f[B]\f[R] T} .TE Examples: .IP \[bu] 2 \f[B]\f[CB]true | path(.) \-\-> []\f[B]\f[R] .IP \[bu] 2 \f[B]\f[CB][1, 2, 3] | path(.[]) \-\-> [0] [1] [2]\f[B]\f[R] .IP \[bu] 2 \f[B]\f[CB][1, 2, 3] | keys_unsorted[] | [.] \-\-> [0] [1] [2]\f[B]\f[R] .IP \[bu] 2 \f[B]\f[CB]{a: 1, b: 2} | path(.[]) \-\-> [\[dq]a\[dq]] [\[dq]b\[dq]]\f[B]\f[R] .IP \[bu] 2 \f[B]\f[CB]{a: 1, b: 2} | keys_unsorted[] | [.] \-\-> [\[dq]a\[dq]] [\[dq]b\[dq]]\f[B]\f[R] .IP \[bu] 2 \f[B]\f[CB][1, 2, 3] | path(.[0]) \-\-> [0]\f[B]\f[R] .IP \[bu] 2 \f[B]\f[CB][1, 2, 3] | path(.[1:\-1]) \-\-> [{\[dq]start\[dq]: 1, \[dq]end\[dq]: \-1}]\f[B]\f[R] .IP \[bu] 2 \f[B]\f[CB]{a: 1, b: 2} | path(.a, .b) \-\-> [\[dq]a\[dq]] [\[dq]b\[dq]]\f[B]\f[R] .IP \[bu] 2 \f[B]\f[CB]{a: 1, b: 2} | path(.a), path(.b) \-\-> [\[dq]a\[dq]] [\[dq]b\[dq]]\f[B]\f[R] .IP \[bu] 2 \f[B]\f[CB][[1], [2]] | path(.[][]) \-\-> [0, 0] [1, 0]\f[B]\f[R] .IP \[bu] 2 \f[B]\f[CB][[1], [2]] | path(.[]) as $p | $p + (getpath($p) | path(.[])) \-\-> [0, 0] [1, 0]\f[B]\f[R] .IP \[bu] 2 \f[B]\f[CB][1, 2, 3] | path((0, 2) as $x | .[$x]) \-\-> [0] [2]\f[B]\f[R] .IP \[bu] 2 \f[B]\f[CB][1, 2, 3] | (0, 2) as $x | path(.[$x]) \-\-> [0] [2]\f[B]\f[R] .PP The filters \f[B]\f[CB]reduce\f[B]\f[R] / \f[B]\f[CB]foreach\f[B]\f[R] are both defined in jaq in terms of simpler filters \f[B]\f[CB]f\f[B]\f[R] that \f[B]\f[CB]path(f)\f[B]\f[R] can evaluate. Therefore, in jaq, you can use \f[B]\f[CB]reduce\f[B]\f[R] / \f[B]\f[CB]foreach\f[B]\f[R] inside \f[B]\f[CB]path(f)\f[B]\f[R], as well as on the left\-hand side of updates. For example: .IP \[bu] 2 \f[B]\f[CB][{a: 1}] | path(reduce (0, \[dq]a\[dq]) as $i (.; .[$i])) \-\-> [0, \[dq]a\[dq]]\f[B]\f[R] .IP \[bu] 2 \f[B]\f[CB][{a: 1}] | path(foreach (0, \[dq]a\[dq]) as $i (.; .[$i])) \-\-> [0] [0, \[dq]a\[dq]]\f[B]\f[R] .PP Similarly, you can use compound paths: .IP \[bu] 2 \f[B]\f[CB][1, 2, 3] | path(.[]?) \-\-> [0] [1] [2]\f[B]\f[R] .IP \[bu] 2 \f[B]\f[CB]\[dq]\[dq] | path(.[]?) \-\->\f[B]\f[R] (no output) .IP \[bu] 2 \f[B]\f[CB]{a: [1, 2]} | path(.a[]) \-\-> [\[dq]a\[dq], 0] [\[dq]a\[dq], 1]\f[B]\f[R] .PP All other filters defined in the core language yield an error, because they construct new values instead of returning references to their inputs. For example: .IP \[bu] 2 \f[B]\f[CB]try path(0 ) catch \[dq]fail\[dq] \-\-> \[dq]fail\[dq]\f[B]\f[R] .IP \[bu] 2 \f[B]\f[CB]try path(1 + 2) catch \[dq]fail\[dq] \-\-> \[dq]fail\[dq]\f[B]\f[R] .IP \[bu] 2 \f[B]\f[CB]try path(1 = 2) catch \[dq]fail\[dq] \-\-> \[dq]fail\[dq]\f[B]\f[R] .TP \f[I]Compatibility\f[R] \f[B]\f[CB]jq\f[B]\f[R] does not support \f[B]\f[CB]reduce\f[B]\f[R] / \f[B]\f[CB]foreach\f[B]\f[R] in \f[B]\f[CB]path\f[B]\f[R]. On the other hand, \f[B]\f[CB]jq\f[B]\f[R] is more permissive with paths of intermediate values. For example, \f[B]\f[CB]try path([] | empty) catch \[dq]fail\[dq] \-\-> \[dq]fail\[dq]\f[B]\f[R], because jaq reduces \f[B]\f[CB]path([] | empty)\f[B]\f[R] to \f[B]\f[CB]path([]) as $p | ...\f[B]\f[R], which fails because \f[B]\f[CB]path([])\f[B]\f[R] is not defined. Conversely, \f[B]\f[CB]jq\f[B]\f[R] yields no output for this filter. Interestingly, \f[B]\f[CB]path([] | .[])\f[B]\f[R] yields an error in both jaq and \f[B]\f[CB]jq\f[B]\f[R], so I do not understand why the example with \f[B]\f[CB]empty\f[B]\f[R] does not yield an error, too. In jaq, \f[B]\f[CB][] | path(.[0: ]) \-\-> [{\[dq]start\[dq]: 0}]\f[B]\f[R] and \f[B]\f[CB][] | path(.[ :0]) \-\-> [{\[dq]end\[dq] : 0}]\f[B]\f[R], whereas \f[B]\f[CB]jq\f[B]\f[R] yields \f[B]\f[CB][{start: 0 , end: null}]\f[B]\f[R] and \f[B]\f[CB][{start: null, end: 0 }]\f[B]\f[R], respectively. That means that \f[B]\f[CB]jq\f[B]\f[R] always adds missing \f[B]\f[CB]start\f[B]\f[R]/\f[B]\f[CB]end\f[B]\f[R] indices as \f[B]\f[CB]null\f[B]\f[R], whereas jaq omits them. .SS Pathless The pathless update model that is used by jaq reduces updates \f[B]\f[CB]p |= u\f[B]\f[R] to simpler expressions, depending on \f[B]\f[CB]p\f[B]\f[R]. It yields the same results as path\-based updates in most common cases, while having the following advantages: .IP \[bu] 2 It does not need to construct paths, resulting in higher performance. .IP \[bu] 2 It considers multiple outputs by \f[B]\f[CB]u\f[B]\f[R] where possible, whereas path\-based updates consider at most one output. For example, \f[B]\f[CB]0 | (., .) |= (., .+1) \-\-> 0 1 1 2\f[B]\f[R] in jaq, whereas it yields only \f[B]\f[CB]0\f[B]\f[R] in jq. However, \f[B]\f[CB]{a: 1} | .a |= (2, 3) \-\-> {\[dq]a\[dq]: 2}\f[B]\f[R] in both jaq and jq, because an object can only associate a single value with any given key, so we cannot use multiple outputs in a meaningful way here. .IP \[bu] 2 It avoids iterator invalidation problems that path\-based updates are prone to. .PP However, pathless updates do not support a few filters on the left\-hand side of updates that path\-based updates support, such as: .IP \[bu] 2 \f[B]\f[CB]try f catch g\f[B]\f[R] .IP \[bu] 2 \f[B]\f[CB]first(f)\f[B]\f[R], \f[B]\f[CB]last(f)\f[B]\f[R] .IP \[bu] 2 \f[B]\f[CB]limit($n; f)\f[B]\f[R] .IP \[bu] 2 \f[B]\f[CB]skip($n; f)\f[B]\f[R] .PP For example, the following filters all yield an error in jaq: .IP \[bu] 2 \f[B]\f[CB][1, 2, 3] | try .[] \-= 1\f[B]\f[R] yields \f[B]\f[CB][0, 1, 2]\f[B]\f[R] in jq. .IP \[bu] 2 \f[B]\f[CB][1, 2, 3] | first( .[]) \-= 1\f[B]\f[R] yields \f[B]\f[CB][0, 2, 3]\f[B]\f[R] in jq. .IP \[bu] 2 \f[B]\f[CB][1, 2, 3] | limit(2; .[]) \-= 1\f[B]\f[R] yields \f[B]\f[CB][0, 1, 3]\f[B]\f[R] in jq. .IP \[bu] 2 \f[B]\f[CB][1, 2, 3] | skip (1; .[]) \-= 1\f[B]\f[R] yields \f[B]\f[CB][1, 1, 2]\f[B]\f[R] in jq. .IP \[bu] 2 \f[B]\f[CB][1, 2, 3] | last ( .[]) \-= 1\f[B]\f[R] yields an error in jq. .PP In such cases, you can fall back to path\-based updates in jaq by writing \f[B]\f[CB]getpath(path(p)) |= u\f[B]\f[R] instead of \f[B]\f[CB]p |= u\f[B]\f[R]. For example, the following filters yield the same outputs in jaq and \f[B]\f[CB]jq\f[B]\f[R]: .IP \[bu] 2 \f[B]\f[CB][1, 2, 3] | getpath(path(try .[] )) \-= 1 \-\-> [0, 1, 2]\f[B]\f[R] .IP \[bu] 2 \f[B]\f[CB][1, 2, 3] | getpath(path(first( .[]))) \-= 1 \-\-> [0, 2, 3]\f[B]\f[R] .IP \[bu] 2 \f[B]\f[CB][1, 2, 3] | getpath(path(limit(2; .[]))) \-= 1 \-\-> [0, 1, 3]\f[B]\f[R] .IP \[bu] 2 \f[B]\f[CB][1, 2, 3] | getpath(path(skip (1; .[]))) \-= 1 \-\-> [1, 1, 2]\f[B]\f[R] .IP \[bu] 2 \f[B]\f[CB][1, 2, 3] | getpath(path(last ( .[]))) \-= 1 \-\-> [1, 2, 2]\f[B]\f[R] (this example yields an error in \f[B]\f[CB]jq\f[B]\f[R], whereas it works in jaq) .TP \f[I]Advanced\f[R] The following table shows how jaq executes an update \f[B]\f[CB]p |= u\f[B]\f[R]. In this table, the case for \f[B]\f[CB]f as $x | g\f[B]\f[R] assumes that \f[B]\f[CB]f\f[B]\f[R] yields single outputs \f[B]\f[CB]f1\f[B]\f[R], \&..., \f[B]\f[CB]fn\f[B]\f[R]. .PP .TS tab(@); l l. T{ .PP \f[B]\f[CB]p\f[B]\f[R] T}@T{ .PP \f[B]\f[CB]p |= u\f[B]\f[R] T} _ T{ .PP \f[B]\f[CB].\f[B]\f[R] T}@T{ .PP \f[B]\f[CB]u\f[B]\f[R] T} T{ .PP \f[B]\f[CB]..\f[B]\f[R] T}@T{ .PP \f[B]\f[CB]def rec_up: (.[]? | rec_up), .; rec_up |= u\f[B]\f[R] T} T{ .PP \f[B]\f[CB]f | g\f[B]\f[R] T}@T{ .PP \f[B]\f[CB]f |= (g |= u)\f[B]\f[R] T} T{ .PP \f[B]\f[CB]f , g\f[B]\f[R] T}@T{ .PP \f[B]\f[CB]f |= u | g |= u\f[B]\f[R] T} T{ .PP \f[B]\f[CB]f as $x | g\f[B]\f[R] T}@T{ .PP \f[B]\f[CB](f1 as $x | g) |= u | ... | (fn as $x | g) |= u\f[B]\f[R] T} T{ .PP \f[B]\f[CB]f // g\f[B]\f[R] T}@T{ .PP \f[B]\f[CB]if first(f // false) then f else g end |= u\f[B]\f[R] T} T{ .PP \f[B]\f[CB]if $p then f else g end\f[B]\f[R] T}@T{ .PP \f[B]\f[CB]if $p then f |= u else g |= u end\f[B]\f[R] T} T{ .PP \f[B]\f[CB].[]\f[B]\f[R] T}@T{ .PP \f[B]\f[CB] iter_upd( u; error)\f[B]\f[R] T} T{ .PP \f[B]\f[CB].[$i]\f[B]\f[R] T}@T{ .PP \f[B]\f[CB]index_upd($i; u; error)\f[B]\f[R] T} T{ .PP \f[B]\f[CB].[$i: ]\f[B]\f[R] T}@T{ .PP \f[B]\f[CB]slice_upd($i; length; u; error)\f[B]\f[R] T} T{ .PP \f[B]\f[CB].[ :$j]\f[B]\f[R] T}@T{ .PP \f[B]\f[CB]slice_upd(0 ; $j ; u; error)\f[B]\f[R] T} T{ .PP \f[B]\f[CB].[$i:$j]\f[B]\f[R] T}@T{ .PP \f[B]\f[CB]slice_upd($i; $j ; u; error)\f[B]\f[R] T} .TE It follows from the table that \f[B]\f[CB]empty |= f\f[B]\f[R] is equivalent to \f[B]\f[CB].\f[B]\f[R] (identity). We now give definitions for \f[B]\f[CB]iter_upd\f[B]\f[R], \f[B]\f[CB]index_upd\f[B]\f[R], and \f[B]\f[CB]slice_upd\f[B]\f[R]: .IP .EX # .[] |= u def iter_upd(u; fail): if isarray then [.[] | u] elif isobject then with_entries(.value |= u) else fail end; def eq($x; u; $y): $x | (.[] |= u) == $y and iter_upd(u; error) == $y; all( eq([1, 2, 3] ; .+1 ; [2, 3, 4] ), eq([1, 2, 3] ; .+1,. ; [2, 1, 3, 2, 4, 3]), eq([1, 2, 3] ; select(.%2 == 1); [1, 3] ), eq({a: 1, b: 2}; .+1 ; {\[dq]a\[dq]: 2, \[dq]b\[dq]: 3} ), eq({a: 1, b: 2}; .+1,. ; {\[dq]a\[dq]: 2, \[dq]b\[dq]: 3} ) ; .) \-\-> true .EE .IP .EX # .[$i] |= u def index_upd($i; u; fail): if (isstring or isarray) and ($i | isobject) then # see \[ga]slice_upd\[ga] below ([.[:$i.start], .[$i.start:$i.end], .[$i.end:]]? | .[1] |= u | add) // fail elif isarray then if 0 <= $i and $i < length then .[:$i] + [.[$i] | first(u)] + .[$i+1:] elif \-length <= $i and $i < 0 then index_upd(length + $i; u; fail) else fail end elif isobject then if has($i) then with_entries(if .key == $i then {key, value: first(.value | u)} end) else . + ([{key: $i, value: first(null | u)}] | from_entries) end else fail end; def eq($x; $i; u; $y): $x | (.[$i] |= u) == $y and index_upd($i; u; error) == $y; all( eq([1, 2, 3] ; 0 ; .+1 ; [2, 2, 3] ), eq([1, 2, 3] ; 0 ; .+1,.; [2, 2, 3] ), eq([1, 2, 3] ; 0 ; empty; [ 2, 3] ), eq([1, 2, 3] ; \-1 ; .+1 ; [1, 2, 4] ), eq([1, 2, 3] ; \-3 ; .+1 ; [2, 2, 3] ), eq({a: 1, b: 2}; \[dq]a\[dq]; .+1 ; {\[dq]a\[dq]: 2, \[dq]b\[dq]: 2}), eq({a: 1, b: 2}; \[dq]a\[dq]; .+1,.; {\[dq]a\[dq]: 2, \[dq]b\[dq]: 2}), eq({a: 1, b: 2}; \[dq]a\[dq]; empty; { \[dq]b\[dq]: 2}) ; .) \-\-> true .EE .IP .EX # .[$i:$j] |= u def slice_upd($i; $j; u; fail): ([.[:$i], .[$i:$j], .[$j:]]? | .[1] |= u | add) // fail; def eq($x; $i; $j; u; $y): $x | (.[$i:$j] |= u) == $y and slice_upd($i; $j; u; error) == $y; all( eq([1, 2, 3, 4]; 1; \-1; map(.+1) ; [1, 3, 4, 4]), eq([1, 2, 3, 4]; 1; \-1; map(.+1),. ; [1, 3, 4, 4]), eq([1, 2, 3, 4]; 1; \-1; empty ; [1, 4]), eq(\[dq]abcd\[dq] ; 1; \-1; ascii_upcase; \[dq]aBCd\[dq] ), eq(\[dq]abcd\[dq] ; 1; \-1; .+. ; \[dq]abcbcd\[dq] ), eq(\[dq]abcd\[dq] ; 1; \-1; empty ; \[dq]ad\[dq] ) ; .) \-\-> true .EE Similar as for \f[B]\f[CB]path\f[B]\f[R], we can also use compound paths such as \f[B]\f[CB].[]?\f[B]\f[R] and \f[B]\f[CB].a[]\f[B]\f[R] on the left\-hand side of updates. The error\-suppressing operators \f[B]\f[CB].[]?\f[B]\f[R], \f[B]\f[CB].[$i]?\f[B]\f[R], \&..., \f[B]\f[CB].[$i:$j]?\f[B]\f[R] are executed like their regular counterparts, but using \f[B]\f[CB].\f[B]\f[R] instead of \f[B]\f[CB]error\f[B]\f[R] as last argument (\f[B]\f[CB]fail\f[B]\f[R]) for the \f[B]\f[CB]*_upd\f[B]\f[R] filters. That means that if an error\-suppressing operator fails, it returns its input unchanged instead of throwing an error. .TP \f[I]Compatibility\f[R] In \f[B]\f[CB]jq\f[B]\f[R], \f[B]\f[CB]. |= empty\f[B]\f[R] yields \f[B]\f[CB]null\f[B]\f[R] for any input, whereas jaq yields no output. Similarily, in \f[B]\f[CB]jq\f[B]\f[R], \f[B]\f[CB]. |= (., .)\f[B]\f[R] yields its input once, whereas jaq yields its input twice. In \f[B]\f[CB]jq\f[B]\f[R], \f[B]\f[CB][0, 1] | .[3] = 3\f[B]\f[R] yields \f[B]\f[CB][0, 1, null, 3]\f[B]\f[R]; that is, \f[B]\f[CB]jq\f[B]\f[R] fills up the list with \f[B]\f[CB]null\f[B]\f[R]s if we update beyond its size. In contrast, jaq fails with an out\-of\-bounds error in such a case. \f[B]\f[CB]jq\f[B]\f[R] does not support updating string slices, whereas jaq does. In \f[B]\f[CB]jq\f[B]\f[R], \f[B]\f[CB]null | .a = 1\f[B]\f[R] yields \f[B]\f[CB]{\[dq]a\[dq]: 1}\f[B]\f[R] and \f[B]\f[CB]null | .[0] = 1\f[B]\f[R] yields \f[B]\f[CB][1]\f[B]\f[R], meaning that \f[B]\f[CB]jq\f[B]\f[R] treats \f[B]\f[CB]null\f[B]\f[R] as empty array or object when updating it with a string or integer index. Because jaq supports non\-string object keys, this is ambiguous, because it is not clear whether \f[B]\f[CB]null | .[0] = 1\f[B]\f[R] should yield \f[B]\f[CB]{0: 1}\f[B]\f[R] or \f[B]\f[CB][1]\f[B]\f[R]. For that reason, jaq yields an error on updates of null with any kind of index. .SS PATTERNS The filter \f[B]\f[CB]f as $x | g\f[B]\f[R] binds the outputs of \f[B]\f[CB]f\f[B]\f[R] to a variable \f[B]\f[CB]$x\f[B]\f[R]. At the place of \f[B]\f[CB]$x\f[B]\f[R], we can use a \f[B]pattern\f[R] to \f[I]destructure\f[R] the input into multiple variables. .PP Consider the following filter: .IP .EX [ 1, {a: 2}] | \&.[0] as $x | \&.[1].a as $y | $x, $y \-\-> 1 2 .EE .PP We can write this more compactly using a pattern as follows: .IP .EX [ 1, {a: 2}] as [$x, {a: $y}] | $x, $y \-\-> 1 2 .EE .PP Here, \f[B]\f[CB][$x, {a: $y}]\f[B]\f[R] is a pattern that is used to match the value \f[B]\f[CB][1, {a: 2}]\f[B]\f[R]. It binds \f[B]\f[CB]1\f[B]\f[R] to \f[B]\f[CB]$x\f[B]\f[R] and \f[B]\f[CB]2\f[B]\f[R] to \f[B]\f[CB]$y\f[B]\f[R]. .PP Similarly to object construction, \f[B]\f[CB]{$x}\f[B]\f[R] is equivalent to \f[B]\f[CB]{x: $x}\f[B]\f[R] also for object patterns. For example, we could have written the previous example equivalently as \f[B]\f[CB][1, {a: 2}] as [$x, {$a}] | $x, $a \-\-> 1 2\f[B]\f[R] .PP When a pattern does not exist in its input, its corresponding variables are bound to \f[B]\f[CB]null\f[B]\f[R]: .IP \[bu] 2 \f[B]\f[CB][1, {b: 2}] as [$x, {$a}] | $x, $a \-\-> 1 null\f[B]\f[R] .IP \[bu] 2 \f[B]\f[CB][1 ] as [$x, $y] | $x, $y \-\-> 1 null\f[B]\f[R] .IP \[bu] 2 \f[B]\f[CB][1, {a: 2}] as [$x, [$y]] | $x, $y \-\-> 1 null\f[B]\f[R] .PP If the types of a pattern and its input do not match, an error is thrown: .IP \[bu] 2 \f[B]\f[CB]try ([1] as {$a} | $a) catch \[dq]fail\[dq] \-\-> \[dq]fail\[dq]\f[B]\f[R] .IP \[bu] 2 \f[B]\f[CB]try ( 1 as [$x] | $x) catch \[dq]fail\[dq] \-\-> \[dq]fail\[dq]\f[B]\f[R] .PP Patterns do not have to match their whole input: .IP \[bu] 2 \f[B]\f[CB][ 1, 2] as [$x] | $x \-\-> 1\f[B]\f[R] .IP \[bu] 2 \f[B]\f[CB]{a: 1, b: 2} as {$a} | $a \-\-> 1\f[B]\f[R] .PP Patterns can be arbitrarily nested: .IP \[bu] 2 \f[B]\f[CB]{a: [1, {b: [2]}]} as {a: [$x, {b: [$y]}]} | $x, $y \-\-> 1 2\f[B]\f[R] .IP \[bu] 2 \f[B]\f[CB][[[1]]] as [[[$x]]] | $x \-\-> 1\f[B]\f[R] .IP \[bu] 2 \f[B]\f[CB]{a: {b: {c: 1}}} as {a: {b: {c: $x}}} | $x \-\-> 1\f[B]\f[R] .PP We can write any filter \f[B]\f[CB](f)\f[B]\f[R] as object key in a pattern: .IP .EX {a: 1, b: 2, c: 3, d: 4} as {(\[dq]a\[dq], \[dq]b\[dq]): $x, (\[dq]c\[dq], \[dq]d\[dq]): $y} | [$x, $y] \-\-> [1, 3] [1, 4] [2, 3] [2, 4] .EE .PP We can also use patterns in \f[B]\f[CB]reduce\f[B]\f[R] and \f[B]\f[CB]foreach\f[B]\f[R]: .IP .EX [{\[dq]a\[dq]: 1, \[dq]b\[dq]: 2}, {\[dq]a\[dq]: 3, \[dq]b\[dq]: 4}] | foreach .[] as {(\[dq]a\[dq], \[dq]b\[dq]): $x} ([]; . + [$x]) \-\-> [1] [1,2] [1,2,3] [1,2,3,4] .EE .TP \f[I]Compatibility\f[R] jaq does not support \f[B]\f[CB]jq\f[B]\f[R]\[cq]s destructuring alternative operator \c .UR https://jqlang.org/manual/#destructuring-alternative-operator \f[B]\f[CB]?//\f[B]\f[R] .UE \c \&. .TP \f[I]Advanced\f[R] A pattern \f[B]\f[CB]p\f[B]\f[R] is either: .IP \[bu] 2 a variable \f[B]\f[CB]$x\f[B]\f[R], .IP \[bu] 2 an array pattern \f[B]\f[CB][p1, ..., pn]\f[B]\f[R] containing \f[B]\f[CB]n\f[B]\f[R] patterns, or .IP \[bu] 2 an object pattern \f[B]\f[CB]{e1, ..., en}\f[B]\f[R] containing \f[B]\f[CB]n\f[B]\f[R] object entries. An object entry \f[B]\f[CB]e\f[B]\f[R] is either: .RS 2 .IP \[bu] 2 a variable \f[B]\f[CB]$x\f[B]\f[R] or .IP \[bu] 2 a key\-value pair \f[B]\f[CB](k): p\f[B]\f[R] (where \f[B]\f[CB]k\f[B]\f[R] is a filter and \f[B]\f[CB]p\f[B]\f[R] is a pattern). .RE An array pattern \f[B]\f[CB][p1, ..., pn]\f[B]\f[R] is equivalent to an object pattern \f[B]\f[CB]{(0): p1, ..., (n): pn}\f[B]\f[R]. Because of this, you can use object patterns with integer keys to destructure arrays, or array patterns to destructure objects with integer keys. Furthermore, you can also destructure byte strings: .IP \[bu] 2 \f[B]\f[CB][1, 2, 3] as {(0): $x, (2): $y} | $x, $y \-\-> 1 3\f[B]\f[R] .IP \[bu] 2 \f[B]\f[CB]{(0): 1, (2): 3} as [$x, $_, $y] | $x, $y \-\-> 1 3\f[B]\f[R] .IP \[bu] 2 \f[B]\f[CB][1, 2, 3] | tobytes as [$x, $y] | $x, $y \-\-> 1 2\f[B]\f[R] When using a filter \f[B]\f[CB](f)\f[B]\f[R] as object key in a pattern, then \f[B]\f[CB]f\f[B]\f[R] is run with the input that was matched by its parent object pattern, not by the whole pattern. For example, \f[B]\f[CB][{\[dq]k\[dq]: \[dq]a\[dq], \[dq]a\[dq]: 1}] as [{(.k): $x}] | $x \-\-> 1\f[B]\f[R] This is equivalent to: .IP .EX [{\[dq]k\[dq]: \[dq]a\[dq], \[dq]a\[dq]: 1}] | \&.[0] as $p0 | $p0[$p0 | .k] as $x | $x \-\-> 1 .EE Here, we can see that \f[B]\f[CB](.k)\f[B]\f[R] is run with the input \f[B]\f[CB]$p0\f[B]\f[R], which is the value that the parent object pattern of \f[B]\f[CB](.k)\f[B]\f[R], namely \f[B]\f[CB]{(.k): $x}\f[B]\f[R], is trying to match. Compare this with the following \f[I]wrong\f[R] transformation, where \f[B]\f[CB](.k)\f[B]\f[R] would be run with the input matched by the whole pattern: .IP .EX [{\[dq]k\[dq]: \[dq]a\[dq], \[dq]a\[dq]: 1}] | try ( \&.[0] as $p0 | $p0[.k] as $x | # fails here because .k is run with whole input $x ) catch \[dq]fail\[dq] \-\-> \[dq]fail\[dq] .EE .SS MODULES jq allows dividing programs into multiple files that are called \f[B]modules\f[R]. .PP At the beginning of any jq module, there is a module header that consists of a (potentially empty) sequence of instructions listed in this section. The module header is then followed by a sequence of definitions. Finally, the main module that is called from the command\-line interface (via \f[B]\f[CB]\-\-from\-file\f[B]\f[R] or inline) must contain a single filter at the end, which is the filter that is executed. .PP All \f[B]\f[CB]include\f[B]\f[R]/\f[B]\f[CB]import\f[B]\f[R] instructions search for files as explained in the search paths section. .SS Module metadata The instruction \f[B]\f[CB]module meta;\f[B]\f[R] sets the metadata of the current module to the output of \f[B]\f[CB]meta\f[B]\f[R], where \f[B]\f[CB]meta\f[B]\f[R] is a filter. This instruction may occur only at the beginning of the module header and only once. .PP For example, \f[B]\f[CB]module \[dq]My module\[dq]; 1 \-\-> 1\f[B]\f[R]. .TP \f[I]Compatibility\f[R] jaq ignores this instruction, whereas \f[B]\f[CB]jq\f[B]\f[R] uses it to provides the output of \f[B]\f[CB]meta\f[B]\f[R] via the \f[B]\f[CB]modulemeta\f[B]\f[R] filter. .SS Module inclusion The instructions \f[B]\f[CB]include \[dq]mod\[dq];\f[B]\f[R] and \f[B]\f[CB]include \[dq]mod\[dq] meta;\f[B]\f[R] make all filters defined in the module \f[B]\f[CB]mod.jq\f[B]\f[R] accessible in the current module. .PP For example, if \f[B]\f[CB]foo.jq\f[B]\f[R] in the current working directory contains \f[B]\f[CB]def bar: 1;\f[B]\f[R], then \f[B]\f[CB]jaq \-L . \-n \[aq]include \[dq]foo\[dq]; bar\[aq]\f[B]\f[R] yields \f[B]\f[CB]1\f[B]\f[R]. .SS Module import The instructions \f[B]\f[CB]import \[dq]mod\[dq] as name;\f[B]\f[R] and \f[B]\f[CB]import \[dq]mod\[dq] as name meta;\f[B]\f[R] make all definitions in the module \f[B]\f[CB]mod.jq\f[B]\f[R] accessible in the current module with the prefix \f[B]\f[CB]name::\f[B]\f[R]. .PP For example: .IP .EX $ echo \[aq]def bar: 1;\[aq] > foo.jq && jaq \-L . \-n \[aq]import \[dq]foo\[dq] as myfoo; myfoo::bar\[aq] && rm foo.jq 1 .EE .SS Data import The instructions \f[B]\f[CB]import \[dq]data\[dq] as $name;\f[B]\f[R] and \f[B]\f[CB]import \[dq]data\[dq] as $name meta;\f[B]\f[R] load all JSON values in \f[B]\f[CB]data.json\f[B]\f[R] to an array, bind it to the variable \f[B]\f[CB]$name\f[B]\f[R], and make it accessible in the current module. .PP For example: .IP .EX $ echo 1 2 3 > foo.json && jaq \-L . \-nc \[aq]import \[dq]foo.json\[dq] as $myfoo; $myfoo\[aq] && rm foo.json [1,2,3] .EE .SS Search paths An \f[B]\f[CB]include\f[B]\f[R]/\f[B]\f[CB]import\f[B]\f[R] instruction searches for its given file in the following directories, in the following order: .IP "1." 3 The global search paths given via \f[B]\f[CB]\-\-library\-path\f[B]\f[R]. They are interpreted relative to the current working directory. .IP "2." 3 The local search paths given via metadata: When an \f[B]\f[CB]include\f[B]\f[R]/\f[B]\f[CB]import\f[B]\f[R] instruction has \f[B]\f[CB]meta\f[B]\f[R] of the shape \f[B]\f[CB]{..., search: ..., ...}\f[B]\f[R], then the value at the key \f[B]\f[CB]\[dq]search\[dq]\f[B]\f[R] sets the local search paths for that instruction to: .RS 4 .IP \[bu] 2 If the value is a string: Just that string. .IP \[bu] 2 If the value is an array: All strings in the array. .IP \[bu] 2 Otherwise: Nothing. If the module containing the \f[B]\f[CB]include\f[B]\f[R]/\f[B]\f[CB]import\f[B]\f[R] instruction is a file, then these paths are interpreted relative to the parent directory of that module. Otherwise, these paths are interpreted relative to the current working directory. (That is the case if the module containing the \f[B]\f[CB]include\f[B]\f[R]/\f[B]\f[CB]import\f[B]\f[R] instruction is given inline on the command\-line.) .RE .PP Every global and local search path is substituted as follows: .IP \[bu] 2 If it starts with \f[B]\f[CB]\[ti]\f[B]\f[R], then \f[B]\f[CB]\[ti]\f[B]\f[R] is substituted with the user\[cq]s home directory, given by the environment variable \f[B]\f[CB]HOME\f[B]\f[R] on Linux and \f[B]\f[CB]USERPROFILE\f[B]\f[R] on Windows. .IP \[bu] 2 If it starts with \f[B]\f[CB]$ORIGIN\f[B]\f[R], then \f[B]\f[CB]$ORIGIN\f[B]\f[R] is substituted by the directory in which the \f[B]\f[CB]jaq\f[B]\f[R] executable resides. .PP For example, \f[B]\f[CB]jaq \-L \[ti]/foo \-L bar \[aq]include \[dq]decode\[dq] {search: [\[dq]baz\[dq], \[dq]$ORIGIN/quux\[dq]]}; 1\[aq]\f[B]\f[R] searches for the file \f[B]\f[CB]decode.jq\f[B]\f[R] at the following paths in the given order: .IP "1." 3 \f[B]\f[CB]\[ti]/foo/decode.jq\f[B]\f[R] (where \f[B]\f[CB]\[ti]\f[B]\f[R] is substituted by the user\[cq]s home directory) .IP "2." 3 \f[B]\f[CB]./bar/decode.jq\f[B]\f[R] .IP "3." 3 \f[B]\f[CB]./baz/decode.jq\f[B]\f[R] .IP "4." 3 \f[B]\f[CB]$ORIGIN/quux/decode.jq\f[B]\f[R] (where \f[B]\f[CB]$ORIGIN\f[B]\f[R] is substituted by the parent directory of the \f[B]\f[CB]jaq\f[B]\f[R] executable) .PP The first path that corresponds to an existing file is taken. .PP Now, suppose that \f[B]\f[CB]decode.jq\f[B]\f[R] contains an instruction \f[B]\f[CB]import \[dq]binary\[dq] as $binary {search: \[dq].\[dq]}\f[B]\f[R]. This searches for \f[B]\f[CB]binary.json\f[B]\f[R] at the following paths: .IP "1." 3 \f[B]\f[CB]\[ti]/foo/binary.json\f[B]\f[R] .IP "2." 3 \f[B]\f[CB]./bar/binary.json\f[B]\f[R] (relative to the current working directory) .IP "3." 3 \f[B]\f[CB]./binary.json\f[B]\f[R] (relative to the parent directory of \f[B]\f[CB]decode.jq\f[B]\f[R]) .TP \f[I]Compatibility\f[R] If a file to load has been given without extension, such as \f[B]\f[CB]decode\f[B]\f[R] and \f[B]\f[CB]binary\f[B]\f[R] above, then jaq adds an extension (\f[B]\f[CB].jq\f[B]\f[R] for modules or \f[B]\f[CB].json\f[B]\f[R] for data). \f[B]\f[CB]jq\f[B]\f[R] adds an extension \f[I]unconditionally\f[R]; that is, even if an extension has been given as part of the file name, \f[B]\f[CB]jq\f[B]\f[R] adds an extension. jaq\[cq]s behaviour is motivated by allowing instructions like \f[B]\f[CB]import \[dq]binary.cbor\[dq] as $binary\f[B]\f[R] in the future. Here, unconditionally adding the \f[B]\f[CB].json\f[B]\f[R] extension would be counterproductive. .SS COMMENTS A comment starts with \f[B]\f[CB]#\f[B]\f[R] and ends with the first newline that is not preceded by an uneven number of backslashes (\f[B]\f[CB]\[rs]\[ga]). For example:\f[B]\f[R] .IP .EX [ 1, # comment 2, # comment \[rs]\[rs] 3, # comment \[rs] comment 4, # comment \[rs]\[rs]\[rs] comment \[rs] comment 5 ] .EE .PP This is equivalent to \f[B]\f[CB][1, 2, 3, 4, 5]\f[B]\f[R]. .SH FORMATS jaq supports reading and writing several data formats. This section describes these data formats. .PP You can load and write data in these formats using either: .IP \[bu] 2 the command\-line options \f[B]\f[CB]\-\-from\f[B]\f[R] / \f[B]\f[CB]\-\-to\f[B]\f[R], or .IP \[bu] 2 (de\-)serialisation filters such as \f[B]\f[CB]fromjson\f[B]\f[R] and \f[B]\f[CB]toyaml\f[B]\f[R] .PP The command\-line options \f[B]\f[CB]\-\-from\f[B]\f[R] and \f[B]\f[CB]\-\-to\f[B]\f[R] always yield better or equal performance than the corresponding filters. .SS JSON \c .UR https://www.json.org JSON .UE \c (JavaScript Object Notation) is specified in \c .UR https://datatracker.ietf.org/doc/html/rfc8259 RFC 8259 .UE \c \&. .PP jaq can read all valid JSON values; however, like \f[B]\f[CB]jq\f[B]\f[R], it also accepts certain values that are invalid JSON. This set of values is documented in the XJON section. .SS XJON The native data format of jaq is a superset of JSON called \f[B]XJON\f[R] (eXtended JavaScript Object Notation, pronounced like \[lq]action\[rq]). .PP XJON extends JSON with following constructs: .IP \[bu] 2 Line comments: \f[B]\f[CB]# ... \[rs]n\f[B]\f[R] is interpreted as comment .IP \[bu] 2 Special floating\-point numbers: \f[B]\f[CB]NaN\f[B]\f[R], \f[B]\f[CB]Infinity\f[B]\f[R], \f[B]\f[CB]+Infinity\f[B]\f[R], \f[B]\f[CB]\-Infinity\f[B]\f[R] .IP \[bu] 2 Numbers starting with \f[B]\f[CB]+\f[B]\f[R] or multiple zeros: The beginning of a number corresponds to the regex \f[B]\f[CB][+\-]?\[rs]d+\f[B]\f[R] in XJON and \f[B]\f[CB]\-?(0|[1\-9]\[rs]d*)\f[B]\f[R] in JSON. That means that in XJON, \f[B]\f[CB]+7.1\f[B]\f[R], \f[B]\f[CB]007\f[B]\f[R], \f[B]\f[CB]\-042\f[B]\f[R] are all valid numbers, whereas they are invalid in JSON. .IP \[bu] 2 UTF\-8 strings with invalid code units: The JSON standard is slightly ambiguous whether strings may contain invalid UTF\-8 code units. XJON explicitly allows for invalid code units in UTF\-8 strings, e.g. the output of \f[B]\f[CB]printf \[aq]\[dq]\[rs]xFF\[dq]\[aq]\f[B]\f[R]. This increases compatibility with tools that output such strings (e.g. file names). Furthermore, it allows for constant\-time loading of strings via \f[B]\f[CB]\-\-rawfile\f[B]\f[R], where jq takes linear time due to UTF\-8 validation. .IP \[bu] 2 Byte strings: A byte string is created via \f[B]\f[CB]b\[dq]...\[dq]\f[B]\f[R], where \f[B]\f[CB]...\f[B]\f[R] is a sequence of: .RS 2 .IP \[bu] 2 bytes in the range 0x20 to (including) 0xFF, excluding the ASCII characters \f[B]\f[CB]\[aq]\[dq]\[aq]\f[B]\f[R] and \f[B]\f[CB]\[aq]\[rs]\[aq]\f[B]\f[R] .IP \[bu] 2 an escape sequence, starting with a backslash (\f[B]\f[CB]\[aq]\[rs]\[aq]\f[B]\f[R]) and followed by \f[B]\f[CB]b\f[B]\f[R], \f[B]\f[CB]f\f[B]\f[R], \f[B]\f[CB]n\f[B]\f[R], \f[B]\f[CB]r\f[B]\f[R], \f[B]\f[CB]t\f[B]\f[R], \f[B]\f[CB]\[aq]\[dq]\[aq]\f[B]\f[R], \f[B]\f[CB]\[aq]\[rs]\[aq]\f[B]\f[R], or \f[B]\f[CB]xHH\f[B]\f[R], where \f[B]\f[CB]HH\f[B]\f[R] is a hexadecimal number For example: \f[B]\f[CB]b\[dq]Here comes \[rs]xFF, dadadada\[rs]nHere comes \[rs]xFF\[rs]nAnd I say: \[rs]\[dq]It\[aq]s alright\[rs]\[dq]\[rs]x00\[dq]\f[B]\f[R]. Byte strings of this shape can also be found in other languages, like Rust & Python (with leading \f[B]\f[CB]b\f[B]\f[R]) and JavaScript & C (without leading \f[B]\f[CB]b\f[B]\f[R]). .RE .IP \[bu] 2 Objects with non\-string keys: Where JSON limits object keys to strings, XJON allows arbitrary values as object keys. For example: \f[B]\f[CB]{null: 0, true: 1, 2: 3, \[dq]str\[dq]: 4, [\[dq]arr\[dq]]: 5, {}: 6}\f[B]\f[R] .PP The goal behind XJON was to support a set of values present in YAML and CBOR, namely byte strings and objects with non\-string keys, while keeping the format both human\-readable and simple & performant to parse, like JSON. .PP XJON can losslessly encode any jaq value; in particular, decoding an XJON\-encoded value is equivalent to the original value. For example: .IP \[bu] 2 \f[B]\f[CB]nan | . | isnan \-\-> true\f[B]\f[R] in jaq and \f[B]\f[CB]jq\f[B]\f[R] .IP \[bu] 2 \f[B]\f[CB]nan | tojson | fromjson | isnan \-\-> true\f[B]\f[R] in jaq, but \f[B]\f[CB]false\f[B]\f[R] in \f[B]\f[CB]jq\f[B]\f[R] .PP That means that \f[B]\f[CB]tojson | fromjson\f[B]\f[R] is equivalent to \f[B]\f[CB].\f[B]\f[R] in jaq, whereas it is \f[I]not\f[R] equivalent in \f[B]\f[CB]jq\f[B]\f[R], in particular because of \f[B]\f[CB]NaN\f[B]\f[R] and \f[B]\f[CB]Infinity\f[B]\f[R]. .PP Currently, wherever jaq accepts JSON, it also accepts XJON. That means that jaq accepts the following, even if it is not valid JSON: .IP .EX $ echo \[aq]NaN b\[dq]Bytes\[dq] {1: 2} # Over and out\[aq] | jaq \-\-from json \-c NaN b\[dq]Bytes\[dq] {1:2} .EE .SS YAML \c .UR https://yaml.org/ YAML .UE \c (YAML Ain\[cq]t Markup Language™) is \[lq]a human\-friendly data serialization language for all programming languages\[rq]. It is also a JSON and XJON superset. That means that every jaq value can be encoded as YAML value. .PP jaq supports reading YAML with anchors (\f[B]\f[CB]&foo\f[B]\f[R]) and aliases (\f[B]\f[CB]*foo\f[B]\f[R]). These allow the creation of shared data structures. However, jaq does not support self\-referential data, i.e. data that contains an alias pointing to itself. For example: .IP \[bu] 2 \f[B]\f[CB]\[dq][&a 1, &b 2, *a, *b]\[dq] | fromyaml \-\-> [1, 2, 1, 2]\f[B]\f[R] .IP \[bu] 2 \f[B]\f[CB]\[dq][&b [&a [], *a], *b]\[dq] | fromyaml \-\-> [[[], []], [[], []]]\f[B]\f[R] .IP \[bu] 2 \f[B]\f[CB]\[dq]&a[*a]\[dq] | try fromyaml catch \-1 \-\-> \-1\f[B]\f[R] .PP jaq validates tags for scalar YAML values, such as \f[B]\f[CB]null\f[B]\f[R], booleans, numbers, and strings: .IP \[bu] 2 \f[B]\f[CB]\[dq]!!bool true\[dq] | fromyaml \-\-> true\f[B]\f[R] .IP \[bu] 2 \f[B]\f[CB]\[dq]!!int true\[dq] | try fromyaml catch \[dq]fail\[dq] \-\-> \[dq]fail\[dq]\f[B]\f[R] .PP On the other hand, jaq ignores tags for arrays and objects: .IP \[bu] 2 \f[B]\f[CB]\[dq]!!foo []\[dq] | fromyaml \-\-> []\f[B]\f[R] .IP \[bu] 2 \f[B]\f[CB]\[dq]!!bar {}\[dq] | fromyaml \-\-> {}\f[B]\f[R] .PP jaq produces YAML that is very close to JSON/XJON. jaq\[cq]s compact YAML output differs from XJON mostly by writing byte strings as Base64\-encoded \f[B]\f[CB]!!binary\f[B]\f[R] string and special floating\-point values as \f[B]\f[CB].inf\f[B]\f[R], \f[B]\f[CB]\-.inf\f[B]\f[R], and \f[B]\f[CB].nan\f[B]\f[R]: .IP .EX [infinite, \-infinite, nan, (\[dq]a\[dq] | tobytes), {\[dq]a\[dq]: 1}] | tojson, toyaml \-\-> \[dq][Infinity,\-Infinity,NaN,b\[rs]\[dq]a\[rs]\[dq],{\[rs]\[dq]a\[rs]\[dq]:1}]\[dq] \[dq][.inf, \-.inf, .nan, !!binary YQ==, {a: 1}]\[dq] .EE .PP jaq preserves invalid UTF\-8 sequences in text strings when writing YAML. However, jaq yields an error when trying to parse YAML containing invalid UTF\-8 sequences. .PP When using \f[B]\f[CB]\-\-to yaml\f[B]\f[R], jaq writes \f[B]\f[CB]\-\-\-\f[B]\f[R] before every output value and \f[B]\f[CB]...\f[B]\f[R] after every output value. This is done to indicate the start/end of YAML documents. For example: .IP .EX $ jaq \-n \[aq][1, {a: 2, b: [3]}]\[aq] \-\-to yaml \-\-\- \- 1 \- a: 2 b: \- 3 \&... $ echo 1 2 | jaq \-\-to yaml \-\-\- 1 \&... \-\-\- 2 \&... .EE .PP Use \f[B]\f[CB]\-j\f[B]\f[R] to omit YAML document start/end markers. This can come in handy when merging multiple arrays: .IP .EX $ echo \[aq][1, 2] [3, 4]\[aq] | jaq \-\-to yaml \-j \- 1 \- 2 \- 3 \- 4 .EE .PP Both \f[B]\f[CB]\-\-from yaml\f[B]\f[R] and the filter \f[B]\f[CB]fromyaml\f[B]\f[R] load the full input into memory before parsing it. .SS CBOR \c .UR https://cbor.io/ CBOR .UE \c (Concise Binary Object Representation) is a binary format specified in \c .UR https://www.rfc-editor.org/rfc/rfc8949.html RFC 8949 .UE \c \&. .PP CBOR values are a superset of jaq values. That means that there are CBOR values for which there are no equivalent jaq values, for example: .IP \[bu] 2 \c .UR https://www.rfc-editor.org/rfc/rfc8949.html#name-epoch-based-date-time date\-time .UE \c .IP \[bu] 2 \c .UR https://www.rfc-editor.org/rfc/rfc8949.html#name-undefined-values undefined .UE \c .IP \[bu] 2 \c .UR https://www.rfc-editor.org/rfc/rfc8949.html#fractions decimal fractions and bigfloats .UE \c .PP jaq fails when trying to decode such CBOR values. .PP Every jaq value can be encoded losslessly as a CBOR value, except for text strings with invalid UTF\-8 code units. Invalid UTF\-8 sequences are replaced with \f[B]\f[CB]U+FFFD\f[B]\f[R], which looks like this: \[lq]�\[rq]. .PP jaq writes sequences of CBOR values by concatenating them without any separator. That means that \f[B]\f[CB]\-\-to cbor\f[B]\f[R] is equivalent to \f[B]\f[CB]\-\-to cbor \-\-join\-output\f[B]\f[R]. jaq can also read sequences of concatenated CBOR values. .SS TOML \c .UR https://toml.io TOML .UE \c is a configuration file format. We can read and query TOML files like JSON files: .IP .EX $ jaq \[aq].profile.release[\[dq]codegen\-units\[dq]]\[aq] Cargo.toml 1 .EE .PP Furthermore, we can also write TOML files: .IP .EX $ echo \[aq]a = {b = 1, c = {d = nan, e = [], f = [{g = inf}, {h = \-inf}]}}\[aq] | jaq \-\-from toml \-\-to toml [a] b = 1 [a.c] d = nan e = [] [[a.c.f]] g = inf [[a.c.f]] h = \-inf .EE .PP Compared to jaq values, TOML has date\-time values, but TOML has neither \f[B]\f[CB]null\f[B]\f[R], byte strings, nor non\-string object keys. Furthermore, the root of a TOML value must be an object. That means that TOML writing may fail in various ways: .IP \[bu] 2 \f[B]\f[CB]0 | try totoml catch \-1 \-\-> \-1\f[B]\f[R] (non\-object root) .IP \[bu] 2 \f[B]\f[CB]{a: null } | try totoml catch \-1 \-\-> \-1\f[B]\f[R] (null) .IP \[bu] 2 \f[B]\f[CB]{a: 0 | tobytes} | try totoml catch \-1 \-\-> \-1\f[B]\f[R] (byte string) .IP \[bu] 2 \f[B]\f[CB]{(1): 2 } | try totoml catch \-1 \-\-> \-1\f[B]\f[R] (non\-string object key) .PP jaq can read \c .UR https://toml.io/en/v1.1.0 TOML 1.1.0 .UE \c values, except for date\-time values. jaq should generally be able to read TOML values it has written, with the exception of big integers. The next example creates an object \f[B]\f[CB]{a: 2\[ha]1024}\f[B]\f[R] containing a big integer, successfully writes it as TOML, then fails when trying to read it back: .PP \f[B]\f[CB]{a: nth(1024; 1 | recurse(.*2))} | totoml | try fromtoml catch \-1 \-\-> \-1\f[B]\f[R] .PP When writing TOML, jaq converts invalid UTF\-8 sequences as for CBOR. That means that even if reading a written TOML value succeeds, its output may not be the same as its input: .PP \f[B]\f[CB]{a: [\-255] | implode} | (totoml | fromtoml) == . \-\-> false\f[B]\f[R] .SS XML jaq reads data adhering to the \c .UR https://www.w3.org/TR/xml/ XML 1.0 .UE \c standard. However, it treats only XML data encoded as UTF\-8. .PP jaq can read XHTML files, but it cannot directly read HTML files. You can use tools such as \c .UR https://github.com/jfisteus/html2xhtml html2xhtml .UE \c to convert HTML to XHTML. .PP Mappings between XML to JSON generally have to make a compromise between \[lq]friendliness\[rq] and round\-tripping; see \[lq]\c .UR https://www.w3.org/2011/10/integration-workshop/p/XML_JSON_mapping_paper.pdf Experiences with JSON and XML Transformations .UE \c \[rq]. Here, \[lq]friendliness\[rq] means that JSON generated from XML has a flat structure, making it easy to consume it. Stefan Goessner gives a nice discussion of different \[lq]friendly\[rq] mappings in \[lq]\c .UR https://www.xml.com/pub/a/2006/05/31/converting-between-xml-and-json.html Converting Between XML and JSON .UE \c \[rq]. The take\-away message is: \[lq]Friendly\[rq] mappings lose information. For that reason, jaq does not use a \[lq]friendly\[rq] mapping, but rather a mapping that preserves XML information perfectly, making it suitable for round\-tripping. .PP As an example, consider the following input: .IP .EX <\f[B]a\f[R] href=\[dq]https://www.w3.org\[dq]>World Wide Web Consortium (<\f[B]em\f[R]>W3C</\f[B]em\f[R]>)</\f[B]a\f[R]> .EE .PP We can see its internal representation in jaq by: .IP .EX $ echo \[aq]<a href=\[dq]https://www.w3.org\[dq]>World Wide Web Consortium (<em>W3C</em>)</a>\[aq] \[rs] | jaq \-\-from xml . { \[dq]t\[dq]: \[dq]a\[dq], \[dq]a\[dq]: { \[dq]href\[dq]: \[dq]https://www.w3.org\[dq] }, \[dq]c\[dq]: [ \[dq]World Wide Web Consortium (\[dq], { \[dq]t\[dq]: \[dq]em\[dq], \[dq]c\[dq]: [ \[dq]W3C\[dq] ] }, \[dq])\[dq] ] } .EE .SS TAC objects Tags are represented by \f[I]TAC objects\f[R]. A TAC object may have the following fields: .IP \[bu] 2 \f[B]\f[CB]t\f[B]\f[R]: Name of the tag, such as \f[B]\f[CB]h1\f[B]\f[R] for \f[B]\f[CB]<h1>...</h1>\f[B]\f[R]. This field must always be present in a TAC object. .IP \[bu] 2 \f[B]\f[CB]a\f[B]\f[R]: Attributes of the tag, such as \f[B]\f[CB]{\[dq]id\[dq]: \[dq]foo\[dq], style: \[dq]color:blue;\[dq]}\f[B]\f[R]. If this field is present, it must contain an object with string values. .IP \[bu] 2 \f[B]\f[CB]c\f[B]\f[R]: Children of the tag. If this field is not present, this tag will be interpreted as self\-closing (such as \f[B]\f[CB]<br/>\f[B]\f[R]). When a TAC object produced by jaq (either via \f[B]\f[CB]\-\-from xml\f[B]\f[R] or \f[B]\f[CB]fromxml\f[B]\f[R]) has the \f[B]\f[CB]c\f[B]\f[R] field, it always holds an array of XML values. When writing XML values (either via \f[B]\f[CB]\-\-to xml\f[B]\f[R] or \f[B]\f[CB]toxml\f[B]\f[R]), jaq accepts any XML value at the \f[B]\f[CB]c\f[B]\f[R] field. .PP An example query to obtain all links in an XHTML file: .IP .EX \&.. | select(.t? == \[dq]a\[dq]) | .a.href .EE .PP We can also transform input XML and yield output XML. For example, to transform all \f[B]\f[CB]em\f[B]\f[R] tags to \f[B]\f[CB]i\f[B]\f[R] tags: .IP .EX (.. | select(.t? == \[dq]em\[dq]) | .t) = \[dq]i\[dq] .EE .PP To yield XML output instead of JSON output, use the option \f[B]\f[CB]\-\-to xml\f[B]\f[R]: .IP .EX $ echo \[aq]<a href=\[dq]https://www.w3.org\[dq]>World Wide Web Consortium (<em>W3C</em>)</a>\[aq] \[rs] | jaq \-\-from xml \-\-to xml \[aq](.. | select(.t? == \[dq]em\[dq]) | .t) = \[dq]i\[dq]\[aq] <a href=\[dq]https://www.w3.org\[dq]>World Wide Web Consortium (<i>W3C</i>)</a> .EE .PP Finally, we can extract all text from an XML file (discarding CDATA blocks): .IP .EX def xml_text: if isstring then . else .c[]? | xml_text end; [xml_text] .EE .SS Other values .IP \[bu] 2 Strings are neither escaped nor unescaped; that means, \f[B]\f[CB]Tom & Jerry\f[B]\f[R] in the source XML becomes \f[B]\f[CB]\[dq]Tom & Jerry\[dq]\f[B]\f[R] in the target JSON. The \f[B]\f[CB]\[at]html\f[B]\f[R]/\f[B]\f[CB]\[at]htmld\f[B]\f[R] filters can be used for manual (un\-)escaping. .IP \[bu] 2 A comment such as \f[B]\f[CB]<!\-\- this comment \-\->\f[B]\f[R] is converted to \f[B]\f[CB]{\[dq]comment\[dq]: \[dq] this comment \[dq]}\f[B]\f[R]. .IP \[bu] 2 A CDATA block such as \f[B]\f[CB]<![CDATA[Tom & Jerry]]>\f[B]\f[R] is converted to \f[B]\f[CB]{\[dq]cdata\[dq]: \[dq]Tom & Jerry\[dq]}\f[B]\f[R]. .IP \[bu] 2 An XML declaration such as \f[B]\f[CB]<?xml version=\[dq]1.0\[dq] encoding=\[dq]UTF\-8\[dq] standalone=\[dq]yes\[dq]?>\f[B]\f[R] is converted to \f[B]\f[CB]{\[dq]xmldecl\[dq]: {\[dq]version\[dq]: \[dq]1.0\[dq], \[dq]encoding\[dq]: \[dq]UTF\-8\[dq], \[dq]standalone\[dq]: \[dq]yes\[dq]}}\f[B]\f[R]. (Note that the values given in this declaration, such as the encoding, are ignored by jaq\[cq]s XML parser.) .IP \[bu] 2 A processing instruction such as \f[B]\f[CB]<?xml\-stylesheet href=\[dq]common.css\[dq]?>\f[B]\f[R] is converted to \f[B]\f[CB]{\[dq]pi\[dq]: {\[dq]target\[dq]: \[dq]xml\-stylesheet\[dq], \[dq]content\[dq]: \[dq]href=\[rs]\[dq]common.css\[rs]\[dq]\[dq]}}\f[B]\f[R]. .PP To put all of this together, consider the following XML file: .IP .EX $ cat examples/test.xhtml <?xml version=\[aq]1.0\[aq]?> <?xml\-stylesheet href=\[dq]common.css\[dq]?> <!DOCTYPE html> <html xmlns=\[dq]http://www.w3.org/1999/xhtml\[dq]> <body> <!\-\- CDATA blocks do not require escaping \-\-> <![CDATA[Hello & goodbye!]]><br/> </body> </html> .EE .PP This yields the following in jaq: .IP .EX $ jaq . examples/test.xhtml { \[dq]xmldecl\[dq]: { \[dq]version\[dq]: \[dq]1.0\[dq] } } { \[dq]pi\[dq]: { \[dq]target\[dq]: \[dq]xml\-stylesheet\[dq], \[dq]content\[dq]: \[dq]href=\[rs]\[dq]common.css\[rs]\[dq]\[dq] } } { \[dq]doctype\[dq]: { \[dq]name\[dq]: \[dq]html\[dq] } } { \[dq]t\[dq]: \[dq]html\[dq], \[dq]a\[dq]: { \[dq]xmlns\[dq]: \[dq]http://www.w3.org/1999/xhtml\[dq] }, \[dq]c\[dq]: [ \[dq]\[rs]n \[dq], { \[dq]t\[dq]: \[dq]body\[dq], \[dq]c\[dq]: [ \[dq]\[rs]n \[dq], { \[dq]comment\[dq]: \[dq] CDATA blocks do not require escaping \[dq] }, \[dq]\[rs]n \[dq], { \[dq]cdata\[dq]: \[dq]Hello & goodbye!\[dq] }, { \[dq]t\[dq]: \[dq]br\[dq] }, \[dq]\[rs]n \[dq] ] }, \[dq]\[rs]n\[dq] ] } .EE .PP The output contains several values consisting only of whitespace, such as \f[B]\f[CB]\[dq]\[rs]n \[dq]\f[B]\f[R]. These are conserved by jaq because XML is a whitespace\-sensitive format. .SS CSV / TSV \c .UR https://www.rfc-editor.org/rfc/rfc4180 CSV .UE \c (Comma\-Separated Values) and TSV (Tabulator\-Separated Values) are tabular data formats. A CSV/TSV table consists of rows of fields. Rows are separated by newlines. Fields are separated by commas in CSV and tabs in TSV. .PP jaq interprets each row as an array of values: .IP .EX $ printf \[dq]a,b\[rs]n1,2\[rs]n3,4\[dq] | jaq \-c \-\-from csv [\[dq]a\[dq],\[dq]b\[dq]] [1,2] [3,4] $ printf \[dq]a,b\[rs]n1,2\[rs]n3,4\[dq] | jaq \-c \-\-from csv \-\-slurp [[\[dq]a\[dq],\[dq]b\[dq]],[1,2],[3,4]] .EE .PP When writing tables using \f[B]\f[CB]\-\-to\f[B]\f[R], jaq prints the raw output of the filter \f[B]\f[CB]tocsv\f[B]\f[R] / \f[B]\f[CB]totsv\f[B]\f[R]: .IP .EX $ jaq \-n \[aq][\[dq]a\[dq],\[dq]b\[dq]], [1,2], [3,4]\[aq] \-\-to csv \[dq]a\[dq],\[dq]b\[dq] 1,2 3,4 $ jaq \-n \[aq][\[dq]a\[dq],\[dq]b\[dq]], [1,2], [3,4] | \[at]csv\[aq] \-\-raw\-output \[dq]a\[dq],\[dq]b\[dq] 1,2 3,4 .EE .SS Headers jaq currently does not provide any special handling for table headers, where the first row of a table contains field names. However, there are a few filters in \f[B]\f[CB]examples/table.jq\f[B]\f[R] that aim to simplify handling of tables with headers. If you find these filters useful or have a problem with them, please \c .UR https://github.com/01mf02/jaq/issues/418 leave your feedback .UE \c \ to help me decide whether to integrate them into jaq\[cq]s standard library. Let us see their usage. .PP For example, let us look at \c .UR https://en.wikipedia.org/wiki/Ferris_Bueller%27s_Day_Off Ferris Bueller .UE \c \[cq]s student record: .IP .EX $ cat examples/ferris.csv ID,Name,Home phone,Days absent 38\-106,\[dq]Bueller, Ferris\[dq],555\-6452,9 .EE .PP Hmmm, this is a bit hard to read, and Edward R. Rooney, Dean of Students, is a busy man. Let us help him out a bit: .IP .EX $ jaq \-L examples \[aq]include \[dq]table\[dq]; from_table\[aq] \-s examples/ferris.csv { \[dq]ID\[dq]: \[dq]38\-106\[dq], \[dq]Name\[dq]: \[dq]Bueller, Ferris\[dq], \[dq]Home phone\[dq]: \[dq]555\-6452\[dq], \[dq]Days absent\[dq]: 9 } .EE .PP Ah, much better. So what does Edward R. Rooney have to say about Ferris to Ferris\[cq]s mom? .RS .PP \[lq]So far this semester, he has been absent nine times.\[rq] \[em] \[lq]Nine times?\[rq] \[em] \[lq]Nine times.\[rq] \[em] \[lq]I don\[cq]t remember him being sick nine times.\[rq] \[em] \[lq]That\[cq]s probably because he wasn\[cq]t sick. He was skipping school. Wake up and smell the coffee, Mrs. Bueller. It\[cq]s a fool\[cq]s paradise. He\[cq]s just leading you down the primrose path.\[rq] \[em] \[lq]I can\[cq]t believe it.\[rq] \[em] \[lq]I got it right here in front of me. He has missed nine days.\[rq] .RE .PP Now it\[cq]s time for Ferris to shine: .IP .EX $ jaq \-L examples \[aq]include \[dq]table\[dq]; from_table | .[\[dq]Days absent\[dq]] \-= 7\[aq] \-s examples/ferris.csv { \[dq]ID\[dq]: \[dq]38\-106\[dq], \[dq]Name\[dq]: \[dq]Bueller, Ferris\[dq], \[dq]Home phone\[dq]: \[dq]555\-6452\[dq], \[dq]Days absent\[dq]: 2 } .EE .RS .PP \[lq]Grace! GRACE!!!\[rq] .RE .PP Next, let\[cq]s have a look at Ferris\[cq]s courses: .IP .EX $ cat examples/ferris\-courses.tsv Perds Days Course Teacher Rm Grade 1 Grade 2 Grade 3 Grade EX 01\-04 MTWF Eng Comp Hollndr 221 B+ A 05\-08 MWTF Calculus McMurry 309 B A\- 09\-10 TWTF Chemistry Gunner 260 A\- A 11\-13 All Lunch Caf 14\-19 MTWF Gym Carlyle 127 B+ A\- 23\-25 TWTF Computr Sc Cohen 114 A\- A 26\-29 MWTF Utpian Scy Jardin 241 A A 30\-32 MTWF Euro Hist Rice 334 B+ B+ .EE .PP Let\[cq]s see \&... in which courses did Ferris get a B+ as first grade? Anyone? Anyone? .IP .EX $ jaq \-L examples \[aq]include \[dq]table\[dq]; with_table(map(select(.[\[dq]Grade 1\[dq]] == \[dq]B+\[dq])))\[aq] \[rs] \-s examples/ferris\-courses.tsv \-\-to tsv Perds Days Course Teacher Rm Grade 1 Grade 2 Grade 3 Grade EX 01\-04 MTWF Eng Comp Hollndr 221 B+ A 14\-19 MTWF Gym Carlyle 127 B+ A\- 30\-32 MTWF Euro Hist Rice 334 B+ B+ .EE .PP Yeah, Ferris \&... you still got a bit of work ahead of you on the database. .PP So far, we slurped in all tables before processing them, using \f[B]\f[CB]\-s\f[B]\f[R]. This can be wasteful, especially when processing large tables, because this reads the whole table into memory. We can also read tables row\-by\-row: One useful pattern there is to use \f[B]\f[CB]inputs\f[B]\f[R] \f[B]without\f[R] the habitual \f[B]\f[CB]\-n\f[B]\f[R] option. That way, the first row (= header) becomes the filter input, and the remaining rows can then be retrieved with \f[B]\f[CB]inputs\f[B]\f[R]. Putting this together, we can rewrite the previous example: .IP .EX $ jaq \-L examples \[aq]include \[dq]table\[dq]; ., . as $header | from_row(inputs) | select(.[\[dq]Grade 1\[dq]] == \[dq]B+\[dq]) | to_row($header)\[aq] \[rs] examples/ferris\-courses.tsv \-\-to tsv Perds Days Course Teacher Rm Grade 1 Grade 2 Grade 3 Grade EX 01\-04 MTWF Eng Comp Hollndr 221 B+ A 14\-19 MTWF Gym Carlyle 127 B+ A\- 30\-32 MTWF Euro Hist Rice 334 B+ B+ .EE .PP This concludes our little Ferris Bueller arc. If you do not know the film yet, I greatly recommend you to change that. And remember: \[lq]Life moves pretty fast. If you don\[cq]t stop and look around once in a while, you could miss it.\[rq] .SH EXAMPLES The following examples should give an impression of what jaq can currently do. You should obtain the same outputs by replacing jaq with jq. .PP Access a field: .IP .EX $ echo \[aq]{\[dq]a\[dq]: 1, \[dq]b\[dq]: 2}\[aq] | jaq \[aq].a\[aq] 1 .EE .PP Add values: .IP .EX $ echo \[aq]{\[dq]a\[dq]: 1, \[dq]b\[dq]: 2}\[aq] | jaq \[aq]add\[aq] 3 .EE .PP Construct an array from an object in two ways and show that they are equal: .IP .EX $ echo \[aq]{\[dq]a\[dq]: 1, \[dq]b\[dq]: 2}\[aq] | jaq \[aq][.a, .b] == [.[]]\[aq] true .EE .PP Apply a filter to all elements of an array and filter the results: .IP .EX $ echo \[aq][0, 1, 2, 3]\[aq] | jaq \-c \[aq]map(.*2) | [.[] | select(. < 5)]\[aq] [0,2,4] .EE .PP Read (slurp) input values into an array and get the average of its elements: .IP .EX $ echo \[aq]1 2 3 4\[aq] | jaq \-s \[aq]add / length\[aq] 2.5 .EE .PP Repeatedly apply a filter to itself and output the intermediate results: .IP .EX $ echo \[aq]0\[aq] | jaq \-c \[aq][recurse(.+1; . < 3)]\[aq] [0,1,2] .EE .PP Lazily fold over inputs and output intermediate results: .IP .EX $ seq 5 | jaq \-n \[aq]foreach inputs as $x (0; . + $x)\[aq] 1 3 6 10 15 .EE .SS LEWIS\[cq]S PUZZLE The following puzzle was communicated to me at a workshop by a certain Mr. Lewis, where I solved it together with him in jq. It goes as follows: .PP We have a sequence of strings: .IP .EX X XYZX XYZXABXYZX .EE .PP For example, the 4th letter of the 2nd string (always counting from zero) is `A'. What is the 10244th letter of the 30th string? .PP First, let us understand how this sequence is built. To get the next sequence of letters, we take the previous sequence, concatenate it with the next two letters in the alphabet, then concatenate it with the previous sequence again. .PP If we take numbers instead of letters, we can write this down as: .IP .EX X(0 ) = 0 X(N+1) = X(N) (m+1) (m+2) X(N), where m is the largest element in X(N) .EE .PP We can now write the strings as JSON arrays. The first array is \f[B]\f[CB][0]\f[B]\f[R], and we can produce each following array by a filter \f[B]\f[CB]next\f[B]\f[R], on which we \f[B]\f[CB]recurse\f[B]\f[R] to get an sequence of all arrays. .IP .EX def next: . + [max + (1, 2)] + .; [0] | limit(3; recurse(next)) \-\-> [0] [0,1,2,0] [0,1,2,0,3,4,0,1,2,0] .EE .PP However, this does not scale well \[em] getting to the 30th array will take a very long time, because the arrays grow exponentially. Feel free to try it, but watch out not to get your RAM eaten. :) (I recommend monitoring RAM usage when doing this experiment. Otherwise, you may very well crash your computer due to memory exhaustion. Guess how I know?) .PP To solve this problem, we can exploit jq\[cq]s sharing. Note that each array contains a portion to the left that is equal to a portion on the right; for example, \f[B]\f[CB][0, 1, 2, 0]\f[B]\f[R] in the 2nd array. We can therefore choose a slightly different array representation that allows us to \f[B]share\f[R] all the equal parts of the array, just by inserting the previous arrays into a new array. .IP .EX def next: [., .[2] + (1,2), .]; [0] | limit(3; recurse(next)) \-\-> [0] [[0],1,2,[0]] [[[0],1,2,[0]],3,4,[[0],1,2,[0]]] .EE .PP In all arrays produced by \f[B]\f[CB]next\f[B]\f[R], the first and the last elements are now shared, meaning that they are stored only a single time in memory. That allows us to store exponentially large data in linear memory, thus cracking the puzzle. .PP To get the largest number of the previous array, we used the fact that the 2nd element of each array contains the largest number in the array. For example, the 2nd element of the 1st array is \f[B]\f[CB]2\f[B]\f[R], and the 2nd element of the 2nd array is \f[B]\f[CB]4\f[B]\f[R]. (For the 0th array, the 2nd element is \f[B]\f[CB]null\f[B]\f[R], but the maximum element of that array is \f[B]\f[CB]0\f[B]\f[R]. However, \f[B]\f[CB]null\f[B]\f[R] is interpreted by addition just like \f[B]\f[CB]0\f[B]\f[R], so this difference does not matter to us.) We can therefore get the two next largest numbers very elegantly via \f[B]\f[CB].[2] + (1, 2)\f[B]\f[R]. .PP We can now get the numbers of any such array with \f[B]\f[CB].. | numbers\f[B]\f[R]. For example, the numbers of the 2nd array are: .IP .EX [[[0],1,2,[0]],3,4,[[0],1,2,[0]]] | .. | numbers \-\-> 0 1 2 0 3 4 0 1 2 0 .EE .PP Putting all this together, we get our solution via: .IP .EX def next: [., .[2] + (1,2), .]; [0] | nth(30; recurse(next)) | nth(10244; .. | numbers) \-\-> 2 .EE .PP This now runs almost instantaneously, and gives us the answer \f[B]\f[CB]2\f[B]\f[R]. Going back to the original puzzle, because \f[B]\f[CB]X = 0\f[B]\f[R], \f[B]\f[CB]Y = 1\f[B]\f[R], \f[B]\f[CB]Z = 2\f[B]\f[R], the final answer to the puzzle is \f[B]\f[CB]Z\f[B]\f[R]. .SS HTML SCRAPING I wanted to extract the \c .UR https://www.rfc-editor.org/rfc/rfc8949.html#name-examples-of-encoded-cbor-da list of examples from the CBOR specification .UE \c , in order to create a test suite for the CBOR encoder/decoder in jaq. For this, I copied the relevant section from the HTML source code and pasted it into \f[B]\f[CB]examples/cbor\-examples.xhtml\f[B]\f[R]. The interesting parts look like this: .IP .EX <\f[B]table\f[R]> <\f[B]tbody\f[R]> <\f[B]tr\f[R]> <\f[B]td\f[R] class=\[dq]text\-left\[dq] rowspan=\[dq]1\[dq] colspan=\[dq]1\[dq]>25</\f[B]td\f[R]> <\f[B]td\f[R] class=\[dq]text\-left\[dq] rowspan=\[dq]1\[dq] colspan=\[dq]1\[dq]>0x1819</\f[B]td\f[R]> </\f[B]tr\f[R]> <\f[B]tr\f[R]> <\f[B]td\f[R] class=\[dq]text\-left\[dq] rowspan=\[dq]1\[dq] colspan=\[dq]1\[dq]>100</\f[B]td\f[R]> <\f[B]td\f[R] class=\[dq]text\-left\[dq] rowspan=\[dq]1\[dq] colspan=\[dq]1\[dq]>0x1864</\f[B]td\f[R]> </\f[B]tr\f[R]> </\f[B]tbody\f[R]> </\f[B]table\f[R]> .EE .PP Here, I was interested in the pairs \f[B]\f[CB]25\f[B]\f[R] / \f[B]\f[CB]0x1819\f[B]\f[R] and \f[B]\f[CB]100\f[B]\f[R] / \f[B]\f[CB]0x1864\f[B]\f[R], meaning that the number \f[B]\f[CB]25\f[B]\f[R] is encoded in CBOR as \f[B]\f[CB]0x1819\f[B]\f[R]. .PP Finally, I came up with a jq program to extract this data. It consists of the following tasks: .IP "1." 3 Select all \f[B]\f[CB]<tr>\f[B]\f[R] elements with \f[B]\f[CB].. | select(.t? == \[dq]tr\[dq])\f[B]\f[R]. .IP "2." 3 Get its children with \f[B]\f[CB].c\f[B]\f[R]. .IP "3." 3 Iterate over the children with \f[B]\f[CB].[]\f[B]\f[R] and get their children with \f[B]\f[CB].c?[]\f[B]\f[R]. .PP (I use \f[B]\f[CB].c?\f[B]\f[R] here instead of \f[B]\f[CB].c\f[B]\f[R] because XML is whitespace\-sensitive, so in \f[B]\f[CB]<tr> <td></td> </tr>\f[B]\f[R], the \f[B]\f[CB]<tr>\f[B]\f[R] element has actually three children, namely two space strings \f[B]\f[CB]\[dq] \[dq]\f[B]\f[R] and the \f[B]\f[CB]<td>\f[B]\f[R] element. Indexing the strings with \f[B]\f[CB].c\f[B]\f[R] yields an error, whereas indexing them with \f[B]\f[CB].c?\f[B]\f[R] just yields nothing, allowing us to ignore the space.) .PP We can see the effects of that on a slightly simplified version of the HTML: .IP .EX \[dq]<table>\[dq] + \[dq]<tr> <td>25</td> <td>0x1819</td> </tr>\[dq] + \[dq]<tr> <td>100</td> <td>0x1864</td> </tr>\[dq] + \[dq]</table>\[dq] | fromxml | .. | select(.t? == \[dq]tr\[dq]).c | [.[].c?[]] \-\-> [ \[dq]25\[dq], \[dq]0x1819\[dq]] [\[dq]100\[dq], \[dq]0x1864\[dq]] .EE .PP To run this via the CLI: .IP .EX jaq \[aq].. | select(.t? == \[dq]tr\[dq]).c | [.[].c?[]]\[aq] examples/cbor\-examples.xhtml .EE .PP We can create a series of tests as follows: .IP .EX jaq \[aq].. | select(.t? == \[dq]tr\[dq]).c | [.[].c?[]] | \[at]json \[dq]jc(\[rs](.[0]), \[rs](.[1][2:]));\[dq]\[aq] \[rs] examples/cbor\-examples.xhtml \-r .EE .PP I used exactly this command to create a draft for jaq\[cq]s CBOR parsing test suite. .SH AUTHOR Michael Färber .SH SEE ALSO \f[I]jq\f[R](1)