1FX(1)                            User Commands                           FX(1)
2
3
4

NAME

6       fx - command-line JSON processing tool
7

SYNOPSIS

9       fx [code ...]
10
11       fx  can  work  in two modes: cli and interactive.  To start interactive
12       mode pipe any JSON into fx:
13           $ curl ... | fx
14       Or you can pass a filename as the first parameter:
15           $ fx my.json
16       If any argument was passed, fx will apply it and prints to stdout.
17

DESCRIPTION

19       Start interactive mode without passing any arguments.
20           $ curl ... | fx
21       Or by passing filename as first argument.
22           $ fx data.json
23       Pass a few JSON files.
24           $ cat foo.json bar.json baz.json | fx .message
25       Use full power of JavaScript.
26           $ curl ... | fx '.filter(x => x.startsWith("a"))'
27       Access all lodash (or ramda, etc) methods by using .fxrc file.
28           $ curl ... |
29           > fx '_.groupBy("commit.committer.name")' '_.mapValues(_.size)'
30       Update JSON using spread operator.
31           $ echo '{"count": 0}' | fx '{...this, count: 1}'
32           {
33             "count": 1
34           }
35       Extract values from maps.
36           $ fx commits.json | fx .[].author.name
37       Print formatted JSON to stdout.
38           $ curl ... | fx .
39       Pipe JSON logs stream into fx.
40           $ kubectl logs ... -f | fx .message
41       And try this:
42           $ fx --life
43
44   USAGE
45       ANONYMOUS FUNCTION
46              Use an anonymous function as reducer which gets  JSON  and  pro‐
47              cesses it:
48                  $ echo '{"foo": [{"bar": "value"}]}' | fx 'x => x.foo[0].bar'
49                  value
50
51       BINDING
52              If  you don't pass anonymous function param => ..., code will be
53              automatically transformed into anonymous function.  And you  can
54              get access to JSON by this keyword:
55                  $ echo '{"foo": [{"bar": "value"}]}' | fx 'this.foo[0].bar'
56                  value
57
58       DOT    It is possible to omit this keyword:
59                  $ echo '{"foo": [{"bar": "value"}]}' | fx .foo[0].bar
60                  value
61              If  a single dot is passed, the input JSON will be formatted but
62              otherwise unaltered:
63                  $ echo '{"foo": "bar"}' | fx .
64                  {
65                    "foo": "bar"
66                  }
67
68       MAP    One of the frequent operations is mapping some  function  on  an
69              array.  For example, to extract some values.
70                  [
71                    {
72                      "author": {
73                        "name": "antonmedv"
74                      }
75                    },
76                    {...},
77                    ...
78                  ]
79              And  we  want  to collect names of each object in the array.  We
80              can do this by mapping anonymous function:
81                  $ cat ... | fx '.map(x => x.author.name)'
82              Or we can do the same by using jq(1)-like syntax:
83                  $ cat ... | fx .[].author.name
84                  [
85                    "antonmedv",
86                    ...
87                  ]
88              Note what [] can be applied to map object values.
89                  $ echo '{"foo": 1, "bar": 2}' | fx .[]
90                  [1, 2]
91
92       CHAINING
93              You can pass any number  of  anonymous  functions  for  reducing
94              JSON:
95                  $ echo '{"foo": [{"bar": "value"}]}' |
96                  > fx 'x => x.foo' 'this[0]' 'this.bar'
97                  value
98
99       UPDATING
100              You can update existing JSON using the spread operator:
101                  $ echo '{"count": 0}' | fx '{...this, count: 1}'
102                  {
103                    "count": 1
104                  }
105
106       EDIT-IN-PLACE
107              fx  provides a function save which will save everything in place
108              and return saved object.  This function can be  only  used  with
109              filename as first argument to fx command.
110
111              Usage:
112                  $ fx data.json '{...this, count: this.count+1}' save .count
113
114       USING PACKAGES
115              Use any npm package by installing it globally:
116                  $ npm install -g lodash
117                  $ cat package.json |
118                  > fx 'require("lodash").keys(this.dependencies)'
119
120   FORMATTING
121       If  you  need output other than JSON (for example arguments for xargs),
122       do not return anything from the reducer.  undefined  value  is  printed
123       into stderr by default.
124           echo '[]' | fx 'void 0'
125           undefined
126
127           echo '[1,2,3]' |
128             fx 'this.forEach(x => console.log(+x))' 2>/dev/null |
129             xargs echo
130           1 2 3
131
132   STREAMING MODE
133       fx supports line-delimited JSON and concatenated JSON streaming.
134           $ kubectl logs ... | fx .message
135       Note  what  is object lacks message field, undefined will be printed to
136       stderr.  This is useful to see if you are skipping some  objects.   But
137       if you want to hide them, redirect stderr to /dev/null.
138
139       FILTERING
140              Sometimes  it is necessary to omit some messages in JSON stream,
141              or select only specified log messages.  For this purpose, fx has
142              special  helpers  select/filter,  pass  function  into it to se‐
143              lect/filter JSON messages.
144                  $ kubectl logs ... |
145                  > fx 'select(x => x.status == 500)' .message
146
147                  $ kubectl logs ... |
148                  > fx 'filter(x => x.status < 499)' .message
149
150              If filter/select overridden in .fxrc you still  able  to  access
151              them with prefix: std.select(cb) or std.filter(cd)
152

