Skip to content

Processing Plain Text and Command Output With fx --raw ​

fx can process plain text too, not just JSON. With -r (--raw), each input line becomes a JavaScript string, so you can filter, transform, and parse the output of ls, ps, df, env, or any log file with JavaScript one-liners instead of awk. Install fx first.

Process Text Line by Line With JavaScript ​

With -r, fx runs the expression once per line, and x is that line as a string:

bash
cat services.txt | fx -r 'x.toUpperCase()'

Input (services.txt, used in the next sections too):

api-gateway
auth-service
# disabled
billing-worker

search-indexer

This prints each line in upper case: API-GATEWAY, AUTH-SERVICE, and so on. String results print without quotes, so you can pipe them into other commands. Objects and arrays print as JSON.

Read All Lines Into an Array ​

Add -s (-rs) to collect every line into one array of strings. Use it when you need the whole input at once, for example to count, sort, or skip a header:

bash
cat services.txt | fx -rs

Output:

json
[
  "api-gateway",
  "auth-service",
  "# disabled",
  "billing-worker",
  "",
  "search-indexer"
]

Filter and Transform Lines ​

In per-line mode, return the skip symbol to drop a line. This prints the four service names, without the blank line and the comment:

bash
cat services.txt | fx -r 'x === "" || x.startsWith("#") ? skip : x'

With -rs, use .filter(), map with @, and print one item per line with list:

bash
cat services.txt | fx -rs '.filter(x => x && !x.startsWith("#"))' '@`https://${x}.internal/health`' list

Output:

https://api-gateway.internal/health
https://auth-service.internal/health
https://billing-worker.internal/health
https://search-indexer.internal/health

Convert key=value Output (env, .env) to JSON ​

Split each line on the first = and build an object. The regex /=(.*)/ keeps any further = in the value. Pipe env the same way, and add '.DATABASE_URL' as another argument to pick one key:

bash
cat .env | fx -rs 'x => Object.fromEntries(x.map(l => l.split(/=(.*)/)))'

Output:

json
{
  "HOME": "/home/alice",
  "SHELL": "/bin/zsh",
  "LANG": "en_US.UTF-8",
  "DATABASE_URL": "postgres://db:5432/app?sslmode=require"
}

Convert ls -l and ps Output to JSON ​

Skip the total line, split each row on whitespace, and pick columns by index. + turns a column into a number, and x.slice(8).join(" ") keeps file names that contain spaces:

bash
ls -l | fx -rs '.slice(1)' '@.trim().split(/\s+/)' '@({name: x.slice(8).join(" "), size: +x[4], dir: x[0][0] === "d"})'

Output:

json
[
  { "name": "README.md", "size": 1832, "dir": false },
  { "name": "app.js", "size": 48213, "dir": false },
  { "name": "src", "size": 160, "dir": true },
  { "name": "package.json", "size": 512, "dir": false }
]

Use the same pattern for ps. The command can contain spaces, so join everything after the fourth column:

bash
ps -eo pid,user,%cpu,%mem,args | fx -rs '.slice(1)' '@.trim().split(/\s+/)' \
  '@({pid: +x[0], user: x[1], cpu: +x[2], command: x.slice(4).join(" ")})' '?.cpu > 10'

Output:

json
[
  {
    "pid": 1044,
    "user": "alice",
    "cpu": 37.5,
    "command": "node server.js --port 3000"
  }
]

This finds disks that are more than 80% full in df -h output:

bash
df -h | fx -rs '.slice(1)' '@.split(/\s+/)' '@({mount: x[5], use: parseInt(x[4])})' '?.use > 80'

Output:

json
[
  { "mount": "/data", "use": 92 }
]

Parse a CSV Log Into JSON Records ​

Split each line on commas, name the fields, and convert the numeric ones. This simple split doesn't handle quoted fields that contain commas:

bash
cat access.log | fx -rs '@.split(",")' '@({time: x[0], method: x[1], path: x[2], status: +x[3], ms: +x[4]})' '?.status >= 500'

Input:

2026-09-25T10:00:01Z,GET,/api/users,200,34
2026-09-25T10:00:02Z,POST,/api/orders,201,120
2026-09-25T10:00:04Z,GET,/api/orders/42,404,8
2026-09-25T10:00:07Z,DELETE,/api/users/7,500,251

Output:

json
[
  {
    "time": "2026-09-25T10:00:07Z",
    "method": "DELETE",
    "path": "/api/users/7",
    "status": 500,
    "ms": 251
  }
]

To sum a column, like awk's {s += $5} END {print s}, use reduce. This prints 413, the total response time:

bash
cat access.log | fx -rs '@.split(",")' '.reduce((sum, c) => sum + +c[4], 0)'

Count Word Frequency in a Text File ​

Extract the words, group them with groupBy, and sort by count:

bash
cat notes.txt | fx -rs '.join(" ").toLowerCase().match(/[a-z]+/g)' 'groupBy(w => w)' \
  'x => Object.entries(x).map(([word, ws]) => ({word, count: ws.length}))' 'sortBy(x => -x.count)' '.slice(0, 3)'

Input:

The quick brown fox jumps over the lazy dog.
The dog sleeps. The fox runs!
A fox is quick.

Output:

json
[
  { "word": "the", "count": 4 },
  { "word": "fox", "count": 3 },
  { "word": "quick", "count": 2 }
]

JSON-Encode a Text File for a Request Body ​

Join the lines back into one string and wrap it with JSON.stringify, which escapes the quotes and newlines:

bash
cat query.sql | fx -rs 'JSON.stringify({query: x.join("\n"), limit: 10})'

Input:

SELECT id, email
FROM users
WHERE name = "O'Brien";

Output:

{"query":"SELECT id, email\nFROM users\nWHERE name = \"O'Brien\";","limit":10}

Pipe the result to curl --data-binary @- to send it. -rs splits the input into lines, so the trailing newline at the end of the file is dropped.

See Also ​