1
0
mirror of https://github.com/kellyjonbrazil/jc.git synced 2025-06-19 00:17:51 +02:00

Merge pull request #123 from kellyjonbrazil/dev

Dev v1.15.2
This commit is contained in:
Kelly Brazil
2021-04-18 17:28:27 -07:00
committed by GitHub
162 changed files with 2915 additions and 1490 deletions

View File

@ -1,5 +1,14 @@
jc changelog jc changelog
20210418 v1.15.2
- Add systeminfo parser tested on Windows
- Update dig parser to fix an issue with IPv6 addresses in the server field
- Update dig parser to fix an issue when axfr entries contain a semicolon
- Update dig parser to add support for Additional Section and Opt Pseudosection
- Update dig parser to add query_size field
- Use dig parser as the main example in readme, documentation, and man page
- Standardize int, float, and boolean conversion rules with functions in jc.utils
20210413 v1.15.1 20210413 v1.15.1
- New feature to show parser documentation interactively with -h --parser_name - New feature to show parser documentation interactively with -h --parser_name
for example: $ jc -h --arp for example: $ jc -h --arp

View File

@ -548,7 +548,7 @@ dig cnn.com www.cnn.com @205.251.194.64 | jc --dig -p # or: jc -p dig
```json ```json
[ [
{ {
"id": 52172, "id": 10267,
"opcode": "QUERY", "opcode": "QUERY",
"status": "NOERROR", "status": "NOERROR",
"flags": [ "flags": [
@ -560,6 +560,13 @@ dig cnn.com www.cnn.com @205.251.194.64 | jc --dig -p # or: jc -p dig
"answer_num": 4, "answer_num": 4,
"authority_num": 0, "authority_num": 0,
"additional_num": 1, "additional_num": 1,
"opt_pseudosection": {
"edns": {
"version": 0,
"flags": [],
"udp": 4096
}
},
"question": { "question": {
"name": "cnn.com.", "name": "cnn.com.",
"class": "IN", "class": "IN",
@ -570,40 +577,40 @@ dig cnn.com www.cnn.com @205.251.194.64 | jc --dig -p # or: jc -p dig
"name": "cnn.com.", "name": "cnn.com.",
"class": "IN", "class": "IN",
"type": "A", "type": "A",
"ttl": 27, "ttl": 17,
"data": "151.101.65.67" "data": "151.101.65.67"
}, },
{ {
"name": "cnn.com.", "name": "cnn.com.",
"class": "IN", "class": "IN",
"type": "A", "type": "A",
"ttl": 27, "ttl": 17,
"data": "151.101.129.67" "data": "151.101.129.67"
}, },
{ {
"name": "cnn.com.", "name": "cnn.com.",
"class": "IN", "class": "IN",
"type": "A", "type": "A",
"ttl": 27, "ttl": 17,
"data": "151.101.1.67" "data": "151.101.1.67"
}, },
{ {
"name": "cnn.com.", "name": "cnn.com.",
"class": "IN", "class": "IN",
"type": "A", "type": "A",
"ttl": 27, "ttl": 17,
"data": "151.101.193.67" "data": "151.101.193.67"
} }
], ],
"query_time": 38, "query_time": 51,
"server": "2600", "server": "2600:1700:bab0:d40::1#53(2600:1700:bab0:d40::1)",
"when": "Tue Mar 30 20:07:59 PDT 2021", "when": "Fri Apr 16 16:24:32 PDT 2021",
"rcvd": 100, "rcvd": 100,
"when_epoch": 1617160079, "when_epoch": 1618615472,
"when_epoch_utc": null "when_epoch_utc": null
}, },
{ {
"id": 36292, "id": 56207,
"opcode": "QUERY", "opcode": "QUERY",
"status": "NOERROR", "status": "NOERROR",
"flags": [ "flags": [
@ -615,6 +622,13 @@ dig cnn.com www.cnn.com @205.251.194.64 | jc --dig -p # or: jc -p dig
"answer_num": 1, "answer_num": 1,
"authority_num": 4, "authority_num": 4,
"additional_num": 1, "additional_num": 1,
"opt_pseudosection": {
"edns": {
"version": 0,
"flags": [],
"udp": 4096
}
},
"question": { "question": {
"name": "www.cnn.com.", "name": "www.cnn.com.",
"class": "IN", "class": "IN",
@ -659,11 +673,11 @@ dig cnn.com www.cnn.com @205.251.194.64 | jc --dig -p # or: jc -p dig
"data": "ns-576.awsdns-08.net." "data": "ns-576.awsdns-08.net."
} }
], ],
"query_time": 27, "query_time": 22,
"server": "205.251.194.64#53(205.251.194.64)", "server": "205.251.194.64#53(205.251.194.64)",
"when": "Tue Mar 30 20:07:59 PDT 2021", "when": "Fri Apr 16 16:24:32 PDT 2021",
"rcvd": 212, "rcvd": 212,
"when_epoch": 1617160079, "when_epoch": 1618615472,
"when_epoch_utc": null "when_epoch_utc": null
} }
] ]
@ -674,7 +688,7 @@ dig -x 1.1.1.1 | jc --dig -p # or: jc -p dig -x 1.1.1.1
```json ```json
[ [
{ {
"id": 22191, "id": 20785,
"opcode": "QUERY", "opcode": "QUERY",
"status": "NOERROR", "status": "NOERROR",
"flags": [ "flags": [
@ -686,6 +700,13 @@ dig -x 1.1.1.1 | jc --dig -p # or: jc -p dig -x 1.1.1.1
"answer_num": 1, "answer_num": 1,
"authority_num": 0, "authority_num": 0,
"additional_num": 1, "additional_num": 1,
"opt_pseudosection": {
"edns": {
"version": 0,
"flags": [],
"udp": 4096
}
},
"question": { "question": {
"name": "1.1.1.1.in-addr.arpa.", "name": "1.1.1.1.in-addr.arpa.",
"class": "IN", "class": "IN",
@ -700,11 +721,11 @@ dig -x 1.1.1.1 | jc --dig -p # or: jc -p dig -x 1.1.1.1
"data": "one.one.one.one." "data": "one.one.one.one."
} }
], ],
"query_time": 44, "query_time": 40,
"server": "2600", "server": "2600:1700:bab0:d40::1#53(2600:1700:bab0:d40::1)",
"when": "Tue Mar 30 20:10:34 PDT 2021", "when": "Sat Apr 17 14:50:50 PDT 2021",
"rcvd": 78, "rcvd": 78,
"when_epoch": 1617160234, "when_epoch": 1618696250,
"when_epoch_utc": null "when_epoch_utc": null
} }
] ]
@ -2869,6 +2890,72 @@ systemctl list-unit-files | jc --systemctl-luf -p # or: jc -p systemct
} }
] ]
``` ```
### systeminfo
```bash
systeminfo | jc --systeminfo -p # or: jc -p systeminfo
```
```json
{
"host_name": "TESTLAPTOP",
"os_name": "Microsoft Windows 10 Enterprise",
"os_version": "10.0.17134 N/A Build 17134",
"os_manufacturer": "Microsoft Corporation",
"os_configuration": "Member Workstation",
"os_build_type": "Multiprocessor Free",
"registered_owner": "Test, Inc.",
"registered_organization": "Test, Inc.",
"product_id": "11111-11111-11111-AA111",
"original_install_date": "3/26/2019, 3:51:30 PM",
"system_boot_time": "3/30/2021, 6:13:59 AM",
"system_manufacturer": "Dell Inc.",
"system_model": "Precision 5530",
"system_type": "x64-based PC",
"processors": [
"Intel64 Family 6 Model 158 Stepping 10 GenuineIntel ~2592 Mhz"
],
"bios_version": "Dell Inc. 1.16.2, 4/21/2020",
"windows_directory": "C:\\WINDOWS",
"system_directory": "C:\\WINDOWS\\system32",
"boot_device": "\\Device\\HarddiskVolume2",
"system_locale": "en-us;English (United States)",
"input_locale": "en-us;English (United States)",
"time_zone": "(UTC+00:00) UTC",
"total_physical_memory_mb": 32503,
"available_physical_memory_mb": 19743,
"virtual_memory_max_size_mb": 37367,
"virtual_memory_available_mb": 22266,
"virtual_memory_in_use_mb": 15101,
"page_file_locations": "C:\\pagefile.sys",
"domain": "test.com",
"logon_server": "\\\\TESTDC01",
"hotfixs": [
"KB2693643",
"KB4601054"
],
"network_cards": [
{
"name": "Intel(R) Wireless-AC 9260 160MHz",
"connection_name": "Wi-Fi",
"status": null,
"dhcp_enabled": true,
"dhcp_server": "192.168.2.1",
"ip_addresses": [
"192.168.2.219"
]
}
],
"hyperv_requirements": {
"vm_monitor_mode_extensions": true,
"virtualization_enabled_in_firmware": true,
"second_level_address_translation": false,
"data_execution_prevention_available": true
},
"original_install_date_epoch": 1553640690,
"original_install_date_epoch_utc": 1553615490,
"system_boot_time_epoch": 1617110039,
"system_boot_time_epoch_utc": 1617084839
}
```
### /usr/bin/time ### /usr/bin/time
```bash ```bash
/usr/bin/time --verbose -o timefile.out sleep 2.5; cat timefile.out | jc --time -p /usr/bin/time --verbose -o timefile.out sleep 2.5; cat timefile.out | jc --time -p

127
README.md
View File

