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:
cat services.txt | fx -r 'x.toUpperCase()'Input (services.txt, used in the next sections too):
api-gateway
auth-service
# disabled
billing-worker
search-indexerThis 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:
cat services.txt | fx -rsOutput:
[
"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:
cat services.txt | fx -r 'x === "" || x.startsWith("#") ? skip : x'With -rs, use .filter(), map with @, and print one item per line with list:
cat services.txt | fx -rs '.filter(x => x && !x.startsWith("#"))' '@`https://${x}.internal/health`' listOutput:
https://api-gateway.internal/health
https://auth-service.internal/health
https://billing-worker.internal/health
https://search-indexer.internal/healthConvert 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:
cat .env | fx -rs 'x => Object.fromEntries(x.map(l => l.split(/=(.*)/)))'Output:
{
"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:
ls -l | fx -rs '.slice(1)' '@.trim().split(/\s+/)' '@({name: x.slice(8).join(" "), size: +x[4], dir: x[0][0] === "d"})'Output:
[
{ "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:
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:
[
{
"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:
df -h | fx -rs '.slice(1)' '@.split(/\s+/)' '@({mount: x[5], use: parseInt(x[4])})' '?.use > 80'Output:
[
{ "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:
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,251Output:
[
{
"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:
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:
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:
[
{ "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:
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.