Overview
Purpose
jc (JSON Convert) is a command-line tool that converts the output
of standard Linux/Unix commands into structured JSON. Instead of writing custom
awk or sed parsers for ps, df, netstat,
ifconfig, ls, and dozens of other commands, jc parses
them for you and outputs clean, consistent JSON that can be piped directly into
jq, Python, or any tool that reads JSON.
Basic Syntax
COMMAND | jc --PARSER — pipe mode (most common)
jc COMMAND [ARGS] — magic syntax mode (jc runs the command)
jc --PARSER < file — parse from a saved file
Why This Matters
Unix command output is human-readable text. Scripts that consume it have to
parse it — and parsers break when column widths shift, when a hostname is longer
than expected, or when output format changes between OS versions. jc absorbs that
fragility. Once output is JSON, jq filters it reliably regardless of
formatting variations. Your scripts become shorter, more readable, and more robust.
Relationship to jq
jc and jq are natural partners. jc converts command
output into JSON. jq queries and transforms JSON. Together they replace most
one-off awk/sed parsing scripts. See the
jq reference page for the jq side of
the pipeline.
Installation
pip (recommended — any distro, always current)
pip3 install jc
# Verify
jc --version
jc --help | head -5
RHEL / CentOS / Fedora
# Fedora
dnf install jc
# RHEL 8/9 via EPEL
dnf install epel-release
dnf install jc
Debian / Ubuntu
apt install jc
List all supported parsers
# Full list — over 100 parsers
jc --list
# Search for a specific command
jc --list | grep ps
jc --list | grep net
Common Options
| Option | Description |
|---|---|
--PARSER |
Specify the parser: --ps, --df, --ls, etc. |
-p |
Pretty-print JSON output (human-readable with indentation) |
-q |
Quiet — suppress warning messages |
-r |
Raw output — return strings instead of converted types |
-u |
Unbuffered output — useful for streaming/live data |
--list |
List all available parsers |
--about |
Show jc version and info |
-a |
About parser — show details about a specific parser |
💡 Pretty-print vs. pipeline
Use -p when you want to read the output yourself.
Omit -p when piping to jq — jq handles its own
formatting and compact JSON is faster to parse.
10 Detailed Examples
# Basic conversion — pretty-printed for reading
ps aux | jc --ps -p
# Pipe into jq to extract just process names and PIDs
ps aux | jc --ps | jq '.[] | {pid, command}'
# Find all processes owned by a specific user
ps aux | jc --ps | jq '.[] | select(.user == "www-data") | {pid, command, cpu_percent}'
# Top 5 processes by CPU
ps aux | jc --ps | jq 'sort_by(.cpu_percent) | reverse | .[:5] | .[] | {pid, command, cpu_percent}'
What This Does:
Converts ps aux text output into a JSON array where each
process is an object with named fields: user, pid,
cpu_percent, mem_percent, command,
and more. No awk field-position parsing required — field names are stable
regardless of column width changes.
Sample Output (excerpt):
JSON OUTPUT# Convert df output to JSON
df -h | jc --df -p
# Find filesystems over 80% used
df | jc --df | jq '.[] | select(.use_percent > 80) | {filesystem, use_percent, mounted_on}'
# Just the mount point and available space
df -h | jc --df | jq '.[] | {mounted_on, available}'
# Alert if root filesystem over 90%
df | jc --df | jq '.[] | select(.mounted_on == "/" and .use_percent > 90) | "WARNING: root at \(.use_percent)%"'
What This Does:
Converts df output into JSON with numeric types for
use_percent, 1k_blocks, used, and
available. Because these are numbers in JSON (not strings),
jq can do numeric comparisons directly — no string-stripping of the
% sign required.
Practical Application:
Replace the classic df -h | awk '$5 > 80' one-liner with
a jc+jq pipeline that is easier to read, extend, and maintain.
# Parse ip address show output
ip addr | jc --ip-address -p
# Get just interface names and their IP addresses
ip addr | jc --ip-address | jq '.[] | {ifname, addr_info}'
# Find the IP of a specific interface
ip addr | jc --ip-address | jq '.[] | select(.ifname == "eth0") | .addr_info[].local'
# All interfaces that are UP
ip addr | jc --ip-address | jq '.[] | select(.flags[] == "UP") | .ifname'
# Parse ip route output
ip route | jc --ip-route -p
What This Does:
Parses the complex nested output of ip addr into structured
JSON with arrays for flags and address info. Extracting an IP address with
awk requires careful field counting that breaks on different interface types.
jc + jq selects by field name — robust against formatting differences.
Also Available:
--ip-route— parse routing table--ip-link— parse link layer info--ss— parse socket statistics (ss command)
# Who is currently logged in
who | jc --who -p
# Convert last output to JSON
last | jc --last -p
# Find all logins from a specific user
last | jc --last | jq '.[] | select(.user == "craig") | {user, hostname, started}'
# Find logins from outside the local network
last | jc --last | jq '.[] | select(.hostname | startswith("192.168") | not) | select(.hostname != "") | {user, hostname, started}'
# Count logins per user
last | jc --last | jq 'group_by(.user) | .[] | {user: .[0].user, count: length}' | jq -s 'sort_by(.count) | reverse'
What This Does:
Converts login history from last and current sessions from
who into structured JSON. Particularly useful for security
auditing — jq filters by hostname pattern to spot logins from unexpected
locations, a task that requires multi-step awk in traditional scripting.
SysAdmin Use Case:
Build a daily login audit report: pipe last through jc,
filter for off-hours or external logins with jq, format output for email
or a ticket.
# Convert /etc/passwd to JSON
cat /etc/passwd | jc --passwd -p
# Find all users with a real shell (not nologin or false)
cat /etc/passwd | jc --passwd | jq '.[] | select(.shell | test("nologin|false|sync") | not) | {username, uid, shell}'
# Find users with UID above 1000 (regular accounts)
cat /etc/passwd | jc --passwd | jq '.[] | select(.uid >= 1000) | {username, uid, home}'
# Convert /etc/group
cat /etc/group | jc --group -p
# Find which groups a user belongs to
cat /etc/group | jc --group | jq '.[] | select(.members[] == "craig") | .group_name'
What This Does:
Parses the colon-delimited passwd and group files into JSON with proper
field names. The members field in group output is a JSON array,
making membership queries trivial with jq's select and
array operations.
Practical Application:
User audits — find all accounts with login shells, accounts with unusual UIDs, or service accounts that have been granted shell access.
# System info
uname -a | jc --uname -p
# Uptime parsed
uptime | jc --uptime -p
# Block devices
lsblk | jc --lsblk -p
# Find all mounted ext4 filesystems
lsblk | jc --lsblk | jq '.[] | .. | objects | select(.fstype? == "ext4") | {name, size, mountpoint}'
# Combine uname and uptime into one object
echo "{\"system\": $(uname -a | jc --uname), \"uptime\": $(uptime | jc --uptime)}" | jq .
What This Does:
Converts system information commands into clean JSON. The last example shows a useful pattern: constructing a composite JSON object by combining multiple jc outputs inline. This is the foundation of an inventory or health-check script that produces structured output.
Inventory Script Pattern:
Collect uname, uptime, df, ip addr, and ps all through jc, combine into one JSON object, and ship it to a central collector. Structured, machine-readable, no custom parsing required on the receiving end.
# Parse known_hosts
cat ~/.ssh/known_hosts | jc --known-hosts-file -p
# List all hostnames in known_hosts
cat ~/.ssh/known_hosts | jc --known-hosts-file | jq '.[].hostnames[]'
# Parse authorized_keys
cat ~/.ssh/authorized_keys | jc --authorized-keys-file -p
# List all key comments (usually username@host)
cat ~/.ssh/authorized_keys | jc --authorized-keys-file | jq '.[].comment'
# Count keys by type
cat ~/.ssh/authorized_keys | jc --authorized-keys-file | jq 'group_by(.key_type) | .[] | {type: .[0].key_type, count: length}'
What This Does:
Parses SSH key files into structured JSON. Useful for security auditing — inventorying all authorized keys across a fleet, checking key types (flagging deprecated RSA-1024 or DSA keys), or verifying known_hosts entries programmatically.
SysAdmin Use Case:
Audit script: loop over all home directories, parse each
authorized_keys file through jc, collect into a single JSON
array, filter for old key types or keys without comments.
# jc runs the command and parses output in one step
jc ps aux -p
jc df -h -p
jc ls -la /etc -p
jc netstat -tlnp -p
jc who -p
jc last -p
# Chain directly into jq without an intermediate pipe
jc ps aux | jq '.[] | select(.cpu_percent > 10)'
jc df | jq '.[] | select(.use_percent > 80)'
What This Does:
In magic syntax mode, jc accepts the command and its arguments directly rather than reading from stdin. It runs the command internally and parses the output. The result is slightly shorter syntax for interactive use.
Pipe Mode vs Magic Mode:
- Pipe:
ps aux | jc --ps— explicit, works in scripts, composable - Magic:
jc ps aux— shorter at the terminal, less explicit - Pipe mode is preferred in scripts for clarity and reliability
# Parse crontab output
crontab -l | jc --crontab -p
# List all cron commands without the schedule
crontab -l | jc --crontab | jq '.schedule[].command'
# Parse crontab file directly
jc --crontab < /etc/cron.d/myjob -p
# Parse systemctl list-units
systemctl list-units | jc --systemctl -p
# Find all failed units
systemctl list-units | jc --systemctl | jq '.[] | select(.sub == "failed") | .unit'
# Find all active services
systemctl list-units --type=service | jc --systemctl | jq '.[] | select(.active == "active") | .unit'
What This Does:
Converts crontab and systemctl output into structured JSON. Parsing systemctl output with awk is notoriously fragile — unit names, states, and descriptions vary in width and content. jc gives you reliable field names regardless of output formatting.
Practical Application:
Health check script: parse systemctl list-units through jc,
filter for failed units with jq, send an alert if the array is non-empty.
#!/bin/bash
# health-report.sh — structured JSON system snapshot
# Requires: jc, jq
HOSTNAME=$(hostname)
TIMESTAMP=$(date -u +"%Y-%m-%dT%H:%M:%SZ")
jq -n \
--arg host "$HOSTNAME" \
--arg ts "$TIMESTAMP" \
--argjson uptime "$(uptime | jc --uptime)" \
--argjson disk "$(df | jc --df)" \
--argjson memory "$(free | jc --free)" \
--argjson top_procs "$(ps aux | jc --ps | jq 'sort_by(.cpu_percent) | reverse | .[:5]')" \
--argjson failed_units "$(systemctl list-units | jc --systemctl | jq '[.[] | select(.sub == \"failed\")]')" \
'{
host: $host,
timestamp: $ts,
uptime: $uptime,
disk: $disk,
memory: $memory,
top_processes: $top_procs,
failed_units: $failed_units
}'
What This Does:
Builds a complete structured system health report as a single JSON object. Each section (uptime, disk, memory, top processes, failed units) is collected through jc and assembled by jq into one document. The output can be saved to a file, shipped to a monitoring API, stored in Elasticsearch, or compared against a previous snapshot.
💡 jc + jq + AI log analysis
The health report JSON is perfect input for AI log analysis. Pipe the
output to sgpt for a plain-English summary:
bash health-report.sh | sgpt "Summarize this system health report. Flag anything that needs attention."
⚠️ Parser availability varies
Not every parser is available in every version of jc. If a parser
throws an error, check jc --list to confirm it exists in
your installed version, then pip3 install --upgrade jc to
get the latest parsers. The pip version is always more current than
distro packages.
Quick Reference — Common Parsers
| Command | jc Parser | Key Fields |
|---|---|---|
ps aux |
--ps |
user, pid, cpu_percent, mem_percent, command |
df |
--df |
filesystem, use_percent, available, mounted_on |
ip addr |
--ip-address |
ifname, flags, addr_info[].local |
ip route |
--ip-route |
route, gateway, dev, metric |
last |
--last |
user, hostname, started, duration |
who |
--who |
user, tty, time, hostname |
cat /etc/passwd |
--passwd |
username, uid, gid, home, shell |
cat /etc/group |
--group |
group_name, gid, members[] |
lsblk |
--lsblk |
name, size, type, fstype, mountpoint |
uptime |
--uptime |
uptime, users, load_1m, load_5m, load_15m |
free |
--free |
type, total, used, free, available |
uname -a |
--uname |
kernel_name, node_name, kernel_release, machine |
systemctl list-units |
--systemctl |
unit, load, active, sub, description |
crontab -l |
--crontab |
schedule[].minute, hour, command |
cat ~/.ssh/authorized_keys |
--authorized-keys-file |
key_type, key, comment |