@ -9,62 +9,56 @@
JSON CLI output utility JSON CLI output utility
`jc` JSONifies the output of many CLI tools and file-types for easier parsing in scripts. See the [**Parsers**](#parsers) section for supported commands and file-types. `jc` JSONifies the output of many CLI tools and file-types for easier parsing in scripts. See the [**Parsers**](#parsers) section for supported commands and file-types.
This allows further command-line processing of output with tools like `jq` by piping commands:
```bash ```bash
ls -l /usr/bin | jc --ls | jq '.[] | select(.size > 50000000)' dig example.com | jc --dig
``` ```
```json ```json
{ [{"id":38052,"opcode":"QUERY","status":"NOERROR","flags":["qr","rd","ra"],"query_num":1,"answer_num":1,
"filename": "docker", "authority_num":0,"additional_num":1,"opt_pseudosection":{"edns":{"version":0,"flags":[],"udp":4096}},"question":
"flags": "-rwxr-xr-x", {"name":"example.com.","class":"IN","type":"A"},"answer":[{"name":"example.com.","class":"IN","type":"A","ttl":
"links": 1, 39049,"data":"93.184.216.34"}],"query_time":49,"server":"2600:1700:bab0:d40::1#53(2600:1700:bab0:d40::1)","when":
"owner": "root", "Fri Apr 16 16:09:00 PDT 2021","rcvd":56,"when_epoch":1618614540,"when_epoch_utc":null}]
"group": "root", ```
"size": 68677120, This allows further command-line processing of output with tools like `jq` by piping commands:
"date": "Aug 14 19:41" ```bash
} $ dig example.com | jc --dig | jq -r '.[].answer[].data'
93.184.216.34
``` ```
or using the alternative "magic" syntax: or using the alternative "magic" syntax:
```bash ```bash
jc ls -l /usr/bin | jq '.[] | select(.size > 50000000)' $ jc dig example.com | jq -r '.[].answer[].data'
``` 93.184.216.34
```json
{
"filename": "docker",
"flags": "-rwxr-xr-x",
"links": 1,
"owner": "root",
"group": "root",
"size": 68677120,
"date": "Aug 14 19:41"
}
``` ```
The `jc` parsers can also be used as python modules. In this case the output will be a python dictionary, or list of dictionaries, instead of JSON: The `jc` parsers can also be used as python modules. In this case the output will be a python dictionary, or list of dictionaries, instead of JSON:
```python ```python
>>> import jc.parsers.ls >>> import jc.parsers.dig
>>> >>>
>>> data='''-rwxr-xr-x 1 root wheel 23648 May 3 22:26 cat >>> data = '''; <<>> DiG 9.10.6 <<>> example.com
... -rwxr-xr-x 1 root wheel 30016 May 3 22:26 chmod ... ;; global options: +cmd
... -rwxr-xr-x 1 root wheel 29024 May 3 22:26 cp ... ;; Got answer:
... -rwxr-xr-x 1 root wheel 375824 May 3 22:26 csh ... ;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 64612
... -rwxr-xr-x 1 root wheel 28608 May 3 22:26 date ... ;; flags: qr rd ra; QUERY: 1, ANSWER: 1, AUTHORITY: 0, ADDITIONAL: 1
... -rwxr-xr-x 1 root wheel 32000 May 3 22:26 dd ...
... -rwxr-xr-x 1 root wheel 23392 May 3 22:26 df ... ;; OPT PSEUDOSECTION:
... -rwxr-xr-x 1 root wheel 18128 May 3 22:26 echo''' ... ; EDNS: version: 0, flags:; udp: 4096
... ;; QUESTION SECTION:
... ;example.com. IN A
...
... ;; ANSWER SECTION:
... example.com. 29658 IN A 93.184.216.34
...
... ;; Query time: 52 msec
... ;; SERVER: 2600:1700:bab0:d40::1#53(2600:1700:bab0:d40::1)
... ;; WHEN: Fri Apr 16 16:13:00 PDT 2021
... ;; MSG SIZE rcvd: 56'''
>>> >>>
>>> jc.parsers.ls.parse(data) >>> jc.parsers.dig.parse(data)
[{'filename': 'cat', 'flags': '-rwxr-xr-x', 'links': 1, 'owner': 'root', 'group': 'wheel', 'size': 23648, [{'id': 64612, 'opcode': 'QUERY', 'status': 'NOERROR', 'flags': ['qr', 'rd', 'ra'], 'query_num': 1, 'answer_num':
'date': 'May 3 22:26'}, {'filename': 'chmod', 'flags': '-rwxr-xr-x', 'links': 1, 'owner': 'root', 1, 'authority_num': 0, 'additional_num': 1, 'opt_pseudosection': {'edns': {'version': 0, 'flags': [], 'udp':
'group': 'wheel', 'size': 30016, 'date': 'May 3 22:26'}, {'filename': 'cp', 'flags': '-rwxr-xr-x', 4096}}, 'question': {'name': 'example.com.', 'class': 'IN', 'type': 'A'}, 'answer': [{'name': 'example.com.',
'links': 1, 'owner': 'root', 'group': 'wheel', 'size': 29024, 'date': 'May 3 22:26'}, {'filename': 'csh', 'class': 'IN', 'type': 'A', 'ttl': 29658, 'data': '93.184.216.34'}], 'query_time': 52, 'server':
'flags': '-rwxr-xr-x', 'links': 1, 'owner': 'root', 'group': 'wheel', 'size': 375824, 'date': 'May 3 '2600:1700:bab0:d40::1#53(2600:1700:bab0:d40::1)', 'when': 'Fri Apr 16 16:13:00 PDT 2021', 'rcvd': 56,
22:26'}, {'filename': 'date', 'flags': '-rwxr-xr-x', 'links': 1, 'owner': 'root', 'group': 'wheel', 'when_epoch': 1618614780, 'when_epoch_utc': None}]
'size': 28608, 'date': 'May 3 22:26'}, {'filename': 'dd', 'flags': '-rwxr-xr-x', 'links': 1, 'owner':
'root', 'group': 'wheel', 'size': 32000, 'date': 'May 3 22:26'}, {'filename': 'df', 'flags':
'-rwxr-xr-x', 'links': 1, 'owner': 'root', 'group': 'wheel', 'size': 23392, 'date': 'May 3 22:26'},
{'filename': 'echo', 'flags': '-rwxr-xr-x', 'links': 1, 'owner': 'root', 'group': 'wheel', 'size': 18128,
'date': 'May 3 22:26'}]
``` ```
Two representations of the data are possible. The default representation uses a strict schema per parser and converts known numbers to int/float JSON values. Certain known values of `None` are converted to JSON `null`, known boolean values are converted, and, in some cases, additional semantic context fields are added. Two representations of the data are possible. The default representation uses a strict schema per parser and converts known numbers to int/float JSON values. Certain known values of `None` are converted to JSON `null`, known boolean values are converted, and, in some cases, additional semantic context fields are added.
@ -183,6 +177,7 @@ The JSON output can be compact (default) or pretty formatted with the `-p` optio
- `--systemctl-lj` enables the `systemctl list-jobs` command parser ([documentation](https://kellyjonbrazil.github.io/jc/docs/parsers/systemctl_lj)) - `--systemctl-lj` enables the `systemctl list-jobs` command parser ([documentation](https://kellyjonbrazil.github.io/jc/docs/parsers/systemctl_lj))
- `--systemctl-ls` enables the `systemctl list-sockets` command parser ([documentation](https://kellyjonbrazil.github.io/jc/docs/parsers/systemctl_ls)) - `--systemctl-ls` enables the `systemctl list-sockets` command parser ([documentation](https://kellyjonbrazil.github.io/jc/docs/parsers/systemctl_ls))
- `--systemctl-luf` enables the `systemctl list-unit-files` command parser ([documentation](https://kellyjonbrazil.github.io/jc/docs/parsers/systemctl_luf)) - `--systemctl-luf` enables the `systemctl list-unit-files` command parser ([documentation](https://kellyjonbrazil.github.io/jc/docs/parsers/systemctl_luf))
- `--systeminfo` enables the `systeminfo` command parser ([documentation](https://kellyjonbrazil.github.io/jc/docs/parsers/systeminfo))
- `--time` enables the `/usr/bin/time` command parser ([documentation](https://kellyjonbrazil.github.io/jc/docs/parsers/time)) - `--time` enables the `/usr/bin/time` command parser ([documentation](https://kellyjonbrazil.github.io/jc/docs/parsers/time))
- `--timedatectl` enables the `timedatectl status` command parser ([documentation](https://kellyjonbrazil.github.io/jc/docs/parsers/timedatectl)) - `--timedatectl` enables the `timedatectl status` command parser ([documentation](https://kellyjonbrazil.github.io/jc/docs/parsers/timedatectl))
- `--tracepath` enables the `tracepath` and `tracepath6` command parser ([documentation](https://kellyjonbrazil.github.io/jc/docs/parsers/tracepath)) - `--tracepath` enables the `tracepath` and `tracepath6` command parser ([documentation](https://kellyjonbrazil.github.io/jc/docs/parsers/tracepath))
@ -352,48 +347,6 @@ cat homes.csv | jc --csv -p
} }
] ]
``` ```
### dig
```bash
dig cnn.com @205.251.194.64 | jc --dig -p # or: jc -p dig cnn.com @205.251.194.64
```
```json
[
{
"id": 52172,
"opcode": "QUERY",
"status": "NOERROR",
"flags": [
"qr",
"rd",
"ra"
],
"query_num": 1,
"answer_num": 1,
"authority_num": 0,
"additional_num": 1,
"question": {
"name": "cnn.com.",
"class": "IN",
"type": "A"
},
"answer": [
{
"name": "cnn.com.",
"class": "IN",
"type": "A",
"ttl": 27,
"data": "151.101.65.67"
}
],
"query_time": 38,
"server": "2600",
"when": "Tue Mar 30 20:07:59 PDT 2021",
"rcvd": 100,
"when_epoch": 1617160079,
"when_epoch_utc": null
}
]
```
### /etc/hosts file ### /etc/hosts file
```bash ```bash
cat /etc/hosts | jc --hosts -p cat /etc/hosts | jc --hosts -p

View File

@ -252,4 +252,4 @@ Returns:
## Parser Information ## Parser Information
Compatibility: linux Compatibility: linux
Version 1.1 by Kelly Brazil (kellyjonbrazil@gmail.com) Version 1.2 by Kelly Brazil (kellyjonbrazil@gmail.com)

View File

@ -105,4 +105,4 @@ Returns:
## Parser Information ## Parser Information
Compatibility: darwin Compatibility: darwin
Version 1.2 by Kelly Brazil (kellyjonbrazil@gmail.com) Version 1.3 by Kelly Brazil (kellyjonbrazil@gmail.com)

View File

@ -133,4 +133,4 @@ Returns:
## Parser Information ## Parser Information
Compatibility: darwin Compatibility: darwin
Version 1.3 by Kelly Brazil (kellyjonbrazil@gmail.com) Version 1.4 by Kelly Brazil (kellyjonbrazil@gmail.com)

View File

@ -145,4 +145,4 @@ Returns:
## Parser Information ## Parser Information
Compatibility: linux Compatibility: linux
Version 1.3 by Kelly Brazil (kellyjonbrazil@gmail.com) Version 1.4 by Kelly Brazil (kellyjonbrazil@gmail.com)

View File

@ -79,4 +79,4 @@ Returns:
## Parser Information ## Parser Information
Compatibility: linux, darwin, cygwin, aix, freebsd Compatibility: linux, darwin, cygwin, aix, freebsd
Version 1.1 by Kelly Brazil (kellyjonbrazil@gmail.com) Version 1.2 by Kelly Brazil (kellyjonbrazil@gmail.com)

View File

@ -122,4 +122,4 @@ Returns:
## Parser Information ## Parser Information
Compatibility: linux, darwin, freebsd Compatibility: linux, darwin, freebsd
Version 1.6 by Kelly Brazil (kellyjonbrazil@gmail.com) Version 1.7 by Kelly Brazil (kellyjonbrazil@gmail.com)

View File

@ -43,6 +43,16 @@ Schema:
"data": string "data": string
} }
], ],
"opt_pseudosection": {
"edns": {
"version": integer,
"flags": [
string
],
"udp": integer
},
"cookie": string
},
"question": { "question": {
"name": string, "name": string,
"class": string, "class": string,
@ -57,6 +67,15 @@ Schema:
"data": string "data": string
} }
], ],
"additional": [
{
"name": string,
"class": string,
"type": string,
"ttl": integer,
"data": string
}
],
"authority": [ "authority": [
{ {
"name": string, "name": string,
@ -66,6 +85,7 @@ Schema:
"data": string "data": string
} }
], ],
"query_size": integer,
"query_time": integer, # in msec "query_time": integer, # in msec
"server": string, "server": string,
"when": string, "when": string,
@ -78,10 +98,10 @@ Schema:
Examples: Examples:
$ dig cnn.com www.cnn.com @205.251.194.64 | jc --dig -p $ dig example.com | jc --dig -p
[ [
{ {
"id": 52172, "id": 2951,
"opcode": "QUERY", "opcode": "QUERY",
"status": "NOERROR", "status": "NOERROR",
"flags": [ "flags": [
@ -90,113 +110,35 @@ Examples:
"ra" "ra"
], ],
"query_num": 1, "query_num": 1,
"answer_num": 4, "answer_num": 1,
"authority_num": 0, "authority_num": 0,
"additional_num": 1, "additional_num": 1,
"opt_pseudosection": {
"edns": {
"version": 0,
"flags": [],
"udp": 4096
}
},
"question": { "question": {
"name": "cnn.com.", "name": "example.com.",
"class": "IN", "class": "IN",
"type": "A" "type": "A"
}, },
"answer": [ "answer": [
{ {
"name": "cnn.com.", "name": "example.com.",
"class": "IN", "class": "IN",
"type": "A", "type": "A",
"ttl": 27, "ttl": 39302,
"data": "151.101.65.67" "data": "93.184.216.34"
},
{
"name": "cnn.com.",
"class": "IN",
"type": "A",
"ttl": 27,
"data": "151.101.129.67"
},
{
"name": "cnn.com.",
"class": "IN",
"type": "A",
"ttl": 27,
"data": "151.101.1.67"
},
{
"name": "cnn.com.",
"class": "IN",
"type": "A",
"ttl": 27,
"data": "151.101.193.67"
} }
], ],
"query_time": 38, "query_time": 49,
"server": "2600", "server": "2600:1700:bab0:d40::1#53(2600:1700:bab0:d40::1)",
"when": "Tue Mar 30 20:07:59 PDT 2021", "when": "Fri Apr 16 16:05:10 PDT 2021",
"rcvd": 100, "rcvd": 56,
"when_epoch": 1617160079, "when_epoch": 1618614310,
"when_epoch_utc": null
},
{
"id": 36292,
"opcode": "QUERY",
"status": "NOERROR",
"flags": [
"qr",
"aa",
"rd"
],
"query_num": 1,
"answer_num": 1,
"authority_num": 4,
"additional_num": 1,
"question": {
"name": "www.cnn.com.",
"class": "IN",
"type": "A"
},
"answer": [
{
"name": "www.cnn.com.",
"class": "IN",
"type": "CNAME",
"ttl": 300,
"data": "turner-tls.map.fastly.net."
}
],
"authority": [
{
"name": "cnn.com.",
"class": "IN",
"type": "NS",
"ttl": 3600,
"data": "ns-1086.awsdns-07.org."
},
{
"name": "cnn.com.",
"class": "IN",
"type": "NS",
"ttl": 3600,
"data": "ns-1630.awsdns-11.co.uk."
},
{
"name": "cnn.com.",
"class": "IN",
"type": "NS",
"ttl": 3600,
"data": "ns-47.awsdns-05.com."
},
{
"name": "cnn.com.",
"class": "IN",
"type": "NS",
"ttl": 3600,
"data": "ns-576.awsdns-08.net."
}
],
"query_time": 27,
"server": "205.251.194.64#53(205.251.194.64)",
"when": "Tue Mar 30 20:07:59 PDT 2021",
"rcvd": 212,
"when_epoch": 1617160079,
"when_epoch_utc": null "when_epoch_utc": null
} }
] ]
@ -204,7 +146,7 @@ Examples:
$ dig cnn.com www.cnn.com @205.251.194.64 | jc --dig -p -r $ dig cnn.com www.cnn.com @205.251.194.64 | jc --dig -p -r
[ [
{ {
"id": "23843", "id": "46052",
"opcode": "QUERY", "opcode": "QUERY",
"status": "NOERROR", "status": "NOERROR",
"flags": [ "flags": [
@ -213,117 +155,41 @@ Examples:
"ra" "ra"
], ],
"query_num": "1", "query_num": "1",
"answer_num": "4", "answer_num": "1",
"authority_num": "0", "authority_num": "0",
"additional_num": "1", "additional_num": "1",
"opt_pseudosection": {
"edns": {
"version": "0",
"flags": [],
"udp": "4096"
}
},
"question": { "question": {
"name": "cnn.com.", "name": "example.com.",
"class": "IN", "class": "IN",
"type": "A" "type": "A"
}, },
"answer": [ "answer": [
{ {
"name": "cnn.com.", "name": "example.com.",
"class": "IN", "class": "IN",
"type": "A", "type": "A",
"ttl": "30", "ttl": "40426",
"data": "151.101.193.67" "data": "93.184.216.34"
},
{
"name": "cnn.com.",
"class": "IN",
"type": "A",
"ttl": "30",
"data": "151.101.1.67"
},
{
"name": "cnn.com.",
"class": "IN",
"type": "A",
"ttl": "30",
"data": "151.101.65.67"
},
{
"name": "cnn.com.",
"class": "IN",
"type": "A",
"ttl": "30",
"data": "151.101.129.67"
} }
], ],
"query_time": "24 msec", "query_time": "48 msec",
"server": "192.168.1.254#53(192.168.1.254)", "server": "2600:1700:bab0:d40::1#53(2600:1700:bab0:d40::1)",
"when": "Tue Nov 12 07:16:19 PST 2019", "when": "Fri Apr 16 16:06:12 PDT 2021",
"rcvd": "100" "rcvd": "56"
},
{
"id": "8266",
"opcode": "QUERY",
"status": "NOERROR",
"flags": [
"qr",
"aa",
"rd"
],
"query_num": "1",
"answer_num": "1",
"authority_num": "4",
"additional_num": "1",
"question": {
"name": "www.cnn.com.",
"class": "IN",
"type": "A"
},
"answer": [
{
"name": "www.cnn.com.",
"class": "IN",
"type": "CNAME",
"ttl": "300",
"data": "turner-tls.map.fastly.net."
}
],
"authority": [
{
"name": "cnn.com.",
"class": "IN",
"type": "NS",
"ttl": "3600",
"data": "ns-1086.awsdns-07.org."
},
{
"name": "cnn.com.",
"class": "IN",
"type": "NS",
"ttl": "3600",
"data": "ns-1630.awsdns-11.co.uk."
},
{
"name": "cnn.com.",
"class": "IN",
"type": "NS",
"ttl": "3600",
"data": "ns-47.awsdns-05.com."
},
{
"name": "cnn.com.",
"class": "IN",
"type": "NS",
"ttl": "3600",
"data": "ns-576.awsdns-08.net."
}
],
"query_time": "26 msec",
"server": "205.251.194.64#53(205.251.194.64)",
"when": "Tue Nov 12 07:16:19 PST 2019",
"rcvd": "212"
} }
] ]
$ dig -x 1.1.1.1 | jc --dig -p $ dig -x 1.1.1.1 | jc --dig -p
[ [
{ {
"id": 22191, "id": 20785,
"opcode": "QUERY", "opcode": "QUERY",
"status": "NOERROR", "status": "NOERROR",
"flags": [ "flags": [
@ -335,6 +201,13 @@ Examples:
"answer_num": 1, "answer_num": 1,
"authority_num": 0, "authority_num": 0,
"additional_num": 1, "additional_num": 1,
"opt_pseudosection": {
"edns": {
"version": 0,
"flags": [],
"udp": 4096
}
},
"question": { "question": {
"name": "1.1.1.1.in-addr.arpa.", "name": "1.1.1.1.in-addr.arpa.",
"class": "IN", "class": "IN",
@ -349,11 +222,11 @@ Examples:
"data": "one.one.one.one." "data": "one.one.one.one."
} }
], ],
"query_time": 44, "query_time": 40,
"server": "2600", "server": "2600:1700:bab0:d40::1#53(2600:1700:bab0:d40::1)",
"when": "Tue Mar 30 20:10:34 PDT 2021", "when": "Sat Apr 17 14:50:50 PDT 2021",
"rcvd": 78, "rcvd": 78,
"when_epoch": 1617160234, "when_epoch": 1618696250,
"when_epoch_utc": null "when_epoch_utc": null
} }
] ]
@ -361,7 +234,7 @@ Examples:
$ dig -x 1.1.1.1 | jc --dig -p -r $ dig -x 1.1.1.1 | jc --dig -p -r
[ [
{ {
"id": "50986", "id": "32644",
"opcode": "QUERY", "opcode": "QUERY",
"status": "NOERROR", "status": "NOERROR",
"flags": [ "flags": [
@ -373,6 +246,13 @@ Examples:
"answer_num": "1", "answer_num": "1",
"authority_num": "0", "authority_num": "0",
"additional_num": "1", "additional_num": "1",
"opt_pseudosection": {
"edns": {
"version": "0",
"flags": [],
"udp": "4096"
}
},
"question": { "question": {
"name": "1.1.1.1.in-addr.arpa.", "name": "1.1.1.1.in-addr.arpa.",
"class": "IN", "class": "IN",
@ -387,9 +267,9 @@ Examples:
"data": "one.one.one.one." "data": "one.one.one.one."
} }
], ],
"query_time": "38 msec", "query_time": "52 msec",
"server": "2600", "server": "2600:1700:bab0:d40::1#53(2600:1700:bab0:d40::1)",
"when": "Tue Nov 12 07:17:19 PST 2019", "when": "Sat Apr 17 14:51:46 PDT 2021",
"rcvd": "78" "rcvd": "78"
} }
] ]
@ -421,4 +301,4 @@ Returns:
## Parser Information ## Parser Information
Compatibility: linux, aix, freebsd, darwin Compatibility: linux, aix, freebsd, darwin
Version 1.7 by Kelly Brazil (kellyjonbrazil@gmail.com) Version 2.0 by Kelly Brazil (kellyjonbrazil@gmail.com)

View File

@ -145,4 +145,4 @@ Returns:
## Parser Information ## Parser Information
Compatibility: win32 Compatibility: win32
Version 1.1 by Rasheed Elsaleh (rasheed@rebelliondefense.com) Version 1.2 by Rasheed Elsaleh (rasheed@rebelliondefense.com)

View File

@ -150,4 +150,4 @@ Returns:
## Parser Information ## Parser Information
Compatibility: linux Compatibility: linux
Version 1.2 by Kelly Brazil (kellyjonbrazil@gmail.com) Version 1.3 by Kelly Brazil (kellyjonbrazil@gmail.com)

View File

@ -112,4 +112,4 @@ Returns:
## Parser Information ## Parser Information
Compatibility: linux, darwin, aix, freebsd Compatibility: linux, darwin, aix, freebsd
Version 1.3 by Kelly Brazil (kellyjonbrazil@gmail.com) Version 1.4 by Kelly Brazil (kellyjonbrazil@gmail.com)

View File

@ -97,4 +97,4 @@ Returns:
## Parser Information ## Parser Information
Compatibility: linux Compatibility: linux
Version 1.3 by Kelly Brazil (kellyjonbrazil@gmail.com) Version 1.4 by Kelly Brazil (kellyjonbrazil@gmail.com)

View File

@ -110,4 +110,4 @@ Returns:
## Parser Information ## Parser Information
Compatibility: linux, freebsd Compatibility: linux, freebsd
Version 1.4 by Kelly Brazil (kellyjonbrazil@gmail.com) Version 1.5 by Kelly Brazil (kellyjonbrazil@gmail.com)

View File

@ -134,4 +134,4 @@ Returns:
## Parser Information ## Parser Information
Compatibility: linux, darwin, aix, freebsd Compatibility: linux, darwin, aix, freebsd
Version 1.2 by Kelly Brazil (kellyjonbrazil@gmail.com) Version 1.3 by Kelly Brazil (kellyjonbrazil@gmail.com)

View File

@ -62,4 +62,4 @@ Returns:
## Parser Information ## Parser Information
Compatibility: linux, darwin, cygwin, aix, freebsd Compatibility: linux, darwin, cygwin, aix, freebsd
Version 1.1 by Kelly Brazil (kellyjonbrazil@gmail.com) Version 1.2 by Kelly Brazil (kellyjonbrazil@gmail.com)

View File

@ -342,4 +342,4 @@ Returns:
## Parser Information ## Parser Information
Compatibility: linux Compatibility: linux
Version 1.1 by Kelly Brazil (kellyjonbrazil@gmail.com) Version 1.2 by Kelly Brazil (kellyjonbrazil@gmail.com)

View File

@ -83,4 +83,4 @@ Returns:
## Parser Information ## Parser Information
Compatibility: linux, darwin, cygwin, aix, freebsd Compatibility: linux, darwin, cygwin, aix, freebsd
Version 1.4 by Kelly Brazil (kellyjonbrazil@gmail.com) Version 1.5 by Kelly Brazil (kellyjonbrazil@gmail.com)

View File

@ -130,4 +130,4 @@ Returns:
## Parser Information ## Parser Information
Compatibility: linux, darwin, aix, freebsd Compatibility: linux, darwin, aix, freebsd
Version 1.2 by Kelly Brazil (kellyjonbrazil@gmail.com) Version 1.3 by Kelly Brazil (kellyjonbrazil@gmail.com)

View File

@ -211,4 +211,4 @@ Returns:
## Parser Information ## Parser Information
Compatibility: linux, aix, freebsd, darwin Compatibility: linux, aix, freebsd, darwin
Version 1.9 by Kelly Brazil (kellyjonbrazil@gmail.com) Version 1.10 by Kelly Brazil (kellyjonbrazil@gmail.com)

View File

@ -188,4 +188,4 @@ Returns:
## Parser Information ## Parser Information
Compatibility: linux Compatibility: linux
Version 1.5 by Kelly Brazil (kellyjonbrazil@gmail.com) Version 1.6 by Kelly Brazil (kellyjonbrazil@gmail.com)

View File

@ -119,4 +119,4 @@ Returns:
## Parser Information ## Parser Information
Compatibility: linux, darwin, cygwin, aix, freebsd Compatibility: linux, darwin, cygwin, aix, freebsd
Version 1.3 by Kelly Brazil (kellyjonbrazil@gmail.com) Version 1.4 by Kelly Brazil (kellyjonbrazil@gmail.com)

View File

@ -128,4 +128,4 @@ Returns:
## Parser Information ## Parser Information
Compatibility: linux, darwin, aix, freebsd Compatibility: linux, darwin, aix, freebsd
Version 1.6 by Kelly Brazil (kellyjonbrazil@gmail.com) Version 1.7 by Kelly Brazil (kellyjonbrazil@gmail.com)

View File

@ -6,7 +6,6 @@ jc - JSON CLI output utility `ls` and `vdir` command output parser
Options supported: Options supported:
- `lbaR1` - `lbaR1`
- `--time-style=full-iso` - `--time-style=full-iso`
- `-h`: File sizes will be available in text form with `-r` but larger file sizes with human readable suffixes will be converted to `Null` in the default view since the parser attempts to convert this field to an integer.
Note: The `-1`, `-l`, or `-b` option of `ls` should be used to correctly parse filenames that include newline characters. Since `ls` does not encode newlines in filenames when outputting to a pipe it will cause `jc` to see multiple files instead of a single file if `-1`, `-l`, or `-b` is not used. Alternatively, `vdir` can be used, which is the same as running `ls -lb`. Note: The `-1`, `-l`, or `-b` option of `ls` should be used to correctly parse filenames that include newline characters. Since `ls` does not encode newlines in filenames when outputting to a pipe it will cause `jc` to see multiple files instead of a single file if `-1`, `-l`, or `-b` is not used. Alternatively, `vdir` can be used, which is the same as running `ls -lb`.
@ -132,4 +131,4 @@ Returns:
## Parser Information ## Parser Information
Compatibility: linux, darwin, cygwin, aix, freebsd Compatibility: linux, darwin, cygwin, aix, freebsd
Version 1.8 by Kelly Brazil (kellyjonbrazil@gmail.com) Version 1.9 by Kelly Brazil (kellyjonbrazil@gmail.com)

View File

@ -293,4 +293,4 @@ Returns:
## Parser Information ## Parser Information
Compatibility: linux Compatibility: linux
Version 1.6 by Kelly Brazil (kellyjonbrazil@gmail.com) Version 1.7 by Kelly Brazil (kellyjonbrazil@gmail.com)

View File

@ -150,4 +150,4 @@ Returns:
## Parser Information ## Parser Information
Compatibility: linux Compatibility: linux
Version 1.4 by Kelly Brazil (kellyjonbrazil@gmail.com) Version 1.5 by Kelly Brazil (kellyjonbrazil@gmail.com)

View File

@ -144,4 +144,4 @@ Returns:
## Parser Information ## Parser Information
Compatibility: linux Compatibility: linux
Version 1.3 by Kelly Brazil (kellyjonbrazil@gmail.com) Version 1.4 by Kelly Brazil (kellyjonbrazil@gmail.com)

View File

@ -379,4 +379,4 @@ Returns:
## Parser Information ## Parser Information
Compatibility: linux, darwin, freebsd Compatibility: linux, darwin, freebsd
Version 1.9 by Kelly Brazil (kellyjonbrazil@gmail.com) Version 1.10 by Kelly Brazil (kellyjonbrazil@gmail.com)

View File

@ -231,4 +231,4 @@ Returns:
## Parser Information ## Parser Information
Compatibility: linux, freebsd Compatibility: linux, freebsd
Version 1.4 by Kelly Brazil (kellyjonbrazil@gmail.com) Version 1.5 by Kelly Brazil (kellyjonbrazil@gmail.com)

View File

@ -119,4 +119,4 @@ Returns:
## Parser Information ## Parser Information
Compatibility: linux, darwin, aix, freebsd Compatibility: linux, darwin, aix, freebsd
Version 1.2 by Kelly Brazil (kellyjonbrazil@gmail.com) Version 1.3 by Kelly Brazil (kellyjonbrazil@gmail.com)

View File

@ -170,4 +170,4 @@ Returns:
## Parser Information ## Parser Information
Compatibility: linux, darwin, freebsd Compatibility: linux, darwin, freebsd
Version 1.3 by Kelly Brazil (kellyjonbrazil@gmail.com) Version 1.4 by Kelly Brazil (kellyjonbrazil@gmail.com)

View File

@ -231,4 +231,4 @@ Returns:
## Parser Information ## Parser Information
Compatibility: linux, darwin, cygwin, aix, freebsd Compatibility: linux, darwin, cygwin, aix, freebsd
Version 1.4 by Kelly Brazil (kellyjonbrazil@gmail.com) Version 1.5 by Kelly Brazil (kellyjonbrazil@gmail.com)

View File

@ -135,4 +135,4 @@ Returns:
## Parser Information ## Parser Information
Compatibility: linux Compatibility: linux
Version 1.5 by Kelly Brazil (kellyjonbrazil@gmail.com) Version 1.6 by Kelly Brazil (kellyjonbrazil@gmail.com)

View File

@ -181,4 +181,4 @@ Returns:
## Parser Information ## Parser Information
Compatibility: linux Compatibility: linux
Version 1.2 by Kelly Brazil (kellyjonbrazil@gmail.com) Version 1.3 by Kelly Brazil (kellyjonbrazil@gmail.com)

View File

@ -126,4 +126,4 @@ Returns:
## Parser Information ## Parser Information
Compatibility: linux, darwin, aix, freebsd Compatibility: linux, darwin, aix, freebsd
Version 1.2 by Kelly Brazil (kellyjonbrazil@gmail.com) Version 1.3 by Kelly Brazil (kellyjonbrazil@gmail.com)

View File

@ -303,4 +303,4 @@ Returns:
## Parser Information ## Parser Information
Compatibility: linux Compatibility: linux
Version 1.3 by Kelly Brazil (kellyjonbrazil@gmail.com) Version 1.4 by Kelly Brazil (kellyjonbrazil@gmail.com)

View File

@ -193,4 +193,4 @@ Returns:
## Parser Information ## Parser Information
Compatibility: linux, darwin, freebsd Compatibility: linux, darwin, freebsd
Version 1.7 by Kelly Brazil (kellyjonbrazil@gmail.com) Version 1.8 by Kelly Brazil (kellyjonbrazil@gmail.com)

View File

@ -100,4 +100,4 @@ Returns:
## Parser Information ## Parser Information
Compatibility: linux Compatibility: linux
Version 1.4 by Kelly Brazil (kellyjonbrazil@gmail.com) Version 1.5 by Kelly Brazil (kellyjonbrazil@gmail.com)

232
docs/parsers/systeminfo.md Normal file
View File

@ -0,0 +1,232 @@
[Home](https://kellyjonbrazil.github.io/jc/)
# jc.parsers.systeminfo
jc - JSON CLI output utility `systeminfo` command output parser
Blank or missing elements are set to `null`.
The `original_install_date_epoch` and `system_boot_time_epoch` calculated timestamp fields are naive (i.e. based on the local time of the system the parser is run on)
The `original_install_date_epoch_utc` and `system_boot_time_epoch_utc` calculated timestamp fields are timezone-aware and are only available if the timezone field is UTC.
Usage (cli):
$ systeminfo | jc --systeminfo
Usage (module):
import jc.parsers.systeminfo
result = jc.parsers.systeminfo.parse(systeminfo_command_output)
Schema:
{
"host_name": string,
"os_name": string,
"os_version": string,
"os_manufacturer": string,
"os_configuration": string,
"os_build_type": string,
"registered_owner": string,
"registered_organization": string,
"product_id": string,
"original_install_date": string,
"original_install_date_epoch": integer, # naive timestamp
"original_install_date_epoch_utc": integer, # timezone-aware timestamp
"system_boot_time": string,
"system_boot_time_epoch": integer, # naive timestamp
"system_boot_time_epoch_utc": integer, # timezone-aware timestamp
"system_manufacturer": string,
"system_model": string,
"system_type": string,
"processors": [
string
],
"bios_version": string,
"windows_directory": string,
"system_directory": string,
"boot_device": string,
"system_locale": string,
"input_locale": string,
"time_zone": string,
"total_physical_memory_mb": string,
"available_physical_memory_mb": integer,
"virtual_memory_max_size_mb": integer,
"virtual_memory_available_mb": integer,
"virtual_memory_in_use_mb": integer,
"page_file_locations": string,
"domain": string,
"logon_server": string,
"hotfixs": [
string
],
"network_cards": [
{
"name": string,
"connection_name": string,
"status": string,
"dhcp_enabled": boolean,
"dhcp_server": string,
"ip_addresses": [
string
]
}
],
"hyperv_requirements": {
"vm_monitor_mode_extensions": boolean,
"virtualization_enabled_in_firmware": boolean,
"second_level_address_translation": boolean,
"data_execution_prevention_available": boolean
}
}
Examples:
$ systeminfo | jc --systeminfo -p
{
"host_name": "TESTLAPTOP",
"os_name": "Microsoft Windows 10 Enterprise",
"os_version": "10.0.17134 N/A Build 17134",
"os_manufacturer": "Microsoft Corporation",
"os_configuration": "Member Workstation",
"os_build_type": "Multiprocessor Free",
"registered_owner": "Test, Inc.",
"registered_organization": "Test, Inc.",
"product_id": "11111-11111-11111-AA111",
"original_install_date": "3/26/2019, 3:51:30 PM",
"system_boot_time": "3/30/2021, 6:13:59 AM",
"system_manufacturer": "Dell Inc.",
"system_model": "Precision 5530",
"system_type": "x64-based PC",
"processors": [
"Intel64 Family 6 Model 158 Stepping 10 GenuineIntel ~2592 Mhz"
],
"bios_version": "Dell Inc. 1.16.2, 4/21/2020",
"windows_directory": "C:\WINDOWS",
"system_directory": "C:\WINDOWS\system32",
"boot_device": "\Device\HarddiskVolume2",
"system_locale": "en-us;English (United States)",
"input_locale": "en-us;English (United States)",
"time_zone": "(UTC+00:00) UTC",
"total_physical_memory_mb": 32503,
"available_physical_memory_mb": 19743,
"virtual_memory_max_size_mb": 37367,
"virtual_memory_available_mb": 22266,
"virtual_memory_in_use_mb": 15101,
"page_file_locations": "C:\pagefile.sys",
"domain": "test.com",
"logon_server": "\\TESTDC01",
"hotfixs": [
"KB2693643",
"KB4601054"
],
"network_cards": [
{
"name": "Intel(R) Wireless-AC 9260 160MHz",
"connection_name": "Wi-Fi",
"status": null,
"dhcp_enabled": true,
"dhcp_server": "192.168.2.1",
"ip_addresses": [
"192.168.2.219"
]
}
],
"hyperv_requirements": {
"vm_monitor_mode_extensions": true,
"virtualization_enabled_in_firmware": true,
"second_level_address_translation": false,
"data_execution_prevention_available": true
},
"original_install_date_epoch": 1553640690,
"original_install_date_epoch_utc": 1553615490,
"system_boot_time_epoch": 1617110039,
"system_boot_time_epoch_utc": 1617084839
}
$ systeminfo | jc --systeminfo -p -r
{
"host_name": "TESTLAPTOP",
"os_name": "Microsoft Windows 10 Enterprise",
"os_version": "10.0.17134 N/A Build 17134",
"os_manufacturer": "Microsoft Corporation",
"os_configuration": "Member Workstation",
"os_build_type": "Multiprocessor Free",
"registered_owner": "Test, Inc.",
"registered_organization": "Test, Inc.",
"product_id": "11111-11111-11111-AA111",
"original_install_date": "3/26/2019, 3:51:30 PM",
"system_boot_time": "3/30/2021, 6:13:59 AM",
"system_manufacturer": "Dell Inc.",
"system_model": "Precision 5530",
"system_type": "x64-based PC",
"processors": [
"Intel64 Family 6 Model 158 Stepping 10 GenuineIntel ~2592 Mhz"
],
"bios_version": "Dell Inc. 1.16.2, 4/21/2020",
"windows_directory": "C:\WINDOWS",
"system_directory": "C:\WINDOWS\system32",
"boot_device": "\Device\HarddiskVolume2",
"system_locale": "en-us;English (United States)",
"input_locale": "en-us;English (United States)",
"time_zone": "(UTC+00:00) UTC",
"total_physical_memory_mb": "32,503 MB",
"available_physical_memory_mb": "19,743 MB",
"virtual_memory_max_size_mb": "37,367 MB",
"virtual_memory_available_mb": "22,266 MB",
"virtual_memory_in_use_mb": "15,101 MB",
"page_file_locations": "C:\pagefile.sys",
"domain": "test.com",
"logon_server": "\\TESTDC01",
"hotfixs": [
"KB2693643",
"KB4601054"
],
"network_cards": [
{
"name": "Intel(R) Wireless-AC 9260 160MHz",
"connection_name": "Wi-Fi",
"status": "",
"dhcp_enabled": "Yes",
"dhcp_server": "192.168.2.1",
"ip_addresses": [
"192.168.2.219"
]
}
],
"hyperv_requirements": {
"vm_monitor_mode_extensions": "Yes",
"virtualization_enabled_in_firmware": "Yes",
"second_level_address_translation": "No",
"data_execution_prevention_available": "Yes"
}
}
## info
```python
info()
```
Provides parser metadata (version, author, etc.)
## parse
```python
parse(data, raw=False, quiet=False)
```
Main text parsing function
Parameters:
data: (string) text data to parse
raw: (boolean) output preprocessed JSON if True
quiet: (boolean) suppress warning messages if True
Returns:
List of Dictionaries. Raw or processed structured data.
## Parser Information
Compatibility: win32
Version 1.0 by Jon Smith (jon@rebelliondefense.com)

View File

@ -148,4 +148,4 @@ Returns:
## Parser Information ## Parser Information
Compatibility: linux, darwin, cygwin, aix, freebsd Compatibility: linux, darwin, cygwin, aix, freebsd
Version 1.1 by Kelly Brazil (kellyjonbrazil@gmail.com) Version 1.2 by Kelly Brazil (kellyjonbrazil@gmail.com)

View File

@ -88,4 +88,4 @@ Returns:
## Parser Information ## Parser Information
Compatibility: linux Compatibility: linux
Version 1.3 by Kelly Brazil (kellyjonbrazil@gmail.com) Version 1.4 by Kelly Brazil (kellyjonbrazil@gmail.com)

View File

@ -156,4 +156,4 @@ Returns:
## Parser Information ## Parser Information
Compatibility: linux Compatibility: linux
Version 1.1 by Kelly Brazil (kellyjonbrazil@gmail.com) Version 1.2 by Kelly Brazil (kellyjonbrazil@gmail.com)

View File

@ -142,4 +142,4 @@ Returns:
## Parser Information ## Parser Information
Compatibility: linux, darwin, freebsd Compatibility: linux, darwin, freebsd
Version 1.2 by Kelly Brazil (kellyjonbrazil@gmail.com) Version 1.3 by Kelly Brazil (kellyjonbrazil@gmail.com)

View File

@ -219,4 +219,4 @@ Returns:
## Parser Information ## Parser Information
Compatibility: linux Compatibility: linux
Version 1.1 by Kelly Brazil (kellyjonbrazil@gmail.com) Version 1.2 by Kelly Brazil (kellyjonbrazil@gmail.com)

View File

@ -90,4 +90,4 @@ Returns:
## Parser Information ## Parser Information
Compatibility: linux, darwin, cygwin, aix, freebsd Compatibility: linux, darwin, cygwin, aix, freebsd
Version 1.4 by Kelly Brazil (kellyjonbrazil@gmail.com) Version 1.5 by Kelly Brazil (kellyjonbrazil@gmail.com)

View File

@ -79,4 +79,4 @@ Returns:
## Parser Information ## Parser Information
Compatibility: linux, darwin, cygwin, aix, freebsd Compatibility: linux, darwin, cygwin, aix, freebsd
Version 1.1 by Kelly Brazil (kellyjonbrazil@gmail.com) Version 1.2 by Kelly Brazil (kellyjonbrazil@gmail.com)

View File

@ -157,4 +157,4 @@ Returns:
## Parser Information ## Parser Information
Compatibility: linux, darwin, cygwin, aix, freebsd Compatibility: linux, darwin, cygwin, aix, freebsd
Version 1.3 by Kelly Brazil (kellyjonbrazil@gmail.com) Version 1.4 by Kelly Brazil (kellyjonbrazil@gmail.com)

View File

@ -10,62 +10,79 @@ For documentation on each parser, see the [documentation site](https://kellyjonb
CLI Example: CLI Example:
$ ls -l /usr/bin | jc --ls -p $ dig example.com | jc --dig -p
[ [
{ {
"filename": "apropos", "id": 2951,
"link_to": "whatis", "opcode": "QUERY",
"flags": "lrwxrwxrwx.", "status": "NOERROR",
"links": 1, "flags": [
"owner": "root", "qr",
"group": "root", "rd",
"size": 6, "ra"
"date": "Aug 15 10:53" ],
"query_num": 1,
"answer_num": 1,
"authority_num": 0,
"additional_num": 1,
"opt_pseudosection": {
"edns": {
"version": 0,
"flags": [],
"udp": 4096
}
}, },
"question": {
"name": "example.com.",
"class": "IN",
"type": "A"
},
"answer": [
{ {
"filename": "ar", "name": "example.com.",
"flags": "-rwxr-xr-x.", "class": "IN",
"links": 1, "type": "A",
"owner": "root", "ttl": 39302,
"group": "root", "data": "93.184.216.34"
"size": 62744, }
"date": "Aug 8 16:14" ],
}, "query_time": 49,
{ "server": "2600:1700:bab0:d40::1#53(2600:1700:bab0:d40::1)",
"filename": "arch", "when": "Fri Apr 16 16:05:10 PDT 2021",
"flags": "-rwxr-xr-x.", "rcvd": 56,
"links": 1, "when_epoch": 1618614310,
"owner": "root", "when_epoch_utc": null
"group": "root", }
"size": 33080,
"date": "Aug 19 23:25"
},
...
] ]
Module Example: Module Example:
>>> import jc.parsers.ls >>> import jc.parsers.dig
>>> >>>
>>> data='''-rwxr-xr-x 1 root wheel 23648 May 3 22:26 cat >>> data = '''; <<>> DiG 9.10.6 <<>> example.com
... -rwxr-xr-x 1 root wheel 30016 May 3 22:26 chmod ... ;; global options: +cmd
... -rwxr-xr-x 1 root wheel 29024 May 3 22:26 cp ... ;; Got answer:
... -rwxr-xr-x 1 root wheel 375824 May 3 22:26 csh ... ;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 64612
... -rwxr-xr-x 1 root wheel 28608 May 3 22:26 date ... ;; flags: qr rd ra; QUERY: 1, ANSWER: 1, AUTHORITY: 0, ADDITIONAL: 1
... -rwxr-xr-x 1 root wheel 32000 May 3 22:26 dd ...
... -rwxr-xr-x 1 root wheel 23392 May 3 22:26 df ... ;; OPT PSEUDOSECTION:
... -rwxr-xr-x 1 root wheel 18128 May 3 22:26 echo''' ... ; EDNS: version: 0, flags:; udp: 4096
... ;; QUESTION SECTION:
... ;example.com. IN A
...
... ;; ANSWER SECTION:
... example.com. 29658 IN A 93.184.216.34
...
... ;; Query time: 52 msec
... ;; SERVER: 2600:1700:bab0:d40::1#53(2600:1700:bab0:d40::1)
... ;; WHEN: Fri Apr 16 16:13:00 PDT 2021
... ;; MSG SIZE rcvd: 56'''
>>> >>>
>>> jc.parsers.ls.parse(data) >>> jc.parsers.dig.parse(data)
[{'filename': 'cat', 'flags': '-rwxr-xr-x', 'links': 1, 'owner': 'root', 'group': 'wheel', 'size': 23648, [{'id': 64612, 'opcode': 'QUERY', 'status': 'NOERROR', 'flags': ['qr', 'rd', 'ra'], 'query_num': 1, 'answer_num':
'date': 'May 3 22:26'}, {'filename': 'chmod', 'flags': '-rwxr-xr-x', 'links': 1, 'owner': 'root', 1, 'authority_num': 0, 'additional_num': 1, 'opt_pseudosection': {'edns': {'version': 0, 'flags': [], 'udp':
'group': 'wheel', 'size': 30016, 'date': 'May 3 22:26'}, {'filename': 'cp', 'flags': '-rwxr-xr-x', 4096}}, 'question': {'name': 'example.com.', 'class': 'IN', 'type': 'A'}, 'answer': [{'name': 'example.com.',
'links': 1, 'owner': 'root', 'group': 'wheel', 'size': 29024, 'date': 'May 3 22:26'}, {'filename': 'csh', 'class': 'IN', 'type': 'A', 'ttl': 29658, 'data': '93.184.216.34'}], 'query_time': 52, 'server':
'flags': '-rwxr-xr-x', 'links': 1, 'owner': 'root', 'group': 'wheel', 'size': 375824, 'date': 'May 3 '2600:1700:bab0:d40::1#53(2600:1700:bab0:d40::1)', 'when': 'Fri Apr 16 16:13:00 PDT 2021', 'rcvd': 56,
22:26'}, {'filename': 'date', 'flags': '-rwxr-xr-x', 'links': 1, 'owner': 'root', 'group': 'wheel', 'when_epoch': 1618614780, 'when_epoch_utc': None}]
'size': 28608, 'date': 'May 3 22:26'}, {'filename': 'dd', 'flags': '-rwxr-xr-x', 'links': 1, 'owner':
'root', 'group': 'wheel', 'size': 32000, 'date': 'May 3 22:26'}, {'filename': 'df', 'flags':
'-rwxr-xr-x', 'links': 1, 'owner': 'root', 'group': 'wheel', 'size': 23392, 'date': 'May 3 22:26'},
{'filename': 'echo', 'flags': '-rwxr-xr-x', 'links': 1, 'owner': 'root', 'group': 'wheel', 'size': 18128,
'date': 'May 3 22:26'}]

View File

@ -69,6 +69,54 @@ Returns:
Boolean True if input string (data) contains non-whitespace characters, otherwise False Boolean True if input string (data) contains non-whitespace characters, otherwise False
## convert_to_int
```python
convert_to_int(value)
```
Converts string input to integer by stripping all non-numeric characters
Parameters:
value: (string/integer/float) Input value
Returns:
integer/None Integer if successful conversion, otherwise None
## convert_to_float
```python
convert_to_float(value)
```
Converts string input to float by stripping all non-numeric characters
Parameters:
value: (string) Input value
Returns:
float/None Float if successful conversion, otherwise None
## convert_to_bool
```python
convert_to_bool(value)
```
Converts string, integer, or float input to boolean by checking for 'truthy' values
Parameters:
value: (string/integer/float) Input value
Returns:
True/False False unless a 'truthy' number or string is found ('y', 'yes', 'true', '1', 1, -1, etc.)
## timestamp ## timestamp
```python ```python
timestamp(datetime_string) timestamp(datetime_string)

View File

@ -8,65 +8,82 @@ For documentation on each parser, see the [documentation site](https://kellyjonb
CLI Example: CLI Example:
$ ls -l /usr/bin | jc --ls -p $ dig example.com | jc --dig -p
[ [
{ {
"filename": "apropos", "id": 2951,
"link_to": "whatis", "opcode": "QUERY",
"flags": "lrwxrwxrwx.", "status": "NOERROR",
"links": 1, "flags": [
"owner": "root", "qr",
"group": "root", "rd",
"size": 6, "ra"
"date": "Aug 15 10:53" ],
"query_num": 1,
"answer_num": 1,
"authority_num": 0,
"additional_num": 1,
"opt_pseudosection": {
"edns": {
"version": 0,
"flags": [],
"udp": 4096
}
}, },
"question": {
"name": "example.com.",
"class": "IN",
"type": "A"
},
"answer": [
{ {
"filename": "ar", "name": "example.com.",
"flags": "-rwxr-xr-x.", "class": "IN",
"links": 1, "type": "A",
"owner": "root", "ttl": 39302,
"group": "root", "data": "93.184.216.34"
"size": 62744, }
"date": "Aug 8 16:14" ],
}, "query_time": 49,
{ "server": "2600:1700:bab0:d40::1#53(2600:1700:bab0:d40::1)",
"filename": "arch", "when": "Fri Apr 16 16:05:10 PDT 2021",
"flags": "-rwxr-xr-x.", "rcvd": 56,
"links": 1, "when_epoch": 1618614310,
"owner": "root", "when_epoch_utc": null
"group": "root", }
"size": 33080,
"date": "Aug 19 23:25"
},
...
] ]
Module Example: Module Example:
>>> import jc.parsers.ls >>> import jc.parsers.dig
>>> >>>
>>> data='''-rwxr-xr-x 1 root wheel 23648 May 3 22:26 cat >>> data = '''; <<>> DiG 9.10.6 <<>> example.com
... -rwxr-xr-x 1 root wheel 30016 May 3 22:26 chmod ... ;; global options: +cmd
... -rwxr-xr-x 1 root wheel 29024 May 3 22:26 cp ... ;; Got answer:
... -rwxr-xr-x 1 root wheel 375824 May 3 22:26 csh ... ;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 64612
... -rwxr-xr-x 1 root wheel 28608 May 3 22:26 date ... ;; flags: qr rd ra; QUERY: 1, ANSWER: 1, AUTHORITY: 0, ADDITIONAL: 1
... -rwxr-xr-x 1 root wheel 32000 May 3 22:26 dd ...
... -rwxr-xr-x 1 root wheel 23392 May 3 22:26 df ... ;; OPT PSEUDOSECTION:
... -rwxr-xr-x 1 root wheel 18128 May 3 22:26 echo''' ... ; EDNS: version: 0, flags:; udp: 4096
... ;; QUESTION SECTION:
... ;example.com. IN A
...
... ;; ANSWER SECTION:
... example.com. 29658 IN A 93.184.216.34
...
... ;; Query time: 52 msec
... ;; SERVER: 2600:1700:bab0:d40::1#53(2600:1700:bab0:d40::1)
... ;; WHEN: Fri Apr 16 16:13:00 PDT 2021
... ;; MSG SIZE rcvd: 56'''
>>> >>>
>>> jc.parsers.ls.parse(data) >>> jc.parsers.dig.parse(data)
[{'filename': 'cat', 'flags': '-rwxr-xr-x', 'links': 1, 'owner': 'root', 'group': 'wheel', 'size': 23648, [{'id': 64612, 'opcode': 'QUERY', 'status': 'NOERROR', 'flags': ['qr', 'rd', 'ra'], 'query_num': 1, 'answer_num':
'date': 'May 3 22:26'}, {'filename': 'chmod', 'flags': '-rwxr-xr-x', 'links': 1, 'owner': 'root', 1, 'authority_num': 0, 'additional_num': 1, 'opt_pseudosection': {'edns': {'version': 0, 'flags': [], 'udp':
'group': 'wheel', 'size': 30016, 'date': 'May 3 22:26'}, {'filename': 'cp', 'flags': '-rwxr-xr-x', 4096}}, 'question': {'name': 'example.com.', 'class': 'IN', 'type': 'A'}, 'answer': [{'name': 'example.com.',
'links': 1, 'owner': 'root', 'group': 'wheel', 'size': 29024, 'date': 'May 3 22:26'}, {'filename': 'csh', 'class': 'IN', 'type': 'A', 'ttl': 29658, 'data': '93.184.216.34'}], 'query_time': 52, 'server':
'flags': '-rwxr-xr-x', 'links': 1, 'owner': 'root', 'group': 'wheel', 'size': 375824, 'date': 'May 3 '2600:1700:bab0:d40::1#53(2600:1700:bab0:d40::1)', 'when': 'Fri Apr 16 16:13:00 PDT 2021', 'rcvd': 56,
22:26'}, {'filename': 'date', 'flags': '-rwxr-xr-x', 'links': 1, 'owner': 'root', 'group': 'wheel', 'when_epoch': 1618614780, 'when_epoch_utc': None}]
'size': 28608, 'date': 'May 3 22:26'}, {'filename': 'dd', 'flags': '-rwxr-xr-x', 'links': 1, 'owner':
'root', 'group': 'wheel', 'size': 32000, 'date': 'May 3 22:26'}, {'filename': 'df', 'flags':
'-rwxr-xr-x', 'links': 1, 'owner': 'root', 'group': 'wheel', 'size': 23392, 'date': 'May 3 22:26'},
{'filename': 'echo', 'flags': '-rwxr-xr-x', 'links': 1, 'owner': 'root', 'group': 'wheel', 'size': 18128,
'date': 'May 3 22:26'}]
""" """
name = 'jc' name = 'jc'
__version__ = '1.15.1' __version__ = '1.15.2'

View File

@ -97,6 +97,7 @@ parsers = [
'systemctl-lj', 'systemctl-lj',
'systemctl-ls', 'systemctl-ls',
'systemctl-luf', 'systemctl-luf',
'systeminfo',
'time', 'time',
'timedatectl', 'timedatectl',
'tracepath', 'tracepath',
@ -319,27 +320,27 @@ def helptext():
{parsers_string} {parsers_string}
Options: Options:
-a about jc -a about jc
-d debug - show traceback (-dd for verbose traceback) -d debug (-dd for verbose debug)
-h help (use -h --parser_name for parser documentation) -h help (-h --parser_name for parser documentation)
-m monochrome output -m monochrome output
-p pretty print output -p pretty print output
-q quiet - suppress parser warnings -q quiet - suppress parser warnings
-r raw JSON output -r raw JSON output
-v version info -v version info
Example: Examples:
ls -al | jc --ls -p Standard Syntax:
$ dig www.google.com | jc --dig -p
or using the magic syntax: Magic Syntax:
$ jc -p dig www.google.com
jc -p ls -al Parser Documentation:
$ jc -h --dig
For parser documentation:
jc -h --ls
''' '''
return textwrap.dedent(helptext_string) return textwrap.dedent(helptext_string)
def help_doc(options): def help_doc(options):
""" """
Returns the parser documentation if a parser is found in the arguments, otherwise Returns the parser documentation if a parser is found in the arguments, otherwise
@ -362,6 +363,7 @@ Version {parser.info.version} by {parser.info.author} ({parser.info.author_email
return helptext() return helptext()
def versiontext(): def versiontext():
"""Return the version text""" """Return the version text"""
versiontext_string = f'''\ versiontext_string = f'''\

Binary file not shown.

View File

@ -227,7 +227,7 @@ import jc.utils
class info(): class info():
"""Provides parser metadata (version, author, etc.)""" """Provides parser metadata (version, author, etc.)"""
version = '1.1' version = '1.2'
description = '`acpi` command parser' description = '`acpi` command parser'
author = 'Kelly Brazil' author = 'Kelly Brazil'
author_email = 'kellyjonbrazil@gmail.com' author_email = 'kellyjonbrazil@gmail.com'
@ -256,38 +256,19 @@ def _process(proc_data):
float_list = ['temperature'] float_list = ['temperature']
for entry in proc_data: for entry in proc_data:
for key in int_list: for key in entry:
if key in entry: if key in int_list:
try: entry[key] = jc.utils.convert_to_int(entry[key])
entry[key] = int(entry[key]) if key in float_list:
except (ValueError): entry[key] = jc.utils.convert_to_float(entry[key])
entry[key] = None
if 'trip_points' in entry: if 'trip_points' in entry:
for tp in entry['trip_points']: for tp in entry['trip_points']:
for key in int_list: for key in tp:
if key in tp: if key in int_list:
try: tp[key] = jc.utils.convert_to_int(tp[key])
tp[key] = int(tp[key]) if key in float_list:
except (ValueError): tp[key] = jc.utils.convert_to_float(tp[key])
tp[key] = None
for entry in proc_data:
for key in float_list:
if key in entry:
try:
entry[key] = float(entry[key])
except (ValueError):
entry[key] = None
if 'trip_points' in entry:
for tp in entry['trip_points']:
for key in float_list:
if key in tp:
try:
tp[key] = float(tp[key])
except (ValueError):
tp[key] = None
for entry in proc_data: for entry in proc_data:
if 'until_charged' in entry: if 'until_charged' in entry:

View File

@ -80,7 +80,7 @@ import jc.utils
class info(): class info():
"""Provides parser metadata (version, author, etc.)""" """Provides parser metadata (version, author, etc.)"""
version = '1.2' version = '1.3'
description = '`airport -I` command parser' description = '`airport -I` command parser'
author = 'Kelly Brazil' author = 'Kelly Brazil'
author_email = 'kellyjonbrazil@gmail.com' author_email = 'kellyjonbrazil@gmail.com'
@ -111,10 +111,7 @@ def _process(proc_data):
'lasttxrate', 'maxrate', 'lastassocstatus', 'mcs'] 'lasttxrate', 'maxrate', 'lastassocstatus', 'mcs']
for key in proc_data: for key in proc_data:
if key in int_list: if key in int_list:
try: proc_data[key] = jc.utils.convert_to_int(proc_data[key])
proc_data[key] = int(proc_data[key])
except (ValueError):
proc_data[key] = None
return proc_data return proc_data

View File

@ -109,7 +109,7 @@ import jc.parsers.universal
class info(): class info():
"""Provides parser metadata (version, author, etc.)""" """Provides parser metadata (version, author, etc.)"""
version = '1.3' version = '1.4'
description = '`airport -s` command parser' description = '`airport -s` command parser'
author = 'Kelly Brazil' author = 'Kelly Brazil'
author_email = 'kellyjonbrazil@gmail.com' author_email = 'kellyjonbrazil@gmail.com'
@ -137,23 +137,14 @@ def _process(proc_data):
""" """
for entry in proc_data: for entry in proc_data:
# integers # convert integers and booleans
int_list = ['rssi'] int_list = ['rssi']
for key in int_list:
if key in entry:
try:
entry[key] = int(entry[key])
except (ValueError):
entry[key] = None
# booleans
bool_list = ['ht'] bool_list = ['ht']
for key in entry: for key in entry:
if key in int_list:
entry[key] = jc.utils.convert_to_int(entry[key])
if key in bool_list: if key in bool_list:
try: entry[key] = jc.utils.convert_to_bool(entry[key])
entry[key] = True if entry[key] == 'Y' else False
except (ValueError):
entry[key] = None
if 'security' in entry: if 'security' in entry:
entry['security'] = entry['security'].split() entry['security'] = entry['security'].split()

View File

@ -150,12 +150,9 @@ def _process(proc_data):
entry['name'] = None entry['name'] = None
int_list = ['expires'] int_list = ['expires']
for key in int_list: for key in entry:
if key in entry: if key in int_list:
try: entry[key] = jc.utils.convert_to_int(entry[key])
entry[key] = int(entry[key])
except (ValueError):
entry[key] = None
return proc_data return proc_data

View File

@ -121,7 +121,7 @@ import jc.utils
class info(): class info():
"""Provides parser metadata (version, author, etc.)""" """Provides parser metadata (version, author, etc.)"""
version = '1.3' version = '1.4'
description = '`blkid` command parser' description = '`blkid` command parser'
author = 'Kelly Brazil' author = 'Kelly Brazil'
author_email = 'kellyjonbrazil@gmail.com' author_email = 'kellyjonbrazil@gmail.com'
@ -155,12 +155,9 @@ def _process(proc_data):
'id_part_entry_offset', 'id_part_entry_size', 'minimum_io_size', 'physical_sector_size', 'id_part_entry_offset', 'id_part_entry_size', 'minimum_io_size', 'physical_sector_size',
'logical_sector_size', 'id_iolimit_minimum_io_size', 'id_iolimit_physical_sector_size', 'logical_sector_size', 'id_iolimit_minimum_io_size', 'id_iolimit_physical_sector_size',
'id_iolimit_logical_sector_size'] 'id_iolimit_logical_sector_size']
for key in int_list: for key in entry:
if key in entry: if key in int_list:
try: entry[key] = jc.utils.convert_to_int(entry[key])
entry[key] = int(entry[key])
except (ValueError):
entry[key] = None
return proc_data return proc_data

View File

@ -54,7 +54,7 @@ import jc.utils
class info(): class info():
"""Provides parser metadata (version, author, etc.)""" """Provides parser metadata (version, author, etc.)"""
version = '1.1' version = '1.2'
description = '`cksum` and `sum` command parser' description = '`cksum` and `sum` command parser'
author = 'Kelly Brazil' author = 'Kelly Brazil'
author_email = 'kellyjonbrazil@gmail.com' author_email = 'kellyjonbrazil@gmail.com'
@ -82,12 +82,10 @@ def _process(proc_data):
for entry in proc_data: for entry in proc_data:
int_list = ['checksum', 'blocks'] int_list = ['checksum', 'blocks']
for key in int_list: for key in entry:
if key in entry: if key in int_list:
try: entry[key] = jc.utils.convert_to_int(entry[key])
entry[key] = int(entry[key])
except (ValueError):
entry[key] = None
return proc_data return proc_data

View File

@ -98,7 +98,7 @@ import jc.parsers.universal
class info(): class info():
"""Provides parser metadata (version, author, etc.)""" """Provides parser metadata (version, author, etc.)"""
version = '1.6' version = '1.7'
description = '`df` command parser' description = '`df` command parser'
author = 'Kelly Brazil' author = 'Kelly Brazil'
author_email = 'kellyjonbrazil@gmail.com' author_email = 'kellyjonbrazil@gmail.com'
@ -144,11 +144,7 @@ def _process(proc_data):
# change any entry for key with '_blocks' in the name to int # change any entry for key with '_blocks' in the name to int
for k in entry: for k in entry:
if '_blocks' in str(k): if '_blocks' in str(k):
try: entry[k] = jc.utils.convert_to_int(entry[k])
blocks_int = int(entry[k])
entry[k] = blocks_int
except (ValueError):
entry[k] = None
# remove percent sign from 'use_percent', 'capacity_percent', and 'iused_percent' # remove percent sign from 'use_percent', 'capacity_percent', and 'iused_percent'
if 'use_percent' in entry: if 'use_percent' in entry:
@ -162,13 +158,9 @@ def _process(proc_data):
# change used, available, use_percent, capacity_percent, ifree, iused, iused_percent to int # change used, available, use_percent, capacity_percent, ifree, iused, iused_percent to int
int_list = ['used', 'available', 'use_percent', 'capacity_percent', 'ifree', 'iused', 'iused_percent'] int_list = ['used', 'available', 'use_percent', 'capacity_percent', 'ifree', 'iused', 'iused_percent']
for key in int_list: for key in entry:
if key in entry: if key in int_list:
try: entry[key] = jc.utils.convert_to_int(entry[key])
key_int = int(entry[key])
entry[key] = key_int
except (ValueError):
entry[key] = None
return proc_data return proc_data

View File

@ -40,6 +40,16 @@ Schema:
"data": string "data": string
} }
], ],
"opt_pseudosection": {
"edns": {
"version": integer,
"flags": [
string
],
"udp": integer
},
"cookie": string
},
"question": { "question": {
"name": string, "name": string,
"class": string, "class": string,
@ -54,6 +64,15 @@ Schema:
"data": string "data": string
} }
], ],
"additional": [
{
"name": string,
"class": string,
"type": string,
"ttl": integer,
"data": string
}
],
"authority": [ "authority": [
{ {
"name": string, "name": string,
@ -63,6 +82,7 @@ Schema:
"data": string "data": string
} }
], ],
"query_size": integer,
"query_time": integer, # in msec "query_time": integer, # in msec
"server": string, "server": string,
"when": string, "when": string,
@ -75,10 +95,10 @@ Schema:
Examples: Examples:
$ dig cnn.com www.cnn.com @205.251.194.64 | jc --dig -p $ dig example.com | jc --dig -p
[ [
{ {
"id": 52172, "id": 2951,
"opcode": "QUERY", "opcode": "QUERY",
"status": "NOERROR", "status": "NOERROR",
"flags": [ "flags": [
@ -87,113 +107,35 @@ Examples:
"ra" "ra"
], ],
"query_num": 1, "query_num": 1,
"answer_num": 4, "answer_num": 1,
"authority_num": 0, "authority_num": 0,
"additional_num": 1, "additional_num": 1,
"opt_pseudosection": {
"edns": {
"version": 0,
"flags": [],
"udp": 4096
}
},
"question": { "question": {
"name": "cnn.com.", "name": "example.com.",
"class": "IN", "class": "IN",
"type": "A" "type": "A"
}, },
"answer": [ "answer": [
{ {
"name": "cnn.com.", "name": "example.com.",
"class": "IN", "class": "IN",
"type": "A", "type": "A",
"ttl": 27, "ttl": 39302,
"data": "151.101.65.67" "data": "93.184.216.34"
},
{
"name": "cnn.com.",
"class": "IN",
"type": "A",
"ttl": 27,
"data": "151.101.129.67"
},
{
"name": "cnn.com.",
"class": "IN",
"type": "A",
"ttl": 27,
"data": "151.101.1.67"
},
{
"name": "cnn.com.",
"class": "IN",
"type": "A",
"ttl": 27,
"data": "151.101.193.67"
} }
], ],
"query_time": 38, "query_time": 49,
"server": "2600", "server": "2600:1700:bab0:d40::1#53(2600:1700:bab0:d40::1)",
"when": "Tue Mar 30 20:07:59 PDT 2021", "when": "Fri Apr 16 16:05:10 PDT 2021",
"rcvd": 100, "rcvd": 56,
"when_epoch": 1617160079, "when_epoch": 1618614310,
"when_epoch_utc": null
},
{
"id": 36292,
"opcode": "QUERY",
"status": "NOERROR",
"flags": [
"qr",
"aa",
"rd"
],
"query_num": 1,
"answer_num": 1,
"authority_num": 4,
"additional_num": 1,
"question": {
"name": "www.cnn.com.",
"class": "IN",
"type": "A"
},
"answer": [
{
"name": "www.cnn.com.",
"class": "IN",
"type": "CNAME",
"ttl": 300,
"data": "turner-tls.map.fastly.net."
}
],
"authority": [
{
"name": "cnn.com.",
"class": "IN",
"type": "NS",
"ttl": 3600,
"data": "ns-1086.awsdns-07.org."
},
{
"name": "cnn.com.",
"class": "IN",
"type": "NS",
"ttl": 3600,
"data": "ns-1630.awsdns-11.co.uk."
},
{
"name": "cnn.com.",
"class": "IN",
"type": "NS",
"ttl": 3600,
"data": "ns-47.awsdns-05.com."
},
{
"name": "cnn.com.",
"class": "IN",
"type": "NS",
"ttl": 3600,
"data": "ns-576.awsdns-08.net."
}
],
"query_time": 27,
"server": "205.251.194.64#53(205.251.194.64)",
"when": "Tue Mar 30 20:07:59 PDT 2021",
"rcvd": 212,
"when_epoch": 1617160079,
"when_epoch_utc": null "when_epoch_utc": null
} }
] ]
@ -201,7 +143,7 @@ Examples:
$ dig cnn.com www.cnn.com @205.251.194.64 | jc --dig -p -r $ dig cnn.com www.cnn.com @205.251.194.64 | jc --dig -p -r
[ [
{ {
"id": "23843", "id": "46052",
"opcode": "QUERY", "opcode": "QUERY",
"status": "NOERROR", "status": "NOERROR",
"flags": [ "flags": [
@ -210,117 +152,41 @@ Examples:
"ra" "ra"
], ],
"query_num": "1", "query_num": "1",
"answer_num": "4", "answer_num": "1",
"authority_num": "0", "authority_num": "0",
"additional_num": "1", "additional_num": "1",
"opt_pseudosection": {
"edns": {
"version": "0",
"flags": [],
"udp": "4096"
}
},
"question": { "question": {
"name": "cnn.com.", "name": "example.com.",
"class": "IN", "class": "IN",
"type": "A" "type": "A"
}, },
"answer": [ "answer": [
{ {
"name": "cnn.com.", "name": "example.com.",
"class": "IN", "class": "IN",
"type": "A", "type": "A",
"ttl": "30", "ttl": "40426",
"data": "151.101.193.67" "data": "93.184.216.34"
},
{
"name": "cnn.com.",
"class": "IN",
"type": "A",
"ttl": "30",
"data": "151.101.1.67"
},
{
"name": "cnn.com.",
"class": "IN",
"type": "A",
"ttl": "30",
"data": "151.101.65.67"
},
{
"name": "cnn.com.",
"class": "IN",
"type": "A",
"ttl": "30",
"data": "151.101.129.67"
} }
], ],
"query_time": "24 msec", "query_time": "48 msec",
"server": "192.168.1.254#53(192.168.1.254)", "server": "2600:1700:bab0:d40::1#53(2600:1700:bab0:d40::1)",
"when": "Tue Nov 12 07:16:19 PST 2019", "when": "Fri Apr 16 16:06:12 PDT 2021",
"rcvd": "100" "rcvd": "56"
},
{
"id": "8266",
"opcode": "QUERY",
"status": "NOERROR",
"flags": [
"qr",
"aa",
"rd"
],
"query_num": "1",
"answer_num": "1",
"authority_num": "4",
"additional_num": "1",
"question": {
"name": "www.cnn.com.",
"class": "IN",
"type": "A"
},
"answer": [
{
"name": "www.cnn.com.",
"class": "IN",
"type": "CNAME",
"ttl": "300",
"data": "turner-tls.map.fastly.net."
}
],
"authority": [
{
"name": "cnn.com.",
"class": "IN",
"type": "NS",
"ttl": "3600",
"data": "ns-1086.awsdns-07.org."
},
{
"name": "cnn.com.",
"class": "IN",
"type": "NS",
"ttl": "3600",
"data": "ns-1630.awsdns-11.co.uk."
},
{
"name": "cnn.com.",
"class": "IN",
"type": "NS",
"ttl": "3600",
"data": "ns-47.awsdns-05.com."
},
{
"name": "cnn.com.",
"class": "IN",
"type": "NS",
"ttl": "3600",
"data": "ns-576.awsdns-08.net."
}
],
"query_time": "26 msec",
"server": "205.251.194.64#53(205.251.194.64)",
"when": "Tue Nov 12 07:16:19 PST 2019",
"rcvd": "212"
} }
] ]
$ dig -x 1.1.1.1 | jc --dig -p $ dig -x 1.1.1.1 | jc --dig -p
[ [
{ {
"id": 22191, "id": 20785,
"opcode": "QUERY", "opcode": "QUERY",
"status": "NOERROR", "status": "NOERROR",
"flags": [ "flags": [
@ -332,6 +198,13 @@ Examples:
"answer_num": 1, "answer_num": 1,
"authority_num": 0, "authority_num": 0,
"additional_num": 1, "additional_num": 1,
"opt_pseudosection": {
"edns": {
"version": 0,
"flags": [],
"udp": 4096
}
},
"question": { "question": {
"name": "1.1.1.1.in-addr.arpa.", "name": "1.1.1.1.in-addr.arpa.",
"class": "IN", "class": "IN",
@ -346,11 +219,11 @@ Examples:
"data": "one.one.one.one." "data": "one.one.one.one."
} }
], ],
"query_time": 44, "query_time": 40,
"server": "2600", "server": "2600:1700:bab0:d40::1#53(2600:1700:bab0:d40::1)",
"when": "Tue Mar 30 20:10:34 PDT 2021", "when": "Sat Apr 17 14:50:50 PDT 2021",
"rcvd": 78, "rcvd": 78,
"when_epoch": 1617160234, "when_epoch": 1618696250,
"when_epoch_utc": null "when_epoch_utc": null
} }
] ]
@ -358,7 +231,7 @@ Examples:
$ dig -x 1.1.1.1 | jc --dig -p -r $ dig -x 1.1.1.1 | jc --dig -p -r
[ [
{ {
"id": "50986", "id": "32644",
"opcode": "QUERY", "opcode": "QUERY",
"status": "NOERROR", "status": "NOERROR",
"flags": [ "flags": [
@ -370,6 +243,13 @@ Examples:
"answer_num": "1", "answer_num": "1",
"authority_num": "0", "authority_num": "0",
"additional_num": "1", "additional_num": "1",
"opt_pseudosection": {
"edns": {
"version": "0",
"flags": [],
"udp": "4096"
}
},
"question": { "question": {
"name": "1.1.1.1.in-addr.arpa.", "name": "1.1.1.1.in-addr.arpa.",
"class": "IN", "class": "IN",
@ -384,9 +264,9 @@ Examples:
"data": "one.one.one.one." "data": "one.one.one.one."
} }
], ],
"query_time": "38 msec", "query_time": "52 msec",
"server": "2600", "server": "2600:1700:bab0:d40::1#53(2600:1700:bab0:d40::1)",
"when": "Tue Nov 12 07:17:19 PST 2019", "when": "Sat Apr 17 14:51:46 PDT 2021",
"rcvd": "78" "rcvd": "78"
} }
] ]
@ -396,7 +276,7 @@ import jc.utils
class info(): class info():
"""Provides parser metadata (version, author, etc.)""" """Provides parser metadata (version, author, etc.)"""
version = '1.7' version = '2.0'
description = '`dig` command parser' description = '`dig` command parser'
author = 'Kelly Brazil' author = 'Kelly Brazil'
author_email = 'kellyjonbrazil@gmail.com' author_email = 'kellyjonbrazil@gmail.com'
@ -421,47 +301,36 @@ def _process(proc_data):
List of Dictionaries. Structured data to conform to the schema. List of Dictionaries. Structured data to conform to the schema.
""" """
for entry in proc_data: for entry in proc_data:
int_list = ['id', 'query_num', 'answer_num', 'authority_num', 'additional_num', 'rcvd'] int_list = ['id', 'query_num', 'answer_num', 'authority_num', 'additional_num', 'rcvd',
for key in int_list: 'query_size', 'query_time']
if key in entry: for key in entry:
try: if key in int_list:
key_int = int(entry[key]) entry[key] = jc.utils.convert_to_int(entry[key])
entry[key] = key_int
except (ValueError):
entry[key] = None
if 'axfr' in entry: if 'axfr' in entry:
for ax in entry['axfr']: for ax in entry['axfr']:
try: ax['ttl'] = jc.utils.convert_to_int(ax['ttl'])
ttl_int = int(ax['ttl'])
ax['ttl'] = ttl_int if 'opt_pseudosection' in entry:
except (ValueError): if 'edns' in entry['opt_pseudosection']:
ax['ttl'] = None if 'version' in entry['opt_pseudosection']['edns']:
entry['opt_pseudosection']['edns']['version'] = jc.utils.convert_to_int(entry['opt_pseudosection']['edns']['version'])
if 'udp' in entry['opt_pseudosection']['edns']:
entry['opt_pseudosection']['edns']['udp'] = jc.utils.convert_to_int(entry['opt_pseudosection']['edns']['udp'])
if 'answer' in entry: if 'answer' in entry:
for ans in entry['answer']: for ans in entry['answer']:
try: ans['ttl'] = jc.utils.convert_to_int(ans['ttl'])
ttl_int = int(ans['ttl'])
ans['ttl'] = ttl_int if 'additional' in entry:
except (ValueError): for add in entry['additional']:
ans['ttl'] = None add['ttl'] = jc.utils.convert_to_int(add['ttl'])
if 'authority' in entry: if 'authority' in entry:
for auth in entry['authority']: for auth in entry['authority']:
try: auth['ttl'] = jc.utils.convert_to_int(auth['ttl'])
ttl_int = int(auth['ttl'])
auth['ttl'] = ttl_int
except (ValueError):
auth['ttl'] = None
if 'query_time' in entry:
try:
qt_int = int(entry['query_time'].split()[0])
entry['query_time'] = qt_int
except (ValueError):
entry['query_time'] = None
if 'when' in entry: if 'when' in entry:
ts = jc.utils.timestamp(entry['when']) ts = jc.utils.timestamp(entry['when'])
@ -507,6 +376,31 @@ def _parse_flags_line(flagsline):
'additional_num': additional_num} 'additional_num': additional_num}
def _parse_opt_pseudosection(optline):
# ;; OPT PSEUDOSECTION:
# ; EDNS: version: 0, flags:; udp: 4096
# ; COOKIE: 1cbc06703eaef210
if optline.startswith('; EDNS:'):
optline_list = optline.replace(',', ' ').split(';')
optline_first = optline_list[1]
optline_rest = optline_list[2]
_, _, ver, _, *flags = optline_first.split()
udp = optline_rest.split()[-1]
return {
'edns': {
'version': ver,
'flags': flags,
'udp': udp
}
}
elif optline.startswith('; COOKIE:'):
return {
'cookie': optline.split()[2]
}
def _parse_question(question): def _parse_question(question):
# ;www.cnn.com. IN A # ;www.cnn.com. IN A
question = question.split() question = question.split()
@ -519,22 +413,6 @@ def _parse_question(question):
'type': dns_type} 'type': dns_type}
def _parse_authority(authority):
# cnn.com. 3600 IN NS ns-1086.awsdns-07.org.
authority = authority.split()
authority_name = authority[0]
authority_class = authority[2]
authority_type = authority[3]
authority_ttl = authority[1]
authority_data = authority[4]
return {'name': authority_name,
'class': authority_class,
'type': authority_type,
'ttl': authority_ttl,
'data': authority_data}
def _parse_answer(answer): def _parse_answer(answer):
# www.cnn.com. 5 IN CNAME turner-tls.map.fastly.net. # www.cnn.com. 5 IN CNAME turner-tls.map.fastly.net.
answer = answer.split(maxsplit=4) answer = answer.split(maxsplit=4)
@ -574,6 +452,28 @@ def _parse_axfr(axfr):
'data': axfr_data} 'data': axfr_data}
def _parse_footer(footer):
# footer consists of 4 lines
# footer line 1
if footer.startswith(';; Query time:'):
return {'query_time': footer.split(':')[1].lstrip()}
# footer line 2
if footer.startswith(';; SERVER:'):
return {'server': footer.split(':', maxsplit=1)[1].lstrip()}
# footer line 3
if footer.startswith(';; WHEN:'):
return {'when': footer.split(':', maxsplit=1)[1].lstrip()}
# footer line 4 (last line)
if footer.startswith(';; MSG SIZE rcvd:'):
return {'rcvd': footer.split(':')[1].lstrip()}
elif footer.startswith(';; XFR size:'):
return {'size': footer.split(':')[1].lstrip()}
def parse(data, raw=False, quiet=False): def parse(data, raw=False, quiet=False):
""" """
Main text parsing function Main text parsing function
@ -597,104 +497,104 @@ def parse(data, raw=False, quiet=False):
# remove blank lines # remove blank lines
cleandata = list(filter(None, cleandata)) cleandata = list(filter(None, cleandata))
question = False # section can be: header, flags, question, authority, answer, axfr, additional, opt_pseudosection, footer
authority = False section = ''
answer = False
axfr = False
output_entry = {} output_entry = {}
if jc.utils.has_data(data): if jc.utils.has_data(data):
for line in cleandata: for line in cleandata:
# identify sections
if line.startswith(';; Got answer:'):
section = ''
continue
if line.startswith('; <<>> ') and ' axfr ' in line.lower(): if line.startswith('; <<>> ') and ' axfr ' in line.lower():
question = False section = 'axfr'
authority = False
answer = False
axfr = True
axfr_list = [] axfr_list = []
continue continue
if ';' not in line and axfr:
axfr_list.append(_parse_axfr(line))
output_entry.update({'axfr': axfr_list})
continue
if line.startswith(';; ->>HEADER<<-'): if line.startswith(';; ->>HEADER<<-'):
section = 'header'
if output_entry:
raw_output.append(output_entry)
output_entry = {} output_entry = {}
output_entry.update(_parse_header(line)) output_entry.update(_parse_header(line))
continue continue
if line.startswith(';; flags:'): if line.startswith(';; flags:'):
section = 'flags'
output_entry.update(_parse_flags_line(line)) output_entry.update(_parse_flags_line(line))
continue continue
if line.startswith(';; QUESTION SECTION:'): if line.startswith(';; OPT PSEUDOSECTION:'):
question = True section = 'opt_pseudosection'
authority = False
answer = False
axfr = False
continue continue
if question: if line.startswith(';; QUESTION SECTION:'):
output_entry['question'] = _parse_question(line) section = 'question'
question = False
authority = False
answer = False
axfr = False
continue continue
if line.startswith(';; AUTHORITY SECTION:'): if line.startswith(';; AUTHORITY SECTION:'):
question = False section = 'authority'
authority = True
answer = False
axfr = False
authority_list = [] authority_list = []
continue continue
if ';' not in line and authority:
authority_list.append(_parse_authority(line))
output_entry.update({'authority': authority_list})
continue
if line.startswith(';; ANSWER SECTION:'): if line.startswith(';; ANSWER SECTION:'):
question = False section = 'answer'
authority = False
answer = True
axfr = False
answer_list = [] answer_list = []
continue continue
if ';' not in line and answer: if line.startswith(';; ADDITIONAL SECTION:'):
section = 'additional'
additional_list = []
continue
if line.startswith(';; Query time:'):
section = 'footer'
output_entry.update(_parse_footer(line))
continue
# parse sections
if line.startswith(';; QUERY SIZE:'):
output_entry.update({'query_size': line.split(': ', maxsplit=1)[1]})
continue
if not line.startswith(';') and section == 'axfr':
axfr_list.append(_parse_axfr(line))
output_entry.update({'axfr': axfr_list})
continue
if section == 'opt_pseudosection':
if 'opt_pseudosection' not in output_entry:
output_entry['opt_pseudosection'] = {}
output_entry['opt_pseudosection'].update(_parse_opt_pseudosection(line))
continue
if section == 'question':
output_entry['question'] = _parse_question(line)
continue
if not line.startswith(';') and section == 'authority':
authority_list.append(_parse_answer(line))
output_entry.update({'authority': authority_list})
continue
if not line.startswith(';') and section == 'answer':
answer_list.append(_parse_answer(line)) answer_list.append(_parse_answer(line))
output_entry.update({'answer': answer_list}) output_entry.update({'answer': answer_list})
continue continue
# footer consists of 4 lines if not line.startswith(';') and section == 'additional':
# footer line 1 additional_list.append(_parse_answer(line))
if line.startswith(';; Query time:'): output_entry.update({'additional': additional_list})
output_entry.update({'query_time': line.split(':')[1].lstrip()})
continue continue
# footer line 2 if section == 'footer':
if line.startswith(';; SERVER:'): output_entry.update(_parse_footer(line))
output_entry.update({'server': line.split(':')[1].lstrip()})
continue continue
# footer line 3
if line.startswith(';; WHEN:'):
output_entry.update({'when': line.split(':', maxsplit=1)[1].lstrip()})
continue
# footer line 4 (last line)
if line.startswith(';; MSG SIZE rcvd:'):
output_entry.update({'rcvd': line.split(':')[1].lstrip()})
if output_entry:
raw_output.append(output_entry)
elif line.startswith(';; XFR size:'):
output_entry.update({'size': line.split(':')[1].lstrip()})
if output_entry: if output_entry:
raw_output.append(output_entry) raw_output.append(output_entry)

View File

@ -121,7 +121,7 @@ import jc.utils
class info(): class info():
"""Provides parser metadata (version, author, etc.)""" """Provides parser metadata (version, author, etc.)"""
version = '1.1' version = '1.2'
description = '`dir` command parser' description = '`dir` command parser'
author = 'Rasheed Elsaleh' author = 'Rasheed Elsaleh'
author_email = 'rasheed@rebelliondefense.com' author_email = 'rasheed@rebelliondefense.com'
@ -155,14 +155,9 @@ def _process(proc_data):
# add ints # add ints
int_list = ["size"] int_list = ["size"]
for key in int_list: for key in entry:
if entry.get(key): if key in int_list:
try: entry[key] = jc.utils.convert_to_int(entry[key])
key_int = int(entry[key].replace(",", ""))
except ValueError:
entry[key] = None
else:
entry[key] = key_int
return proc_data return proc_data

View File

@ -125,7 +125,7 @@ import jc.utils
class info(): class info():
"""Provides parser metadata (version, author, etc.)""" """Provides parser metadata (version, author, etc.)"""
version = '1.2' version = '1.3'
description = '`dmidecode` command parser' description = '`dmidecode` command parser'
author = 'Kelly Brazil' author = 'Kelly Brazil'
author_email = 'kellyjonbrazil@gmail.com' author_email = 'kellyjonbrazil@gmail.com'
@ -153,13 +153,9 @@ def _process(proc_data):
""" """
for entry in proc_data: for entry in proc_data:
int_list = ['type', 'bytes'] int_list = ['type', 'bytes']
for key in int_list: for key in entry:
if key in entry: if key in int_list:
try: entry[key] = jc.utils.convert_to_int(entry[key])
key_int = int(entry[key])
entry[key] = key_int
except (ValueError):
entry[key] = None
if not entry['values']: if not entry['values']:
entry['values'] = None entry['values'] = None

View File

@ -88,7 +88,7 @@ import jc.parsers.universal
class info(): class info():
"""Provides parser metadata (version, author, etc.)""" """Provides parser metadata (version, author, etc.)"""
version = '1.3' version = '1.4'
description = '`du` command parser' description = '`du` command parser'
author = 'Kelly Brazil' author = 'Kelly Brazil'
author_email = 'kellyjonbrazil@gmail.com' author_email = 'kellyjonbrazil@gmail.com'
@ -116,13 +116,9 @@ def _process(proc_data):
""" """
int_list = ['size'] int_list = ['size']
for entry in proc_data: for entry in proc_data:
for key in int_list: for key in entry:
if key in entry: if key in int_list:
try: entry[key] = jc.utils.convert_to_int(entry[key])
key_int = int(entry[key])
entry[key] = key_int
except (ValueError):
entry[key] = None
return proc_data return proc_data

View File

@ -66,6 +66,8 @@ def _process(proc_data):
""" """
# rebuild output for added semantic information # rebuild output for added semantic information
# use helper functions in jc.utils for int, float, bool conversions and timestamps
return proc_data return proc_data

View File

@ -73,7 +73,7 @@ import jc.parsers.universal
class info(): class info():
"""Provides parser metadata (version, author, etc.)""" """Provides parser metadata (version, author, etc.)"""
version = '1.3' version = '1.4'
description = '`free` command parser' description = '`free` command parser'
author = 'Kelly Brazil' author = 'Kelly Brazil'
author_email = 'kellyjonbrazil@gmail.com' author_email = 'kellyjonbrazil@gmail.com'
@ -101,13 +101,9 @@ def _process(proc_data):
for entry in proc_data: for entry in proc_data:
int_list = ['total', 'used', 'free', 'shared', 'buff_cache', 'available'] int_list = ['total', 'used', 'free', 'shared', 'buff_cache', 'available']
for key in int_list: for key in entry:
if key in entry: if key in int_list:
try: entry[key] = jc.utils.convert_to_int(entry[key])
key_int = int(entry[key])
entry[key] = key_int
except (ValueError):
entry[key] = None
return proc_data return proc_data

View File

@ -85,7 +85,7 @@ import jc.utils
class info(): class info():
"""Provides parser metadata (version, author, etc.)""" """Provides parser metadata (version, author, etc.)"""
version = '1.4' version = '1.5'
description = '`/etc/fstab` file parser' description = '`/etc/fstab` file parser'
author = 'Kelly Brazil' author = 'Kelly Brazil'
author_email = 'kellyjonbrazil@gmail.com' author_email = 'kellyjonbrazil@gmail.com'
@ -111,13 +111,9 @@ def _process(proc_data):
""" """
for entry in proc_data: for entry in proc_data:
int_list = ['fs_freq', 'fs_passno'] int_list = ['fs_freq', 'fs_passno']
for key in int_list: for key in entry:
if key in entry: if key in int_list:
try: entry[key] = jc.utils.convert_to_int(entry[key])
key_int = int(entry[key])
entry[key] = key_int
except (ValueError):
entry[key] = None
return proc_data return proc_data

View File

@ -109,7 +109,7 @@ import jc.utils
class info(): class info():
"""Provides parser metadata (version, author, etc.)""" """Provides parser metadata (version, author, etc.)"""
version = '1.2' version = '1.3'
description = '`/etc/group` file parser' description = '`/etc/group` file parser'
author = 'Kelly Brazil' author = 'Kelly Brazil'
author_email = 'kellyjonbrazil@gmail.com' author_email = 'kellyjonbrazil@gmail.com'
@ -136,13 +136,9 @@ def _process(proc_data):
""" """
for entry in proc_data: for entry in proc_data:
int_list = ['gid'] int_list = ['gid']
for key in int_list: for key in entry:
if key in entry: if key in int_list:
try: entry[key] = jc.utils.convert_to_int(entry[key])
key_int = int(entry[key])
entry[key] = key_int
except (ValueError):
entry[key] = None
if entry['members'] == ['']: if entry['members'] == ['']:
entry['members'] = [] entry['members'] = []

View File

@ -38,7 +38,7 @@ import jc.parsers.universal
class info(): class info():
"""Provides parser metadata (version, author, etc.)""" """Provides parser metadata (version, author, etc.)"""
version = '1.1' version = '1.2'
description = '`hash` command parser' description = '`hash` command parser'
author = 'Kelly Brazil' author = 'Kelly Brazil'
author_email = 'kellyjonbrazil@gmail.com' author_email = 'kellyjonbrazil@gmail.com'
@ -63,15 +63,10 @@ def _process(proc_data):
List of Dictionaries. Structured data to conform to the schema. List of Dictionaries. Structured data to conform to the schema.
""" """
for entry in proc_data: for entry in proc_data:
# change to int
int_list = ['hits'] int_list = ['hits']
for key in int_list: for key in entry:
if key in entry: if key in int_list:
try: entry[key] = jc.utils.convert_to_int(entry[key])
key_int = int(entry[key])
entry[key] = key_int
except (ValueError):
entry[key] = None
return proc_data return proc_data

View File

@ -317,7 +317,7 @@ import jc.utils
class info(): class info():
"""Provides parser metadata (version, author, etc.)""" """Provides parser metadata (version, author, etc.)"""
version = '1.1' version = '1.2'
description = '`hciconfig` command parser' description = '`hciconfig` command parser'
author = 'Kelly Brazil' author = 'Kelly Brazil'
author_email = 'kellyjonbrazil@gmail.com' author_email = 'kellyjonbrazil@gmail.com'
@ -346,15 +346,11 @@ def _process(proc_data):
for entry in proc_data: for entry in proc_data:
# integers
int_list = ['acl_mtu', 'acl_mtu_packets', 'sco_mtu', 'sco_mtu_packets', 'rx_bytes', 'rx_acl', 'rx_sco', int_list = ['acl_mtu', 'acl_mtu_packets', 'sco_mtu', 'sco_mtu_packets', 'rx_bytes', 'rx_acl', 'rx_sco',
'rx_events', 'rx_errors', 'tx_bytes', 'tx_acl', 'tx_sco', 'tx_commands', 'tx_errors'] 'rx_events', 'rx_errors', 'tx_bytes', 'tx_acl', 'tx_sco', 'tx_commands', 'tx_errors']
for key in int_list: for key in entry:
if key in entry: if key in int_list:
try: entry[key] = jc.utils.convert_to_int(entry[key])
entry[key] = int(entry[key])
except (ValueError):
entry[key] = None
if 'service_classes' in entry and len(entry['service_classes']) == 1 and 'Unspecified' in entry['service_classes']: if 'service_classes' in entry and len(entry['service_classes']) == 1 and 'Unspecified' in entry['service_classes']:
entry['service_classes'] = None entry['service_classes'] = None

View File

@ -57,7 +57,7 @@ import jc.utils
class info(): class info():
"""Provides parser metadata (version, author, etc.)""" """Provides parser metadata (version, author, etc.)"""
version = '1.4' version = '1.5'
description = '`history` command parser' description = '`history` command parser'
author = 'Kelly Brazil' author = 'Kelly Brazil'
author_email = 'kellyjonbrazil@gmail.com' author_email = 'kellyjonbrazil@gmail.com'
@ -82,12 +82,10 @@ def _process(proc_data):
List of Dictionaries. Structured data to conform to the schema. List of Dictionaries. Structured data to conform to the schema.
""" """
# rebuild output for added semantic information
processed = [] processed = []
for k, v in proc_data.items(): for k, v in proc_data.items():
proc_line = { proc_line = {
'line': int(k) if k.isdigit() else None, 'line': jc.utils.convert_to_int(k),
'command': v, 'command': v,
} }
processed.append(proc_line) processed.append(proc_line)

View File

@ -105,7 +105,7 @@ import jc.utils
class info(): class info():
"""Provides parser metadata (version, author, etc.)""" """Provides parser metadata (version, author, etc.)"""
version = '1.2' version = '1.3'
description = '`id` command parser' description = '`id` command parser'
author = 'Kelly Brazil' author = 'Kelly Brazil'
author_email = 'kellyjonbrazil@gmail.com' author_email = 'kellyjonbrazil@gmail.com'
@ -133,25 +133,16 @@ def _process(proc_data):
""" """
if 'uid' in proc_data: if 'uid' in proc_data:
if 'id' in proc_data['uid']: if 'id' in proc_data['uid']:
try: proc_data['uid']['id'] = jc.utils.convert_to_int(proc_data['uid']['id'])
proc_data['uid']['id'] = int(proc_data['uid']['id'])
except (ValueError):
proc_data['uid']['id'] = None
if 'gid' in proc_data: if 'gid' in proc_data:
if 'id' in proc_data['gid']: if 'id' in proc_data['gid']:
try: proc_data['gid']['id'] = jc.utils.convert_to_int(proc_data['gid']['id'])
proc_data['gid']['id'] = int(proc_data['gid']['id'])
except (ValueError):
proc_data['gid']['id'] = None
if 'groups' in proc_data: if 'groups' in proc_data:
for group in proc_data['groups']: for group in proc_data['groups']:
if 'id' in group: if 'id' in group:
try: group['id'] = jc.utils.convert_to_int(group['id'])
group['id'] = int(group['id'])
except (ValueError):
group['id'] = None
return proc_data return proc_data

View File

@ -188,7 +188,7 @@ import jc.utils
class info(): class info():
"""Provides parser metadata (version, author, etc.)""" """Provides parser metadata (version, author, etc.)"""
version = '1.9' version = '1.10'
description = '`ifconfig` command parser' description = '`ifconfig` command parser'
author = 'Kelly Brazil' author = 'Kelly Brazil'
author_email = 'kellyjonbrazil@gmail.com' author_email = 'kellyjonbrazil@gmail.com'
@ -264,7 +264,7 @@ class _IfconfigParser(object):
:return: :return:
""" """
for attr in kwargs.keys(): for attr in kwargs.keys():
if attr not in IfconfigParser.attributes: if attr not in _IfconfigParser.attributes:
raise ValueError("Attribute [{}] not supported.".format(attr)) raise ValueError("Attribute [{}] not supported.".format(attr))
filtered_interfaces = [] filtered_interfaces = []
@ -398,7 +398,8 @@ class _IfconfigParser(object):
if match: if match:
details = match.groupdict() details = match.groupdict()
for k, v in details.items(): for k, v in details.items():
if isinstance(v, str): details[k] = v.strip() if isinstance(v, str):
details[k] = v.strip()
_interface.update(details) _interface.update(details)
if _interface is not None: if _interface is not None:
available_interfaces[_interface['name']] = self.update_interface_details(_interface) available_interfaces[_interface['name']] = self.update_interface_details(_interface)
@ -433,13 +434,9 @@ def _process(proc_data):
int_list = ['flags', 'mtu', 'ipv6_mask', 'rx_packets', 'rx_bytes', 'rx_errors', 'rx_dropped', 'rx_overruns', int_list = ['flags', 'mtu', 'ipv6_mask', 'rx_packets', 'rx_bytes', 'rx_errors', 'rx_dropped', 'rx_overruns',
'rx_frame', 'tx_packets', 'tx_bytes', 'tx_errors', 'tx_dropped', 'tx_overruns', 'tx_carrier', 'rx_frame', 'tx_packets', 'tx_bytes', 'tx_errors', 'tx_dropped', 'tx_overruns', 'tx_carrier',
'tx_collisions', 'metric'] 'tx_collisions', 'metric']
for key in int_list: for key in entry:
if key in entry: if key in int_list:
try: entry[key] = jc.utils.convert_to_int(entry[key])
key_int = int(entry[key])
entry[key] = key_int
except (ValueError, TypeError):
entry[key] = None
# convert OSX-style subnet mask to dotted quad # convert OSX-style subnet mask to dotted quad
if 'ipv4_mask' in entry: if 'ipv4_mask' in entry:

View File

@ -163,7 +163,7 @@ import jc.utils
class info(): class info():
"""Provides parser metadata (version, author, etc.)""" """Provides parser metadata (version, author, etc.)"""
version = '1.5' version = '1.6'
description = '`iptables` command parser' description = '`iptables` command parser'
author = 'Kelly Brazil' author = 'Kelly Brazil'
author_email = 'kellyjonbrazil@gmail.com' author_email = 'kellyjonbrazil@gmail.com'
@ -191,13 +191,9 @@ def _process(proc_data):
for entry in proc_data: for entry in proc_data:
for rule in entry['rules']: for rule in entry['rules']:
int_list = ['num', 'pkts'] int_list = ['num', 'pkts']
for key in int_list: for key in rule:
if key in rule: if key in int_list:
try: rule[key] = jc.utils.convert_to_int(rule[key])
key_int = int(rule[key])
rule[key] = key_int
except (ValueError):
rule[key] = None
if 'bytes' in rule: if 'bytes' in rule:
multiplier = 1 multiplier = 1
@ -218,7 +214,7 @@ def _process(proc_data):
rule['bytes'] = rule['bytes'].rstrip('P') rule['bytes'] = rule['bytes'].rstrip('P')
try: try:
bytes_int = int(rule['bytes']) bytes_int = jc.utils.convert_to_int(rule['bytes'])
rule['bytes'] = bytes_int * multiplier rule['bytes'] = bytes_int * multiplier
except (ValueError): except (ValueError):
rule['bytes'] = None rule['bytes'] = None

View File

@ -95,7 +95,7 @@ import jc.utils
class info(): class info():
"""Provides parser metadata (version, author, etc.)""" """Provides parser metadata (version, author, etc.)"""
version = '1.3' version = '1.4'
description = '`jobs` command parser' description = '`jobs` command parser'
author = 'Kelly Brazil' author = 'Kelly Brazil'
author_email = 'kellyjonbrazil@gmail.com' author_email = 'kellyjonbrazil@gmail.com'
@ -122,13 +122,9 @@ def _process(proc_data):
""" """
for entry in proc_data: for entry in proc_data:
int_list = ['job_number', 'pid'] int_list = ['job_number', 'pid']
for key in int_list: for key in entry:
if key in entry: if key in int_list:
try: entry[key] = jc.utils.convert_to_int(entry[key])
key_int = int(entry[key])
entry[key] = key_int
except (ValueError):
entry[key] = None
return proc_data return proc_data

View File

@ -104,7 +104,7 @@ import jc.utils
class info(): class info():
"""Provides parser metadata (version, author, etc.)""" """Provides parser metadata (version, author, etc.)"""
version = '1.6' version = '1.7'
description = '`last` and `lastb` command parser' description = '`last` and `lastb` command parser'
author = 'Kelly Brazil' author = 'Kelly Brazil'
author_email = 'kellyjonbrazil@gmail.com' author_email = 'kellyjonbrazil@gmail.com'
@ -161,7 +161,7 @@ def _process(proc_data):
entry['logout_epoch'] = timestamp.naive entry['logout_epoch'] = timestamp.naive
if 'login_epoch' in entry and 'logout_epoch' in entry: if 'login_epoch' in entry and 'logout_epoch' in entry:
entry['duration_seconds'] = int(entry['logout_epoch']) - int(entry['login_epoch']) entry['duration_seconds'] = entry['logout_epoch'] - entry['login_epoch']
if 'duration' in entry and re.match(r'^\d+\+', entry['duration']): if 'duration' in entry and re.match(r'^\d+\+', entry['duration']):
m = re.match(r'^(?P<days>\d+)\+(?P<hours>\d\d):(?P<minutes>\d\d)', entry['duration']) m = re.match(r'^(?P<days>\d+)\+(?P<hours>\d\d):(?P<minutes>\d\d)', entry['duration'])

View File

@ -3,7 +3,6 @@
Options supported: Options supported:
- `lbaR1` - `lbaR1`
- `--time-style=full-iso` - `--time-style=full-iso`
- `-h`: File sizes will be available in text form with `-r` but larger file sizes with human readable suffixes will be converted to `Null` in the default view since the parser attempts to convert this field to an integer.
Note: The `-1`, `-l`, or `-b` option of `ls` should be used to correctly parse filenames that include newline characters. Since `ls` does not encode newlines in filenames when outputting to a pipe it will cause `jc` to see multiple files instead of a single file if `-1`, `-l`, or `-b` is not used. Alternatively, `vdir` can be used, which is the same as running `ls -lb`. Note: The `-1`, `-l`, or `-b` option of `ls` should be used to correctly parse filenames that include newline characters. Since `ls` does not encode newlines in filenames when outputting to a pipe it will cause `jc` to see multiple files instead of a single file if `-1`, `-l`, or `-b` is not used. Alternatively, `vdir` can be used, which is the same as running `ls -lb`.
@ -108,7 +107,7 @@ import jc.utils
class info(): class info():
"""Provides parser metadata (version, author, etc.)""" """Provides parser metadata (version, author, etc.)"""
version = '1.8' version = '1.9'
description = '`ls` command parser' description = '`ls` command parser'
author = 'Kelly Brazil' author = 'Kelly Brazil'
author_email = 'kellyjonbrazil@gmail.com' author_email = 'kellyjonbrazil@gmail.com'
@ -135,13 +134,9 @@ def _process(proc_data):
""" """
for entry in proc_data: for entry in proc_data:
int_list = ['links', 'size'] int_list = ['links', 'size']
for key in int_list: for key in entry:
if key in entry: if key in int_list:
try: entry[key] = jc.utils.convert_to_int(entry[key])
key_int = int(entry[key])
entry[key] = key_int
except (ValueError):
entry[key] = None
if 'date' in entry: if 'date' in entry:
# to speed up processing only try to convert the date if it's not the default format # to speed up processing only try to convert the date if it's not the default format

View File

@ -269,7 +269,7 @@ import jc.parsers.universal
class info(): class info():
"""Provides parser metadata (version, author, etc.)""" """Provides parser metadata (version, author, etc.)"""
version = '1.6' version = '1.7'
description = '`lsblk` command parser' description = '`lsblk` command parser'
author = 'Kelly Brazil' author = 'Kelly Brazil'
author_email = 'kellyjonbrazil@gmail.com' author_email = 'kellyjonbrazil@gmail.com'
@ -295,25 +295,14 @@ def _process(proc_data):
List of Dictionaries. Structured data to conform to the schema. List of Dictionaries. Structured data to conform to the schema.
""" """
for entry in proc_data: for entry in proc_data:
# boolean changes # boolean and integer changes
bool_list = ['rm', 'ro', 'rota', 'disc_zero', 'rand'] bool_list = ['rm', 'ro', 'rota', 'disc_zero', 'rand']
for key in bool_list:
if key in entry:
try:
key_bool = bool(int(entry[key]))
entry[key] = key_bool
except (ValueError):
entry[key] = None
# integer changes
int_list = ['ra', 'alignment', 'min_io', 'opt_io', 'phy_sec', 'log_sec', 'rq_size', 'disc_aln'] int_list = ['ra', 'alignment', 'min_io', 'opt_io', 'phy_sec', 'log_sec', 'rq_size', 'disc_aln']
for key in int_list: for key in entry:
if key in entry: if key in bool_list:
try: entry[key] = jc.utils.convert_to_bool(entry[key])
key_int = int(entry[key]) if key in int_list:
entry[key] = key_int entry[key] = jc.utils.convert_to_int(entry[key])
except (ValueError):
entry[key] = None
return proc_data return proc_data

View File

@ -126,7 +126,7 @@ import jc.parsers.universal
class info(): class info():
"""Provides parser metadata (version, author, etc.)""" """Provides parser metadata (version, author, etc.)"""
version = '1.4' version = '1.5'
description = '`lsmod` command parser' description = '`lsmod` command parser'
author = 'Kelly Brazil' author = 'Kelly Brazil'
author_email = 'kellyjonbrazil@gmail.com' author_email = 'kellyjonbrazil@gmail.com'
@ -152,15 +152,10 @@ def _process(proc_data):
List of Dictionaries. Structured data to conform to the schema. List of Dictionaries. Structured data to conform to the schema.
""" """
for entry in proc_data: for entry in proc_data:
# integer changes
int_list = ['size', 'used'] int_list = ['size', 'used']
for key in int_list: for key in entry:
if key in entry: if key in int_list:
try: entry[key] = jc.utils.convert_to_int(entry[key])
key_int = int(entry[key])
entry[key] = key_int
except (ValueError):
entry[key] = None
return proc_data return proc_data

View File

@ -120,7 +120,7 @@ import jc.parsers.universal
class info(): class info():
"""Provides parser metadata (version, author, etc.)""" """Provides parser metadata (version, author, etc.)"""
version = '1.3' version = '1.4'
description = '`lsof` command parser' description = '`lsof` command parser'
author = 'Kelly Brazil' author = 'Kelly Brazil'
author_email = 'kellyjonbrazil@gmail.com' author_email = 'kellyjonbrazil@gmail.com'
@ -146,15 +146,11 @@ def _process(proc_data):
List of Dictionaries. Structured data to conform to the schema. List of Dictionaries. Structured data to conform to the schema.
""" """
for entry in proc_data: for entry in proc_data:
# integer changes
int_list = ['pid', 'tid', 'size_off', 'node'] int_list = ['pid', 'tid', 'size_off', 'node']
for key in int_list: for key in entry:
if key in entry: if key in int_list:
try: entry[key] = jc.utils.convert_to_int(entry[key])
key_int = int(entry[key])
entry[key] = key_int
except (ValueError, TypeError):
entry[key] = None
return proc_data return proc_data

View File

@ -349,11 +349,12 @@ Examples:
} }
] ]
""" """
import jc.utils
class info(): class info():
"""Provides parser metadata (version, author, etc.)""" """Provides parser metadata (version, author, etc.)"""
version = '1.9' version = '1.10'
description = '`netstat` command parser' description = '`netstat` command parser'
author = 'Kelly Brazil' author = 'Kelly Brazil'
author_email = 'kellyjonbrazil@gmail.com' author_email = 'kellyjonbrazil@gmail.com'
@ -379,7 +380,7 @@ def _process(proc_data):
List of Dictionaries. Structured data to conform to the schema. List of Dictionaries. Structured data to conform to the schema.
""" """
for entry in proc_data: for entry in proc_data:
# integer changes # integer and float conversions
int_list = ['recv_q', 'send_q', 'pid', 'refcnt', 'inode', 'unit', 'vendor', 'class', int_list = ['recv_q', 'send_q', 'pid', 'refcnt', 'inode', 'unit', 'vendor', 'class',
'osx_flags', 'subcla', 'pcbcount', 'rcvbuf', 'sndbuf', 'rxbytes', 'txbytes', 'osx_flags', 'subcla', 'pcbcount', 'rcvbuf', 'sndbuf', 'rxbytes', 'txbytes',
'route_refs', 'use', 'mtu', 'mss', 'window', 'irtt', 'metric', 'ipkts', 'route_refs', 'use', 'mtu', 'mss', 'window', 'irtt', 'metric', 'ipkts',
@ -387,35 +388,23 @@ def _process(proc_data):
'tx_ok', 'tx_err', 'tx_drp', 'tx_ovr', 'idrop', 'ibytes', 'obytes', 'r_mbuf', 'tx_ok', 'tx_err', 'tx_drp', 'tx_ovr', 'idrop', 'ibytes', 'obytes', 'r_mbuf',
's_mbuf', 'r_clus', 's_clus', 'r_hiwa', 's_hiwa', 'r_lowa', 's_lowa', 'r_bcnt', 's_mbuf', 'r_clus', 's_clus', 'r_hiwa', 's_hiwa', 'r_lowa', 's_lowa', 'r_bcnt',
's_bcnt', 'r_bmax', 's_bmax', 'rexmit', 'ooorcv', '0_win'] 's_bcnt', 'r_bmax', 's_bmax', 'rexmit', 'ooorcv', '0_win']
for key in int_list:
if key in entry:
try:
key_int = int(entry[key])
entry[key] = key_int
except (ValueError):
entry[key] = None
# float changes
float_list = ['rexmt', 'persist', 'keep', '2msl', 'delack', 'rcvtime'] float_list = ['rexmt', 'persist', 'keep', '2msl', 'delack', 'rcvtime']
for key in float_list: for key in entry:
if key in entry: if key in int_list:
try: entry[key] = jc.utils.convert_to_int(entry[key])
key_float = float(entry[key]) if key in float_list:
entry[key] = key_float entry[key] = jc.utils.convert_to_float(entry[key])
except (ValueError):
entry[key] = None
# add number keys
if 'local_port' in entry: if 'local_port' in entry:
try: local_num = jc.utils.convert_to_int(entry['local_port'])
entry['local_port_num'] = int(entry['local_port']) if local_num:
except (ValueError): entry['local_port_num'] = local_num
pass
if 'foreign_port' in entry: if 'foreign_port' in entry:
try: foreign_num = jc.utils.convert_to_int(entry['foreign_port'])
entry['foreign_port_num'] = int(entry['foreign_port']) if foreign_num:
except (ValueError): entry['foreign_port_num'] = foreign_num
pass
return proc_data return proc_data