FILES

154   USING .fxrc
155       Create  .fxrc  in  $HOME  directory, and require any packages or define
156       global functions.
157
158       For example, access all lodash methods without _ prefix.  Put  in  your
159       .fxrc file:
160           Object.assign(global, require('lodash/fp'))
161       And  now you will be able to call all lodash methods.  For example, see
162       who's been committing to react recently:
163           curl 'https://api.github.com/repos/facebook/react/commits?per_page=100' |
164             fx 'groupBy("commit.author.name")' 'mapValues(size)' toPairs \
165                 'sortBy(1)' reverse 'take(10)' fromPairs
166       See the ENVIRONMENT section.
167
168       QUERY LANGUAGE
169              If  you  want  to  use  query  language,  for  example   jsonata
170https://jsonata.org/⟩ you can use helper function like this:
171                  global.jsonata = expr => require('jsonata')(expr).evaluate
172              And use it like this:
173                  curl ... |
174                    fx 'jsonata("$sum(Order.Product.(Price * Quantity))")'
175              Instead you can create next alias in .bashrc file:
176                  alias jsonata='FX_APPLY=jsonata fx'
177              And  now  all  code  arguments to jsonata will be passed through
178              jsonata helper.  And now you can use it like this:
179                  curl ... | jsonata '$sum(Order.Product.(Price * Quantity))'
180
181   INTERACTIVE MODE
182       Click on fields to expand or collapse JSON tree,  use  mouse  wheel  to
183       scroll view.
184
185       Next commands available in interactive mode:
186
187       ┌───────────────────┬──────────────────────────────────────────────┐
188KeyCommand
189       ├───────────────────┼──────────────────────────────────────────────┤
190q or Esc or Ctrl+c │ Exit                                         │
191       ├───────────────────┼──────────────────────────────────────────────┤
192up or k            │ Move cursor up                               │
193       ├───────────────────┼──────────────────────────────────────────────┤
194left or h          │ Collapse                                     │
195       ├───────────────────┼──────────────────────────────────────────────┤
196right or l         │ Expand                                       │
197       ├───────────────────┼──────────────────────────────────────────────┤
198Shift+right or L   │ Expand all under cursor                      │
199       ├───────────────────┼──────────────────────────────────────────────┤
200Shift+left or K    │ Collapse all under cursor                    │
201       ├───────────────────┼──────────────────────────────────────────────┤
202e                  │ Expand all                                   │
203       ├───────────────────┼──────────────────────────────────────────────┤
204E                  │ Collapse all                                 │
205       ├───────────────────┼──────────────────────────────────────────────┤
206g                  │ Scroll to top                                │
207       ├───────────────────┼──────────────────────────────────────────────┤
208G                  │ Scroll to bottom                             │
209       ├───────────────────┼──────────────────────────────────────────────┤
210.                  │ Edit filter                                  │
211       ├───────────────────┼──────────────────────────────────────────────┤
212/                  │ Search                                       │
213       ├───────────────────┼──────────────────────────────────────────────┤
214n                  │ Find next                                    │
215       ├───────────────────┼──────────────────────────────────────────────┤
216p                  │ Exit and print JSON to stdout                │
217       ├───────────────────┼──────────────────────────────────────────────┤
218P                  │ Exit and print fully expanded JSON to stdout │
219       └───────────────────┴──────────────────────────────────────────────┘
220       These commands are available when editing the filter:
221
222       ┌────────┬─────────────────────┐
223KeyCommand
224       ├────────┼─────────────────────┤
225Enter   │ Apply filter        │
226       ├────────┼─────────────────────┤
227Ctrl+u  │ Clear filter        │
228       ├────────┼─────────────────────┤
229Ctrl+w  │ Delete last part    │
230       ├────────┼─────────────────────┤
231up/down │ Select autocomplete │
232       └────────┴─────────────────────┘
233       SEARCHING
234              Press  /  and  type  regexp  pattern  to search in current JSON.
235              Search work with currently applied filter.
236
237              Examples of pattern and corresponding regexp:
238
239              ┌───────────┬───────────┐
240PatternRegExp
241              ├───────────┼───────────┤
242/apple     /apple/ig 
243              ├───────────┼───────────┤
244/apple/+u  /apple/   
245              ├───────────┼───────────┤
246/apple/u+w /apple/u  
247              ├───────────┼───────────┤
248\w+        /\w+/ig   
249              └───────────┴───────────┘
250       SELECTING TEXT
251              You may found what you can't just select text in  fx.   This  is
252              due  the  fact that all mouse events redirected to stdin.  To be
253              able select again you need instruct your terminal not to do  it.
254              This can be done by holding special keys while selecting:
255
256              ┌─────────────┬───────────────┐
257KeyTerminal
258              ├─────────────┼───────────────┤
259Option+Mouse │ iTerm2, Hyper │
260              ├─────────────┼───────────────┤
261Fn+Mouse     │ Terminal.app  │
262              ├─────────────┼───────────────┤
263Shift+Mouse  │ Linux         │
264              └─────────────┴───────────────┘
265              Note  what  you  can press p/P to print everything to stdout and
266              select if there.
267
268   MEMORY USAGE
269       You may find that sometimes, on really big JSON files, fx prints an er‐
270       ror message like this:
271           FATAL ERROR: JavaScript heap out of memory
272       V8 limits memory usage to around 2 GB by default.  You can increase the
273       limit by putting this line in your .profile:
274           export NODE_OPTIONS='--max-old-space-size=8192'
275

ENVIRONMENT

277       To be able require global modules make sure you have correct  NODE_PATH
278       env variable.
279

EXAMPLES

281   BASIC EXAMPLES
282       $ echo '{"key": "value"}' | fx 'x => x.key'
283       value
284
285       $ echo '{"key": "value"}' | fx .key
286       value
287
288       $ echo '[1,2,3]' | fx 'this.map(x => x * 2)'
289       [2, 4, 6]
290
291       $ echo '{"items": ["one", "two"]}' | fx 'this.items' 'this[1]'
292       two
293
294       $ echo '{"count": 0}' | fx '{...this, count: 1}'
295       {"count": 1}
296
297       $ echo '{"foo": 1, "bar": 2}' | fx ?
298       ["foo", "bar"]
299
300   OTHER EXAMPLES
301       Convert object to array:
302           $ cat package.json | fx 'Object.keys(this.dependencies)'
303       Or by two functions:
304           $ cat package.json | fx .dependencies Object.keys
305       By  the  way, fx has shortcut for Object.keys.  Previous example can be
306       rewritten as:
307           $ cat package.json | fx .dependencies ?
308

SEE ALSO

310       jq(1)
311
312
313
314                                 February 2021                           FX(1)
Impressum