diff --git a/README.md b/README.md
index f9743e0d..3278bd36 100644
--- a/README.md
+++ b/README.md
@@ -199,6 +199,7 @@ option.
- `--lsusb` enables the `lsusb` command parser ([documentation](https://kellyjonbrazil.github.io/jc/docs/parsers/lsusb))
- `--mount` enables the `mount` command parser ([documentation](https://kellyjonbrazil.github.io/jc/docs/parsers/mount))
- `--netstat` enables the `netstat` command parser ([documentation](https://kellyjonbrazil.github.io/jc/docs/parsers/netstat))
+- `--nmcli` enables the `nmcli` command parser ([documentation](https://kellyjonbrazil.github.io/jc/docs/parsers/nmcli))
- `--ntpq` enables the `ntpq -p` command parser ([documentation](https://kellyjonbrazil.github.io/jc/docs/parsers/ntpq))
- `--passwd` enables the `/etc/passwd` file parser ([documentation](https://kellyjonbrazil.github.io/jc/docs/parsers/passwd))
- `--ping` enables the `ping` and `ping6` command parser ([documentation](https://kellyjonbrazil.github.io/jc/docs/parsers/ping))
diff --git a/docs/parsers/nmcli.md b/docs/parsers/nmcli.md
new file mode 100644
index 00000000..3e715588
--- /dev/null
+++ b/docs/parsers/nmcli.md
@@ -0,0 +1,172 @@
+[Home](https://kellyjonbrazil.github.io/jc/)
+
+
+# jc.parsers.nmcli
+
+jc - JSON CLI output utility `nmcli` command output parser
+
+Supports the following `nmcli` subcommands:
+- `nmcli general`
+- `nmcli general permissions`
+- `nmcli connection`
+- `nmcli connection show `
+- `nmcli device`
+- `nmcli device show`
+- `nmcli device show `
+
+Usage (cli):
+
+ $ nmcli device show lo | jc --nmcli
+
+ or
+
+ $ jc nmcli device show lo
+
+Usage (module):
+
+ import jc
+ result = jc.parse('nmcli', nmcli_command_output)
+
+ or
+
+ import jc.parsers.nmcli
+ result = jc.parsers.nmcli.parse(nmcli_command_output)
+
+Schema:
+
+ Because there are so many options, the schema is best effort. Integer
+ and Float value conversions are attempted and the original values are
+ kept if they fail. If you don't want automatic conversion, then use the
+ -r or raw=True option to disable it.
+
+ The structure is flat, for the most part, but there are a couple of
+ "well-known" keys that are further parsed into objects for convenience.
+ These are documented below.
+
+ [
+ {
+ "": string/integer/float, [0]
+ "dhcp4_option_x": {
+ "name": string,
+ "value": string/integer/float,
+ },
+ "ip4_route_x": {
+ "dst": string,
+ "nh": string,
+ "mt": integer
+ },
+ "ip6_route_x": {
+ "dst": string,
+ "nh": string,
+ "mt": integer,
+ "table": integer
+ }
+ }
+ ]
+
+ [0] all values of `---` are converted to null
+
+Examples:
+
+ $ nmcli connection show ens33 | jc --nmcli -p
+ [
+ {
+ "connection_id": "ens33",
+ "connection_uuid": "d92ece08-9e02-47d5-b2d2-92c80e155744",
+ "connection_stable_id": null,
+ "connection_type": "802-3-ethernet",
+ "connection_interface_name": "ens33",
+ "connection_autoconnect": "yes",
+ ...
+ "ip4_address_1": "192.168.71.180/24",
+ "ip4_gateway": "192.168.71.2",
+ "ip4_route_1": {
+ "dst": "0.0.0.0/0",
+ "nh": "192.168.71.2",
+ "mt": 100
+ },
+ "ip4_route_2": {
+ "dst": "192.168.71.0/24",
+ "nh": "0.0.0.0",
+ "mt": 100
+ },
+ "ip4_dns_1": "192.168.71.2",
+ "ip4_domain_1": "localdomain",
+ "dhcp4_option_1": {
+ "name": "broadcast_address",
+ "value": "192.168.71.255"
+ },
+ ...
+ "ip6_address_1": "fe80::c1cb:715d:bc3e:b8a0/64",
+ "ip6_gateway": null,
+ "ip6_route_1": {
+ "dst": "fe80::/64",
+ "nh": "::",
+ "mt": 100
+ }
+ }
+ ]
+
+ $ nmcli | jc --nmcli -p -r
+ [
+ {
+ "connection_id": "ens33",
+ "connection_uuid": "d92ece08-9e02-47d5-b2d2-92c80e155744",
+ "connection_stable_id": null,
+ "connection_type": "802-3-ethernet",
+ "connection_interface_name": "ens33",
+ "connection_autoconnect": "yes",
+ ...
+ "ip4_address_1": "192.168.71.180/24",
+ "ip4_gateway": "192.168.71.2",
+ "ip4_route_1": {
+ "dst": "0.0.0.0/0",
+ "nh": "192.168.71.2",
+ "mt": "100"
+ },
+ "ip4_route_2": {
+ "dst": "192.168.71.0/24",
+ "nh": "0.0.0.0",
+ "mt": "100"
+ },
+ "ip4_dns_1": "192.168.71.2",
+ "ip4_domain_1": "localdomain",
+ "dhcp4_option_1": {
+ "name": "broadcast_address",
+ "value": "192.168.71.255"
+ },
+ ...
+ "ip6_address_1": "fe80::c1cb:715d:bc3e:b8a0/64",
+ "ip6_gateway": null,
+ "ip6_route_1": {
+ "dst": "fe80::/64",
+ "nh": "::",
+ "mt": "100"
+ }
+ }
+ ]
+
+
+
+### parse
+
+```python
+def parse(data: str, raw: bool = False, quiet: bool = False) -> List[Dict]
+```
+
+Main text parsing function
+
+Parameters:
+
+ data: (string) text data to parse
+ raw: (boolean) unprocessed output if True
+ quiet: (boolean) suppress warning messages if True
+
+Returns:
+
+ List of Dictionaries. Raw or processed structured data.
+
+### Parser Information
+Compatibility: linux
+
+Version 1.0 by Kelly Brazil (kellyjonbrazil@gmail.com)
diff --git a/jc/parsers/nmcli.py b/jc/parsers/nmcli.py
index dadff717..4cc074c2 100644
--- a/jc/parsers/nmcli.py
+++ b/jc/parsers/nmcli.py
@@ -342,7 +342,6 @@ def _connection_show_x_parse(data: str) -> List[Dict]:
if '_route_' in key_n and key_n[-1].isdigit():
item[key_n] = _split_routes(item[key_n])
-
if item:
raw_output.append(item)
@@ -402,7 +401,7 @@ def parse(
# nmcli (second line startswith \t)
if data.splitlines()[1].startswith('\t'):
- raise ParseError('Use device, connection, or general subcommands in nmcli.')
+ raise ParseError('Use the device, connection, or general subcommand in nmcli.')
# nmcli device show
# nmcli device show lo
diff --git a/man/jc.1 b/man/jc.1
index 1151b676..29a94931 100644
--- a/man/jc.1
+++ b/man/jc.1
@@ -1,4 +1,4 @@
-.TH jc 1 2022-02-14 1.18.3 "JSON CLI output utility"
+.TH jc 1 2022-02-24 1.18.4 "JSON CLI output utility"
.SH NAME
jc \- JSONifies the output of many CLI tools and file-types
.SH SYNOPSIS
@@ -257,6 +257,11 @@ Key/Value file parser
\fB--netstat\fP
`netstat` command parser
+.TP
+.B
+\fB--nmcli\fP
+`nmcli` command parser
+
.TP
.B
\fB--ntpq\fP