View File

@ -207,7 +207,7 @@ import jc.parsers.universal
class info(): class info():
"""Provides parser metadata (version, author, etc.)""" """Provides parser metadata (version, author, etc.)"""
version = '1.4' version = '1.5'
description = '`ntpq -p` command parser' description = '`ntpq -p` command parser'
author = 'Kelly Brazil' author = 'Kelly Brazil'
author_email = 'kellyjonbrazil@gmail.com' author_email = 'kellyjonbrazil@gmail.com'
@ -240,20 +240,12 @@ def _process(proc_data):
entry['state'] = entry.pop('s') entry['state'] = entry.pop('s')
int_list = ['st', 'when', 'poll', 'reach'] int_list = ['st', 'when', 'poll', 'reach']
for key in int_list:
if key in entry:
try:
entry[key] = int(entry[key])
except (ValueError):
entry[key] = None
float_list = ['delay', 'offset', 'jitter'] float_list = ['delay', 'offset', 'jitter']
for key in float_list: for key in entry:
if key in entry: if key in int_list:
try: entry[key] = jc.utils.convert_to_int(entry[key])
entry[key] = float(entry[key]) if key in float_list:
except (ValueError): entry[key] = jc.utils.convert_to_float(entry[key])
entry[key] = None
return proc_data return proc_data

View File

@ -94,7 +94,7 @@ import jc.utils
class info(): class info():
"""Provides parser metadata (version, author, etc.)""" """Provides parser metadata (version, author, etc.)"""
version = '1.2' version = '1.3'
description = '`/etc/passwd` file parser' description = '`/etc/passwd` file parser'
author = 'Kelly Brazil' author = 'Kelly Brazil'
author_email = 'kellyjonbrazil@gmail.com' author_email = 'kellyjonbrazil@gmail.com'
@ -121,13 +121,9 @@ def _process(proc_data):
""" """
for entry in proc_data: for entry in proc_data:
int_list = ['uid', 'gid'] int_list = ['uid', 'gid']
for key in int_list: for key in entry:
if key in entry: if key in int_list:
try: entry[key] = jc.utils.convert_to_int(entry[key])
key_int = int(entry[key])
entry[key] = key_int
except (ValueError):
entry[key] = None
return proc_data return proc_data

View File

@ -146,7 +146,7 @@ import jc.utils
class info(): class info():
"""Provides parser metadata (version, author, etc.)""" """Provides parser metadata (version, author, etc.)"""
version = '1.3' version = '1.4'
description = '`ping` and `ping6` command parser' description = '`ping` and `ping6` command parser'
author = 'Kelly Brazil' author = 'Kelly Brazil'
author_email = 'kellyjonbrazil@gmail.com' author_email = 'kellyjonbrazil@gmail.com'
@ -175,34 +175,20 @@ def _process(proc_data):
float_list = ['packet_loss_percent', 'round_trip_ms_min', 'round_trip_ms_avg', 'round_trip_ms_max', float_list = ['packet_loss_percent', 'round_trip_ms_min', 'round_trip_ms_avg', 'round_trip_ms_max',
'round_trip_ms_stddev', 'timestamp', 'time_ms'] 'round_trip_ms_stddev', 'timestamp', 'time_ms']
for key in proc_data.keys(): for key in proc_data:
for item in int_list: if key in int_list:
if item == key: proc_data[key] = jc.utils.convert_to_int(proc_data[key])
try:
proc_data[key] = int(proc_data[key])
except (ValueError, TypeError):
proc_data[key] = None
for item in float_list: if key in float_list:
if item == key: proc_data[key] = jc.utils.convert_to_float(proc_data[key])
try:
proc_data[key] = float(proc_data[key])
except (ValueError, TypeError):
proc_data[key] = None
if key == 'responses': if key == 'responses':
for entry in proc_data['responses']: for entry in proc_data['responses']:
for k in entry.keys(): for k in entry:
if k in int_list: if k in int_list:
try: entry[k] = jc.utils.convert_to_int(entry[k])
entry[k] = int(entry[k])
except (ValueError, TypeError):
entry[k] = None
if k in float_list: if k in float_list:
try: entry[k] = jc.utils.convert_to_float(entry[k])
entry[k] = float(entry[k])
except (ValueError, TypeError):
entry[k] = None
return proc_data return proc_data

View File

@ -207,7 +207,7 @@ import jc.parsers.universal
class info(): class info():
"""Provides parser metadata (version, author, etc.)""" """Provides parser metadata (version, author, etc.)"""
version = '1.4' version = '1.5'
description = '`ps` command parser' description = '`ps` command parser'
author = 'Kelly Brazil' author = 'Kelly Brazil'
author_email = 'kellyjonbrazil@gmail.com' author_email = 'kellyjonbrazil@gmail.com'
@ -241,26 +241,16 @@ def _process(proc_data):
if '%mem' in entry: if '%mem' in entry:
entry['mem_percent'] = entry.pop('%mem') entry['mem_percent'] = entry.pop('%mem')
# change to int # convert ints and floats
int_list = ['pid', 'ppid', 'c', 'vsz', 'rss'] int_list = ['pid', 'ppid', 'c', 'vsz', 'rss']
for key in int_list:
if key in entry:
try:
key_int = int(entry[key])
entry[key] = key_int
except (ValueError):
entry[key] = None
# change to float
float_list = ['cpu_percent', 'mem_percent'] float_list = ['cpu_percent', 'mem_percent']
for key in float_list: for key in entry:
if key in entry: if key in int_list:
try: entry[key] = jc.utils.convert_to_int(entry[key])
key_float = float(entry[key]) if key in float_list:
entry[key] = key_float entry[key] = jc.utils.convert_to_float(entry[key])
except (ValueError):
entry[key] = None
# clean up other fields
if 'tty' in entry: if 'tty' in entry:
if entry['tty'] == '?' or entry['tty'] == '??': if entry['tty'] == '?' or entry['tty'] == '??':
entry['tty'] = None entry['tty'] = None

View File

@ -111,7 +111,7 @@ import jc.parsers.universal
class info(): class info():
"""Provides parser metadata (version, author, etc.)""" """Provides parser metadata (version, author, etc.)"""
version = '1.5' version = '1.6'
description = '`route` command parser' description = '`route` command parser'
author = 'Kelly Brazil' author = 'Kelly Brazil'
author_email = 'kellyjonbrazil@gmail.com' author_email = 'kellyjonbrazil@gmail.com'
@ -138,13 +138,9 @@ def _process(proc_data):
""" """
for entry in proc_data: for entry in proc_data:
int_list = ['metric', 'ref', 'use', 'mss', 'window', 'irtt'] int_list = ['metric', 'ref', 'use', 'mss', 'window', 'irtt']
for key in int_list: for key in entry:
if key in entry: if key in int_list:
try: entry[key] = jc.utils.convert_to_int(entry[key])
key_int = int(entry[key])
entry[key] = key_int
except (ValueError):
entry[key] = None
# add flags_pretty # add flags_pretty
# Flag mapping from https://www.man7.org/linux/man-pages/man8/route.8.html # Flag mapping from https://www.man7.org/linux/man-pages/man8/route.8.html

View File

@ -156,7 +156,7 @@ import jc.utils
class info(): class info():
"""Provides parser metadata (version, author, etc.)""" """Provides parser metadata (version, author, etc.)"""
version = '1.2' version = '1.3'
description = '`rpm -qi` command parser' description = '`rpm -qi` command parser'
author = 'Kelly Brazil' author = 'Kelly Brazil'
author_email = 'kellyjonbrazil@gmail.com' author_email = 'kellyjonbrazil@gmail.com'
@ -185,12 +185,9 @@ def _process(proc_data):
for entry in proc_data: for entry in proc_data:
int_list = ['epoch', 'size'] int_list = ['epoch', 'size']
for key in int_list: for key in entry:
if key in entry: if key in int_list:
try: entry[key] = jc.utils.convert_to_int(entry[key])
entry[key] = int(entry[key])
except (ValueError):
entry[key] = None
if 'build_date' in entry: if 'build_date' in entry:
timestamp = jc.utils.timestamp(entry['build_date']) timestamp = jc.utils.timestamp(entry['build_date'])

View File

@ -101,7 +101,7 @@ import jc.utils
class info(): class info():
"""Provides parser metadata (version, author, etc.)""" """Provides parser metadata (version, author, etc.)"""
version = '1.2' version = '1.3'
description = '`/etc/shadow` file parser' description = '`/etc/shadow` file parser'
author = 'Kelly Brazil' author = 'Kelly Brazil'
author_email = 'kellyjonbrazil@gmail.com' author_email = 'kellyjonbrazil@gmail.com'
@ -128,13 +128,9 @@ def _process(proc_data):
""" """
for entry in proc_data: for entry in proc_data:
int_list = ['last_changed', 'minimum', 'maximum', 'warn', 'inactive', 'expire'] int_list = ['last_changed', 'minimum', 'maximum', 'warn', 'inactive', 'expire']
for key in int_list: for key in entry:
if key in entry: if key in int_list:
try: entry[key] = jc.utils.convert_to_int(entry[key])
key_int = int(entry[key])
entry[key] = key_int
except (ValueError):
entry[key] = None
return proc_data return proc_data

View File

@ -279,7 +279,7 @@ import jc.utils
class info(): class info():
"""Provides parser metadata (version, author, etc.)""" """Provides parser metadata (version, author, etc.)"""
version = '1.3' version = '1.4'
description = '`ss` command parser' description = '`ss` command parser'
author = 'Kelly Brazil' author = 'Kelly Brazil'
author_email = 'kellyjonbrazil@gmail.com' author_email = 'kellyjonbrazil@gmail.com'
@ -306,25 +306,19 @@ def _process(proc_data):
""" """
for entry in proc_data: for entry in proc_data:
int_list = ['recv_q', 'send_q', 'pid'] int_list = ['recv_q', 'send_q', 'pid']
for key in int_list: for key in entry:
if key in entry: if key in int_list:
try: entry[key] = jc.utils.convert_to_int(entry[key])
key_int = int(entry[key])
entry[key] = key_int
except (ValueError):
entry[key] = None
if 'local_port' in entry: if 'local_port' in entry:
try: local_num = jc.utils.convert_to_int(entry['local_port'])
entry['local_port_num'] = int(entry['local_port']) if local_num is not None and local_num >= 0:
except (ValueError): entry['local_port_num'] = local_num
pass
if 'peer_port' in entry: if 'peer_port' in entry:
try: peer_num = jc.utils.convert_to_int(entry['peer_port'])
entry['peer_port_num'] = int(entry['peer_port']) if peer_num is not None and peer_num >= 0:
except (ValueError): entry['peer_port_num'] = peer_num
pass
return proc_data return proc_data

View File

@ -169,7 +169,7 @@ import jc.utils
class info(): class info():
"""Provides parser metadata (version, author, etc.)""" """Provides parser metadata (version, author, etc.)"""
version = '1.7' version = '1.8'
description = '`stat` command parser' description = '`stat` command parser'
author = 'Kelly Brazil' author = 'Kelly Brazil'
author_email = 'kellyjonbrazil@gmail.com' author_email = 'kellyjonbrazil@gmail.com'
@ -195,14 +195,11 @@ def _process(proc_data):
List of Dictionaries. Structured data to conform to the schema. List of Dictionaries. Structured data to conform to the schema.
""" """
for entry in proc_data: for entry in proc_data:
int_list = ['size', 'blocks', 'io_blocks', 'inode', 'links', 'uid', 'gid', 'unix_device', 'rdev', 'block_size'] int_list = ['size', 'blocks', 'io_blocks', 'inode', 'links', 'uid', 'gid', 'unix_device',
for key in int_list: 'rdev', 'block_size']
if key in entry: for key in entry:
try: if key in int_list:
key_int = int(entry[key]) entry[key] = jc.utils.convert_to_int(entry[key])
entry[key] = key_int
except (ValueError):
entry[key] = None
# turn - into null for time fields and add calculated timestamp fields # turn - into null for time fields and add calculated timestamp fields
for entry in proc_data: for entry in proc_data:

View File

@ -75,7 +75,7 @@ import jc.utils
class info(): class info():
"""Provides parser metadata (version, author, etc.)""" """Provides parser metadata (version, author, etc.)"""
version = '1.4' version = '1.5'
description = '`systemctl list-jobs` command parser' description = '`systemctl list-jobs` command parser'
author = 'Kelly Brazil' author = 'Kelly Brazil'
author_email = 'kellyjonbrazil@gmail.com' author_email = 'kellyjonbrazil@gmail.com'
@ -102,13 +102,10 @@ def _process(proc_data):
""" """
for entry in proc_data: for entry in proc_data:
int_list = ['job'] int_list = ['job']
for key in int_list: for key in entry:
if key in entry: if key in int_list:
try: entry[key] = jc.utils.convert_to_int(entry[key])
key_int = int(entry[key])
entry[key] = key_int
except (ValueError):
entry[key] = None
return proc_data return proc_data

528
jc/parsers/systeminfo.py Normal file
View File

@ -0,0 +1,528 @@
"""jc - JSON CLI output utility `systeminfo` command output parser
Blank or missing elements are set to `null`.
The `original_install_date_epoch` and `system_boot_time_epoch` calculated timestamp fields are naive (i.e. based on the local time of the system the parser is run on)
The `original_install_date_epoch_utc` and `system_boot_time_epoch_utc` calculated timestamp fields are timezone-aware and are only available if the timezone field is UTC.
Usage (cli):
$ systeminfo | jc --systeminfo
Usage (module):
import jc.parsers.systeminfo
result = jc.parsers.systeminfo.parse(systeminfo_command_output)
Schema:
{
"host_name": string,
"os_name": string,
"os_version": string,
"os_manufacturer": string,
"os_configuration": string,
"os_build_type": string,
"registered_owner": string,
"registered_organization": string,
"product_id": string,
"original_install_date": string,
"original_install_date_epoch": integer, # naive timestamp
"original_install_date_epoch_utc": integer, # timezone-aware timestamp
"system_boot_time": string,
"system_boot_time_epoch": integer, # naive timestamp
"system_boot_time_epoch_utc": integer, # timezone-aware timestamp
"system_manufacturer": string,
"system_model": string,
"system_type": string,
"processors": [
string
],
"bios_version": string,
"windows_directory": string,
"system_directory": string,
"boot_device": string,
"system_locale": string,
"input_locale": string,
"time_zone": string,
"total_physical_memory_mb": string,
"available_physical_memory_mb": integer,
"virtual_memory_max_size_mb": integer,
"virtual_memory_available_mb": integer,
"virtual_memory_in_use_mb": integer,
"page_file_locations": string,
"domain": string,
"logon_server": string,
"hotfixs": [
string
],
"network_cards": [
{
"name": string,
"connection_name": string,
"status": string,
"dhcp_enabled": boolean,
"dhcp_server": string,
"ip_addresses": [
string
]
}
],
"hyperv_requirements": {
"vm_monitor_mode_extensions": boolean,
"virtualization_enabled_in_firmware": boolean,
"second_level_address_translation": boolean,
"data_execution_prevention_available": boolean
}
}
Examples:
$ systeminfo | jc --systeminfo -p
{
"host_name": "TESTLAPTOP",
"os_name": "Microsoft Windows 10 Enterprise",
"os_version": "10.0.17134 N/A Build 17134",
"os_manufacturer": "Microsoft Corporation",
"os_configuration": "Member Workstation",
"os_build_type": "Multiprocessor Free",
"registered_owner": "Test, Inc.",
"registered_organization": "Test, Inc.",
"product_id": "11111-11111-11111-AA111",
"original_install_date": "3/26/2019, 3:51:30 PM",
"system_boot_time": "3/30/2021, 6:13:59 AM",
"system_manufacturer": "Dell Inc.",
"system_model": "Precision 5530",
"system_type": "x64-based PC",
"processors": [
"Intel64 Family 6 Model 158 Stepping 10 GenuineIntel ~2592 Mhz"
],
"bios_version": "Dell Inc. 1.16.2, 4/21/2020",
"windows_directory": "C:\\WINDOWS",
"system_directory": "C:\\WINDOWS\\system32",
"boot_device": "\\Device\\HarddiskVolume2",
"system_locale": "en-us;English (United States)",
"input_locale": "en-us;English (United States)",
"time_zone": "(UTC+00:00) UTC",
"total_physical_memory_mb": 32503,
"available_physical_memory_mb": 19743,
"virtual_memory_max_size_mb": 37367,
"virtual_memory_available_mb": 22266,
"virtual_memory_in_use_mb": 15101,
"page_file_locations": "C:\\pagefile.sys",
"domain": "test.com",
"logon_server": "\\\\TESTDC01",
"hotfixs": [
"KB2693643",
"KB4601054"
],
"network_cards": [
{
"name": "Intel(R) Wireless-AC 9260 160MHz",
"connection_name": "Wi-Fi",
"status": null,
"dhcp_enabled": true,
"dhcp_server": "192.168.2.1",
"ip_addresses": [
"192.168.2.219"
]
}
],
"hyperv_requirements": {
"vm_monitor_mode_extensions": true,
"virtualization_enabled_in_firmware": true,
"second_level_address_translation": false,
"data_execution_prevention_available": true
},
"original_install_date_epoch": 1553640690,
"original_install_date_epoch_utc": 1553615490,
"system_boot_time_epoch": 1617110039,
"system_boot_time_epoch_utc": 1617084839
}
$ systeminfo | jc --systeminfo -p -r
{
"host_name": "TESTLAPTOP",
"os_name": "Microsoft Windows 10 Enterprise",
"os_version": "10.0.17134 N/A Build 17134",
"os_manufacturer": "Microsoft Corporation",
"os_configuration": "Member Workstation",
"os_build_type": "Multiprocessor Free",
"registered_owner": "Test, Inc.",
"registered_organization": "Test, Inc.",
"product_id": "11111-11111-11111-AA111",
"original_install_date": "3/26/2019, 3:51:30 PM",
"system_boot_time": "3/30/2021, 6:13:59 AM",
"system_manufacturer": "Dell Inc.",
"system_model": "Precision 5530",
"system_type": "x64-based PC",
"processors": [
"Intel64 Family 6 Model 158 Stepping 10 GenuineIntel ~2592 Mhz"
],
"bios_version": "Dell Inc. 1.16.2, 4/21/2020",
"windows_directory": "C:\\WINDOWS",
"system_directory": "C:\\WINDOWS\\system32",
"boot_device": "\\Device\\HarddiskVolume2",
"system_locale": "en-us;English (United States)",
"input_locale": "en-us;English (United States)",
"time_zone": "(UTC+00:00) UTC",
"total_physical_memory_mb": "32,503 MB",
"available_physical_memory_mb": "19,743 MB",
"virtual_memory_max_size_mb": "37,367 MB",
"virtual_memory_available_mb": "22,266 MB",
"virtual_memory_in_use_mb": "15,101 MB",
"page_file_locations": "C:\\pagefile.sys",
"domain": "test.com",
"logon_server": "\\\\TESTDC01",
"hotfixs": [
"KB2693643",
"KB4601054"
],
"network_cards": [
{
"name": "Intel(R) Wireless-AC 9260 160MHz",
"connection_name": "Wi-Fi",
"status": "",
"dhcp_enabled": "Yes",
"dhcp_server": "192.168.2.1",
"ip_addresses": [
"192.168.2.219"
]
}
],
"hyperv_requirements": {
"vm_monitor_mode_extensions": "Yes",
"virtualization_enabled_in_firmware": "Yes",
"second_level_address_translation": "No",
"data_execution_prevention_available": "Yes"
}
}
"""
import re
import jc.utils
class info:
"""Provides parser metadata (version, author, etc.)"""
version = "1.0"
description = "`systeminfo` command parser"
author = "Jon Smith"
author_email = "jon@rebelliondefense.com"
# details = 'enter any other details here'
# compatible options: linux, darwin, cygwin, win32, aix, freebsd
compatible = ["win32"]
magic_commands = ["systeminfo"]
__version__ = info.version
def _process(proc_data):
"""
Final processing to conform to the schema.
Parameters:
proc_data: (Dictionary) raw structured data to process
Returns:
Dictionary. Some keys are optional. Example: a system without hyper-v capabilities
will not have a 'hyperv_requirements' key, and a system already running hyper-v
will have an empty "hyperv_requirements" object.
Structured data to conform to the schema.
"""
# convert empty strings to None/null
for item in proc_data:
if isinstance(proc_data[item], str) and not proc_data[item]:
proc_data[item] = None
for i, nic in enumerate(proc_data["network_cards"]):
proc_data["network_cards"][i]["dhcp_enabled"] = jc.utils.convert_to_bool(
nic["dhcp_enabled"]
)
# convert empty strings to None/null
for item in nic:
if isinstance(nic[item], str) and not nic[item]:
proc_data["network_cards"][i][item] = None
int_list = [
"total_physical_memory_mb",
"available_physical_memory_mb",
"virtual_memory_max_size_mb",
"virtual_memory_available_mb",
"virtual_memory_in_use_mb",
]
for key in int_list:
proc_data[key] = jc.utils.convert_to_int(proc_data[key])
dt_list = ["original_install_date", "system_boot_time"]
for key in dt_list:
tz = proc_data.get("time_zone", "")
if tz:
# convert
# from: (UTC-08:00) Pacific Time (US & Canada)
# to: (UTC-0800)
tz_fields = tz.split()
tz = " " + tz_fields[0].replace(":", "")
proc_data[key + '_epoch'] = jc.utils.timestamp(f"{proc_data.get(key)}{tz}").naive
proc_data[key + '_epoch_utc'] = jc.utils.timestamp(f"{proc_data.get(key)}{tz}").utc
hyperv_key = "hyperv_requirements"
hyperv_subkey_list = [
"vm_monitor_mode_extensions",
"virtualization_enabled_in_firmware",
"second_level_address_translation",
"data_execution_prevention_available",
]
if hyperv_key in proc_data:
for key in hyperv_subkey_list:
if key in proc_data[hyperv_key]:
proc_data[hyperv_key][key] = jc.utils.convert_to_bool(
proc_data[hyperv_key][key]
)
return proc_data
def parse(data, raw=False, quiet=False):
"""
Main text parsing function
Parameters:
data: (string) text data to parse
raw: (boolean) output preprocessed JSON if True
quiet: (boolean) suppress warning messages if True
Returns:
List of Dictionaries. Raw or processed structured data.
"""
if not quiet:
jc.utils.compatibility(__name__, info.compatible)
delim = ":" # k/v delimiter
raw_data = {} # intermediary output
if jc.utils.has_data(data):
# keepends = True, so that multiline data retains return chars
lines = [line for line in data.splitlines(keepends=True) if line.strip() != ""]
# find the character position of the value in the k/v pair of the first line
# all subsequent lines of data use the same character position
start_value_pos = _get_value_pos(lines[0], delim)
last_key = None
for line in lines:
key = line[0:start_value_pos]
value = line[start_value_pos:]
# possible multiline data
if last_key:
# the value data doesn't start where it should
# so this is multiline data
if delim not in key:
raw_data[last_key] += line
continue
raw_data[key] = value
last_key = key
# clean up keys; strip values
raw_output = {}
for k, v in raw_data.items():
k = _transform_key(k)
# since we split on start_value_pos, the delimiter
# is still in the key field. Remove it.
k = k.rstrip(delim)
if k in ["hotfixs", "processors"]:
raw_output[k] = _parse_hotfixs_or_processors(v)
elif k in ["network_cards"]:
raw_output[k] = _parse_network_cards(v)
elif k in ["hyperv_requirements"]:
raw_output[k] = _parse_hyperv_requirements(v)
elif k in [
"total_physical_memory",
"available_physical_memory",
"virtual_memory_max_size",
"virtual_memory_available",
"virtual_memory_in_use"
]:
raw_output[k + "_mb"] = v.strip()
else:
raw_output[k] = v.strip()
if raw:
return raw_output
else:
return _process(raw_output)
def _parse_hotfixs_or_processors(data):
"""
Turns a list of return-delimited hotfixes or processors
with [x] as a prefix into an array of hotfixes
Note that if a high number of items exist, the list may cutoff
and this list may not contain all items installed on the system
IRL, this likely applies to hotfixes more than processors
Parameters:
data: (string) Input string
"""
arr_output = []
for i, l in enumerate(data.splitlines()):
# skip line that says how many are installed
if i == 0:
continue
# we have to make sure this is a complete line
# as data could cutoff. Make sure the delimiter
# exists. Otherwise, skip it.
if ":" in l:
k, v = l.split(":")
# discard the number sequence
arr_output.append(v.strip())
return arr_output
def _parse_hyperv_requirements(data):
"""
Turns a list of key/value settings for hyperv
into an object
Parameters:
data: (string) Input string
"""
output = {}
for i, l in enumerate(data.splitlines()):
if ":" in l:
k, v = l.split(":")
# discard the number sequence
output[_transform_key(k)] = v.strip()
return output
def _parse_network_cards(data):
"""
Turns a list of network_cards into an array of objects
Parameters:
data: (string) Input string
"""
delim = ":"
arr_output = []
cur_nic = None
is_ip = False
nic_value_pos = 0
for i, line in enumerate(data.splitlines()):
# skip first line
if i == 0:
continue
if "IP address(es)" in line:
is_ip = True
continue
cur_value_pos = len(line) - len(line.lstrip())
line = line.strip()
m = re.match(r"\[(\d+)\]" + delim + "(.+)", line)
if m and is_ip and cur_value_pos > nic_value_pos:
cur_nic["ip_addresses"].append(m.group(2).strip())
elif m:
if cur_nic:
arr_output.append(cur_nic)
cur_nic = _default_nic()
cur_nic["name"] = m.group(2).strip()
nic_value_pos = cur_value_pos
is_ip = False
elif delim in line:
k, v = line.split(delim)
k = _transform_key(k)
cur_nic[k] = v.strip()
if cur_nic:
arr_output.append(cur_nic)
return arr_output
def _convert_to_boolean(value):
"""
Converts string input to boolean assuming "Yes/No" inputs
Parameters:
value: (string) Input value
"""
return value == "Yes"
def _convert_to_int(value):
"""
Converts string input to integer by stripping all non-numeric characters
Parameters:
value: (string) Input value
"""
try:
value = int(re.sub("[^0-9]", "", value))
except ValueError:
pass
return value
def _default_nic():
"""
Returns a default network card object
"""
return {
"name": "",
"connection_name": "",
"status": "",
"dhcp_enabled": "No",
"dhcp_server": "",
"ip_addresses": [],
}
def _get_value_pos(line, delim):
"""
Finds the first non-whitespace character after the delimiter
Parameters:
line: (string) Input string
delim: (string) The data delimiter
"""
fields = line.split(delim, 1)
if not len(fields) == 2:
raise Exception(f"Expected a '{delim}' delimited field. Actual: {line}")
return len(line) - len(fields[1].lstrip())
def _transform_key(key):
"""
Converts a given key to a valid json key that plays nice with jq
Parameters:
key: (string) Input value
"""
# lowercase and replace spaces with underscores
key = key.strip().lower().replace(" ", "_")
# remove invalid key characters
for c in ";:!@#$%^&*()-":
key = key.replace(c, "")
return key

View File

@ -123,7 +123,7 @@ import jc.utils
class info(): class info():
"""Provides parser metadata (version, author, etc.)""" """Provides parser metadata (version, author, etc.)"""
version = '1.1' version = '1.2'
description = '`/usr/bin/time` command parser' description = '`/usr/bin/time` command parser'
author = 'Kelly Brazil' author = 'Kelly Brazil'
author_email = 'kellyjonbrazil@gmail.com' author_email = 'kellyjonbrazil@gmail.com'
@ -156,38 +156,30 @@ def _process(proc_data):
*hours, minutes, seconds, centiseconds = proc_data['elapsed_time'].split(':') *hours, minutes, seconds, centiseconds = proc_data['elapsed_time'].split(':')
proc_data['elapsed_time'] = proc_data['elapsed_time'][::-1].replace(':', '.', 1)[::-1] proc_data['elapsed_time'] = proc_data['elapsed_time'][::-1].replace(':', '.', 1)[::-1]
if hours: if hours:
proc_data['elapsed_time_hours'] = int(hours[0]) proc_data['elapsed_time_hours'] = jc.utils.convert_to_int(hours[0])
else: else:
proc_data['elapsed_time_hours'] = 0 proc_data['elapsed_time_hours'] = 0
proc_data['elapsed_time_minutes'] = int(minutes) proc_data['elapsed_time_minutes'] = jc.utils.convert_to_int(minutes)
proc_data['elapsed_time_seconds'] = int(seconds) proc_data['elapsed_time_seconds'] = jc.utils.convert_to_int(seconds)
proc_data['elapsed_time_centiseconds'] = int(centiseconds) proc_data['elapsed_time_centiseconds'] = jc.utils.convert_to_int(centiseconds)
proc_data['elapsed_time_total_seconds'] = (proc_data['elapsed_time_hours'] * 3600) + \ proc_data['elapsed_time_total_seconds'] = (proc_data['elapsed_time_hours'] * 3600) + \
(proc_data['elapsed_time_minutes'] * 60) + \ (proc_data['elapsed_time_minutes'] * 60) + \
(proc_data['elapsed_time_seconds']) + \ (proc_data['elapsed_time_seconds']) + \
(proc_data['elapsed_time_centiseconds'] / 100) (proc_data['elapsed_time_centiseconds'] / 100)
int_list = ['elapsed_time_hours', 'elapsed_time_minutes', 'elapsed_time_seconds', 'elapsed_time_microseconds', # convert ints and floats
'cpu_percent', 'average_shared_text_size', 'average_unshared_data_size', 'average_unshared_stack_size', int_list = ['cpu_percent', 'average_shared_text_size', 'average_unshared_data_size', 'average_unshared_stack_size',
'average_shared_memory_size', 'maximum_resident_set_size', 'block_input_operations', 'average_shared_memory_size', 'maximum_resident_set_size', 'block_input_operations',
'block_output_operations', 'major_pagefaults', 'minor_pagefaults', 'swaps', 'page_reclaims', 'block_output_operations', 'major_pagefaults', 'minor_pagefaults', 'swaps', 'page_reclaims',
'page_faults', 'messages_sent', 'messages_received', 'signals_received', 'voluntary_context_switches', 'page_faults', 'messages_sent', 'messages_received', 'signals_received', 'voluntary_context_switches',
'involuntary_context_switches', 'average_stack_size', 'average_total_size', 'average_resident_set_size', 'involuntary_context_switches', 'average_stack_size', 'average_total_size', 'average_resident_set_size',
'signals_delivered', 'page_size', 'exit_status'] 'signals_delivered', 'page_size', 'exit_status']
for key in int_list:
if key in proc_data:
try:
proc_data[key] = int(proc_data[key])
except (ValueError, TypeError):
proc_data[key] = None
float_list = ['real_time', 'user_time', 'system_time'] float_list = ['real_time', 'user_time', 'system_time']
for key in float_list: for key in proc_data:
if key in proc_data: if key in int_list:
try: proc_data[key] = jc.utils.convert_to_int(proc_data[key])
proc_data[key] = float(proc_data[key]) if key in float_list:
except (ValueError): proc_data[key] = jc.utils.convert_to_float(proc_data[key])
proc_data[key] = None
return proc_data return proc_data

View File

@ -63,7 +63,7 @@ import jc.utils
class info(): class info():
"""Provides parser metadata (version, author, etc.)""" """Provides parser metadata (version, author, etc.)"""
version = '1.3' version = '1.4'
description = '`timedatectl status` command parser' description = '`timedatectl status` command parser'
author = 'Kelly Brazil' author = 'Kelly Brazil'
author_email = 'kellyjonbrazil@gmail.com' author_email = 'kellyjonbrazil@gmail.com'
@ -89,15 +89,11 @@ def _process(proc_data):
Dictionary. Structured data to conform to the schema. Dictionary. Structured data to conform to the schema.
""" """
# boolean changes
bool_list = ['ntp_enabled', 'ntp_synchronized', 'rtc_in_local_tz', 'dst_active', bool_list = ['ntp_enabled', 'ntp_synchronized', 'rtc_in_local_tz', 'dst_active',
'system_clock_synchronized', 'systemd-timesyncd.service_active'] 'system_clock_synchronized', 'systemd-timesyncd.service_active']
for key in proc_data: for key in proc_data:
if key in bool_list: if key in bool_list:
try: proc_data[key] = jc.utils.convert_to_bool(proc_data[key])
proc_data[key] = True if proc_data[key] == 'yes' else False
except (ValueError):
proc_data[key] = None
if 'universal_time' in proc_data: if 'universal_time' in proc_data:
ts = jc.utils.timestamp(proc_data['universal_time']) ts = jc.utils.timestamp(proc_data['universal_time'])

View File

@ -132,7 +132,7 @@ import jc.utils
class info(): class info():
"""Provides parser metadata (version, author, etc.)""" """Provides parser metadata (version, author, etc.)"""
version = '1.1' version = '1.2'
description = '`tracepath` and `tracepath6` command parser' description = '`tracepath` and `tracepath6` command parser'
author = 'Kelly Brazil' author = 'Kelly Brazil'
author_email = 'kellyjonbrazil@gmail.com' author_email = 'kellyjonbrazil@gmail.com'
@ -157,39 +157,23 @@ def _process(proc_data):
Dictionary. Structured data to conform to the schema. Dictionary. Structured data to conform to the schema.
""" """
# convert ints and floats
int_list = ['pmtu', 'forward_hops', 'return_hops', 'ttl', 'asymmetric_difference'] int_list = ['pmtu', 'forward_hops', 'return_hops', 'ttl', 'asymmetric_difference']
float_list = ['reply_ms'] float_list = ['reply_ms']
for key in proc_data:
for key, value in proc_data.items():
for item in int_list:
if key in int_list: if key in int_list:
try: proc_data[key] = jc.utils.convert_to_int(proc_data[key])
proc_data[key] = int(proc_data[key])
except (ValueError, TypeError):
proc_data[key] = None
for item in int_list:
if key in float_list: if key in float_list:
try: proc_data[key] = jc.utils.convert_to_float(proc_data[key])
proc_data[key] = float(proc_data[key])
except (ValueError, TypeError):
proc_data[key] = None
if 'hops' in proc_data: if 'hops' in proc_data:
for entry in proc_data['hops']: for entry in proc_data['hops']:
for key in int_list: for key in entry:
if key in entry: if key in int_list:
try: entry[key] = jc.utils.convert_to_int(entry[key])
entry[key] = int(entry[key])
except (ValueError, TypeError):
entry[key] = None
for key in float_list: if key in float_list:
if key in entry: entry[key] = jc.utils.convert_to_float(entry[key])
try:
entry[key] = float(entry[key])
except (ValueError, TypeError):
entry[key] = None
return proc_data return proc_data

View File

@ -119,7 +119,7 @@ import jc.utils
class info(): class info():
"""Provides parser metadata (version, author, etc.)""" """Provides parser metadata (version, author, etc.)"""
version = '1.2' version = '1.3'
description = '`traceroute` and `traceroute6` command parser' description = '`traceroute` and `traceroute6` command parser'
author = 'Kelly Brazil' author = 'Kelly Brazil'
author_email = 'kellyjonbrazil@gmail.com' author_email = 'kellyjonbrazil@gmail.com'
@ -335,35 +335,21 @@ def _process(proc_data):
if 'hops' in proc_data: if 'hops' in proc_data:
for entry in proc_data['hops']: for entry in proc_data['hops']:
for key in int_list: for key in entry:
if key in entry: if key in int_list:
try: entry[key] = jc.utils.convert_to_int(entry[key])
entry[key] = int(entry[key])
except (ValueError, TypeError):
entry[key] = None
for key in float_list: if key in float_list:
if key in entry: entry[key] = jc.utils.convert_to_float(entry[key])
try:
entry[key] = float(entry[key])
except (ValueError, TypeError):
entry[key] = None
if 'probes' in entry: if 'probes' in entry:
for item in entry['probes']: for item in entry['probes']:
for key in int_list: for key in item:
if key in item: if key in int_list:
try: item[key] = jc.utils.convert_to_int(item[key])
item[key] = int(item[key])
except (ValueError, TypeError):
item[key] = None
for key in float_list: if key in float_list:
if key in item: item[key] = jc.utils.convert_to_float(item[key])
try:
item[key] = float(item[key])
except (ValueError, TypeError):
item[key] = None
return proc_data return proc_data

View File

@ -194,7 +194,7 @@ import jc.utils
class info(): class info():
"""Provides parser metadata (version, author, etc.)""" """Provides parser metadata (version, author, etc.)"""
version = '1.1' version = '1.2'
description = '`upower` command parser' description = '`upower` command parser'
author = 'Kelly Brazil' author = 'Kelly Brazil'
author_email = 'kellyjonbrazil@gmail.com' author_email = 'kellyjonbrazil@gmail.com'
@ -225,7 +225,7 @@ def _process(proc_data):
if 'updated' in entry: if 'updated' in entry:
updated_list = entry['updated'].replace('(', '').replace(')', '').split() updated_list = entry['updated'].replace('(', '').replace(')', '').split()
entry['updated'] = ' '.join(updated_list[:-3]) entry['updated'] = ' '.join(updated_list[:-3])
entry['updated_seconds_ago'] = int(updated_list[-3]) entry['updated_seconds_ago'] = jc.utils.convert_to_int(updated_list[-3])
if entry['updated']: if entry['updated']:
ts = jc.utils.timestamp(entry['updated']) ts = jc.utils.timestamp(entry['updated'])
@ -236,20 +236,14 @@ def _process(proc_data):
bool_list = ['power_supply', 'has_history', 'has_statistics', 'on_battery', 'lid_is_closed', 'lid_is_present'] bool_list = ['power_supply', 'has_history', 'has_statistics', 'on_battery', 'lid_is_closed', 'lid_is_present']
for key in entry: for key in entry:
if key in bool_list: if key in bool_list:
if entry[key].lower() == 'yes': entry[key] = jc.utils.convert_to_bool(entry[key])
entry[key] = True
else:
entry[key] = False
# detail level boolean conversions # detail level boolean conversions
bool_list = ['online', 'present', 'rechargeable'] bool_list = ['online', 'present', 'rechargeable']
if 'detail' in entry: if 'detail' in entry:
for key in entry['detail']: for key in entry['detail']:
if key in bool_list: if key in bool_list:
if entry['detail'][key].lower() == 'yes': entry['detail'][key] = jc.utils.convert_to_bool(entry['detail'][key])
entry['detail'][key] = True
else:
entry['detail'][key] = False
# detail level convert warning to null if value is none # detail level convert warning to null if value is none
if 'detail' in entry: if 'detail' in entry:
@ -262,8 +256,8 @@ def _process(proc_data):
add_items = [] add_items = []
for key, value in entry['detail'].items(): for key, value in entry['detail'].items():
if value and isinstance(value, str): if value and isinstance(value, str):
if len(value.split()) == 2 and value.split()[0].replace('.', '').isnumeric(): if len(value.split()) == 2:
entry['detail'][key] = float(value.split()[0]) entry['detail'][key] = jc.utils.convert_to_float(value.split()[0])
add_items.append({ add_items.append({
key + '_unit': value.split()[1] key + '_unit': value.split()[1]
}) })
@ -278,7 +272,7 @@ def _process(proc_data):
for key, value in entry['detail'].items(): for key, value in entry['detail'].items():
if value and isinstance(value, str): if value and isinstance(value, str):
if value[-1] == '%': if value[-1] == '%':
entry['detail'][key] = float(value[:-1]) entry['detail'][key] = jc.utils.convert_to_float(value)
# detail level fix quoted values # detail level fix quoted values
if 'detail' in entry: if 'detail' in entry:
@ -302,9 +296,9 @@ def _process(proc_data):
new_history_obj = {} new_history_obj = {}
for key, value in history_obj.items(): for key, value in history_obj.items():
if key == 'time': if key == 'time':
new_history_obj[key] = int(value) new_history_obj[key] = jc.utils.convert_to_int(value)
elif key == 'percent_charged': elif key == 'percent_charged':
new_history_obj[key] = float(value) new_history_obj[key] = jc.utils.convert_to_float(value)
else: else:
new_history_obj[key] = value new_history_obj[key] = value

View File

@ -65,7 +65,7 @@ import jc.utils
class info(): class info():
"""Provides parser metadata (version, author, etc.)""" """Provides parser metadata (version, author, etc.)"""
version = '1.4' version = '1.5'
description = '`uptime` command parser' description = '`uptime` command parser'
author = 'Kelly Brazil' author = 'Kelly Brazil'
author_email = 'kellyjonbrazil@gmail.com' author_email = 'kellyjonbrazil@gmail.com'
@ -92,10 +92,10 @@ def _process(proc_data):
""" """
if 'time' in proc_data: if 'time' in proc_data:
time_list = proc_data['time'].split(':') time_list = proc_data['time'].split(':')
proc_data['time_hour'] = int(time_list[0]) proc_data['time_hour'] = jc.utils.convert_to_int(time_list[0])
proc_data['time_minute'] = int(time_list[1]) proc_data['time_minute'] = jc.utils.convert_to_int(time_list[1])
if len(time_list) == 3: if len(time_list) == 3:
proc_data['time_second'] = int(time_list[2]) proc_data['time_second'] = jc.utils.convert_to_int(time_list[2])
else: else:
proc_data['time_second'] = None proc_data['time_second'] = None
@ -113,14 +113,14 @@ def _process(proc_data):
uptime_total_seconds = 0 uptime_total_seconds = 0
if 'min' in proc_data['uptime']: if 'min' in proc_data['uptime']:
uptime_minutes = int(proc_data['uptime'].split()[-2]) uptime_minutes = jc.utils.convert_to_int(proc_data['uptime'].split()[-2])
if ':' in proc_data['uptime']: if ':' in proc_data['uptime']:
uptime_hours = int(proc_data['uptime'].split()[-1].split(':')[-2]) uptime_hours = jc.utils.convert_to_int(proc_data['uptime'].split()[-1].split(':')[-2])
uptime_minutes = int(proc_data['uptime'].split(':')[-1]) uptime_minutes = jc.utils.convert_to_int(proc_data['uptime'].split(':')[-1])
if 'day' in proc_data['uptime']: if 'day' in proc_data['uptime']:
uptime_days = int(proc_data['uptime'].split()[0]) uptime_days = jc.utils.convert_to_int(proc_data['uptime'].split()[0])
proc_data['uptime_days'] = uptime_days proc_data['uptime_days'] = uptime_days
proc_data['uptime_hours'] = uptime_hours proc_data['uptime_hours'] = uptime_hours
@ -129,25 +129,14 @@ def _process(proc_data):
uptime_total_seconds = (uptime_days * 86400) + (uptime_hours * 3600) + (uptime_minutes * 60) uptime_total_seconds = (uptime_days * 86400) + (uptime_hours * 3600) + (uptime_minutes * 60)
proc_data['uptime_total_seconds'] = uptime_total_seconds proc_data['uptime_total_seconds'] = uptime_total_seconds
# integer conversions # integer and float conversions
int_list = ['users'] int_list = ['users']
for key in int_list:
if key in proc_data:
try:
key_int = int(proc_data[key])
proc_data[key] = key_int
except (ValueError):
proc_data[key] = None
# float conversions
float_list = ['load_1m', 'load_5m', 'load_15m'] float_list = ['load_1m', 'load_5m', 'load_15m']
for key in float_list: for key in proc_data:
if key in proc_data: if key in int_list:
try: proc_data[key] = jc.utils.convert_to_int(proc_data[key])
key_float = float(proc_data[key]) if key in float_list:
proc_data[key] = key_float proc_data[key] = jc.utils.convert_to_float(proc_data[key])
except (ValueError):
proc_data[key] = None
return proc_data return proc_data

View File

@ -131,8 +131,8 @@ def _process(proc_data):
""" """
for entry in proc_data: for entry in proc_data:
null_list = ['user', 'tty', 'from', 'login_at', 'idle', 'what'] null_list = ['user', 'tty', 'from', 'login_at', 'idle', 'what']
for key in null_list: for key in entry:
if key in entry: if key in null_list:
if entry[key] == '-': if entry[key] == '-':
entry[key] = None entry[key] = None

View File

@ -54,7 +54,7 @@ import jc.utils
class info(): class info():
"""Provides parser metadata (version, author, etc.)""" """Provides parser metadata (version, author, etc.)"""
version = '1.1' version = '1.2'
description = '`wc` command parser' description = '`wc` command parser'
author = 'Kelly Brazil' author = 'Kelly Brazil'
author_email = 'kellyjonbrazil@gmail.com' author_email = 'kellyjonbrazil@gmail.com'
@ -82,12 +82,10 @@ def _process(proc_data):
for entry in proc_data: for entry in proc_data:
int_list = ['lines', 'words', 'characters'] int_list = ['lines', 'words', 'characters']
for key in int_list: for key in entry:
if key in entry: if key in int_list:
try: entry[key] = jc.utils.convert_to_int(entry[key])
entry[key] = int(entry[key])
except (ValueError):
entry[key] = None
return proc_data return proc_data

Some files were not shown because too many files have changed in this diff Show More