mirror of
https://github.com/kellyjonbrazil/jc.git
synced 2026-04-03 17:44:07 +02:00
Compare commits
327 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
e30a75e25c | ||
|
|
85ad5cfd0b | ||
|
|
88b9d5068c | ||
|
|
f8c4948a09 | ||
|
|
412322447f | ||
|
|
d4f289e40f | ||
|
|
e1f3feb8f5 | ||
|
|
37d3bc699c | ||
|
|
672fd18016 | ||
|
|
bc2c23a2a0 | ||
|
|
865f7e7812 | ||
|
|
720212b552 | ||
|
|
d3be61f608 | ||
|
|
13418b16b8 | ||
|
|
42d2017cd6 | ||
|
|
4345e76ead | ||
|
|
741431322b | ||
|
|
980beaaf41 | ||
|
|
2205034e09 | ||
|
|
82b9c87a66 | ||
|
|
dda517a937 | ||
|
|
4e6d283b9e | ||
|
|
55acab05aa | ||
|
|
ed38a18d23 | ||
|
|
95b3c11203 | ||
|
|
dce318f4fd | ||
|
|
85127f0fb8 | ||
|
|
fb45058244 | ||
|
|
45bb5ae389 | ||
|
|
339238ab36 | ||
|
|
032cda8b3d | ||
|
|
6badd3fb1e | ||
|
|
724d825745 | ||
|
|
ff1e32ad2e | ||
|
|
a5f97febd3 | ||
|
|
5baa6cc865 | ||
|
|
7a4f30b843 | ||
|
|
b2c385dc4f | ||
|
|
5d5da8d33f | ||
|
|
e604571578 | ||
|
|
f9dacc3f95 | ||
|
|
6086920332 | ||
|
|
f52f3163bc | ||
|
|
d18ff73e88 | ||
|
|
1e5d602cae | ||
|
|
12912521ec | ||
|
|
842ea3a94b | ||
|
|
a8560dbc15 | ||
|
|
a65e27540a | ||
|
|
c3c5ed11e6 | ||
|
|
ce24149335 | ||
|
|
0314ca8c48 | ||
|
|
ebd8ee49a9 | ||
|
|
38d10c9781 | ||
|
|
360106c24d | ||
|
|
ca470a5d02 | ||
|
|
57f66e6b1d | ||
|
|
e774f67924 | ||
|
|
ac10e576c1 | ||
|
|
bcae0a99cd | ||
|
|
c73c2ff879 | ||
|
|
c39b1a3356 | ||
|
|
125dc2d9e0 | ||
|
|
b7d4ddc7ce | ||
|
|
f5e546c6fa | ||
|
|
928e39cd10 | ||
|
|
d0b7ea68a0 | ||
|
|
8444690133 | ||
|
|
c03c42d767 | ||
|
|
ab67688a00 | ||
|
|
5dcb7166da | ||
|
|
14697b86d7 | ||
|
|
4f4b6276d4 | ||
|
|
7bc497e129 | ||
|
|
68a37a6a5a | ||
|
|
6f5cd1d7c5 | ||
|
|
126b1b121c | ||
|
|
2341e456a0 | ||
|
|
72d80e95bb | ||
|
|
f5ec82440c | ||
|
|
c8e526ead3 | ||
|
|
066adfb764 | ||
|
|
5b444d4717 | ||
|
|
69c95adc8d | ||
|
|
2b0e0d8f5c | ||
|
|
778d1bacbf | ||
|
|
7e1b041016 | ||
|
|
313b9b329c | ||
|
|
6830062256 | ||
|
|
323072c982 | ||
|
|
8719d96bdd | ||
|
|
dd5d318ab5 | ||
|
|
d6dc7f5e65 | ||
|
|
c203664eb5 | ||
|
|
19ecf1fa19 | ||
|
|
b8deb0426c | ||
|
|
3b8371f020 | ||
|
|
20bb1cdf39 | ||
|
|
301daa48d0 | ||
|
|
8421ec8803 | ||
|
|
74211eb012 | ||
|
|
60bd42f298 | ||
|
|
14bdd74526 | ||
|
|
fb0f3eda04 | ||
|
|
91ee6e6701 | ||
|
|
51f4e6927c | ||
|
|
94988d8667 | ||
|
|
fe36f5a98c | ||
|
|
f9eb18b927 | ||
|
|
cc60f36748 | ||
|
|
604ade791f | ||
|
|
690ac52a91 | ||
|
|
34ed772775 | ||
|
|
d5ab95571f | ||
|
|
ffb3a0ee5f | ||
|
|
94b12b57aa | ||
|
|
6d149e8457 | ||
|
|
1ad89c90d8 | ||
|
|
fb71c7b020 | ||
|
|
28ed17ad3b | ||
|
|
0c2a4e2bf7 | ||
|
|
62bec30de2 | ||
|
|
3fced77e4e | ||
|
|
a09d1d8b76 | ||
|
|
8f4243fbd8 | ||
|
|
47aaf20549 | ||
|
|
0c5289ea50 | ||
|
|
3e53323514 | ||
|
|
a5ee9861b9 | ||
|
|
feb8ca7654 | ||
|
|
a7abe4473b | ||
|
|
780b9b61de | ||
|
|
19ace36ffa | ||
|
|
5fff8afc9f | ||
|
|
4ad230c927 | ||
|
|
dd98eb1ec8 | ||
|
|
c6baf42e72 | ||
|
|
e2bac97d56 | ||
|
|
d112ee94d0 | ||
|
|
27b21b2faf | ||
|
|
8c96d5cd20 | ||
|
|
c29ed3fd69 | ||
|
|
cedf603f12 | ||
|
|
279161c36f | ||
|
|
ce0b43d919 | ||
|
|
ddafa5bf06 | ||
|
|
bc7116c31b | ||
|
|
53b7092721 | ||
|
|
beb9174b1b | ||
|
|
aea41ed341 | ||
|
|
d789494cb1 | ||
|
|
608e7b4cff | ||
|
|
4ee199c02a | ||
|
|
fbf47d4085 | ||
|
|
5a238e4b42 | ||
|
|
f852b8246a | ||
|
|
88140d929a | ||
|
|
45f7268240 | ||
|
|
3a3c8e4d4a | ||
|
|
c1ac183a04 | ||
|
|
18bb779ee5 | ||
|
|
8b6612fe79 | ||
|
|
fde0bc8534 | ||
|
|
e661a78939 | ||
|
|
847e346602 | ||
|
|
b969751688 | ||
|
|
ad6f2ba03a | ||
|
|
63c6a5edc0 | ||
|
|
9f4cf9dd5e | ||
|
|
51331b6dc0 | ||
|
|
efb6761033 | ||
|
|
6a4f737a0f | ||
|
|
be6864b778 | ||
|
|
de3b91a36c | ||
|
|
ef5482c3b5 | ||
|
|
d20b795137 | ||
|
|
8a134065df | ||
|
|
22aee1bfa4 | ||
|
|
b282820fd6 | ||
|
|
3ee098306d | ||
|
|
09e8f379a6 | ||
|
|
69018cdb3a | ||
|
|
d0d7254c6a | ||
|
|
cc0f0971d7 | ||
|
|
2af61730f0 | ||
|
|
83f41b83dc | ||
|
|
1fb84fce88 | ||
|
|
a8837e1244 | ||
|
|
04d2eec558 | ||
|
|
1b57ec92f0 | ||
|
|
4d88595404 | ||
|
|
52b1272a3a | ||
|
|
d2ccad6a83 | ||
|
|
cad6dde4ac | ||
|
|
06811c3539 | ||
|
|
0cb23c2b21 | ||
|
|
ac4688dca2 | ||
|
|
326c3b4670 | ||
|
|
9b29d0c268 | ||
|
|
e0013c3871 | ||
|
|
a75744075b | ||
|
|
525aec1a02 | ||
|
|
0bf9a7a072 | ||
|
|
d8f2f4c95b | ||
|
|
35d733b44f | ||
|
|
9179b4175c | ||
|
|
bb07d78c78 | ||
|
|
07b179cd7f | ||
|
|
054422d837 | ||
|
|
3e052d1810 | ||
|
|
c8e72805cf | ||
|
|
12a80e7db0 | ||
|
|
ee7ff9a09d | ||
|
|
f6478fb636 | ||
|
|
811a0b0495 | ||
|
|
aeb48edf72 | ||
|
|
b1e94f0df7 | ||
|
|
60050e3c0f | ||
|
|
39ef09aa5b | ||
|
|
8377d43116 | ||
|
|
54e4c447ab | ||
|
|
937a9fa9cf | ||
|
|
808ff6cf0e | ||
|
|
7f5c649a95 | ||
|
|
b72727dec9 | ||
|
|
3fc88bfb33 | ||
|
|
9f2279d586 | ||
|
|
346a14cb9b | ||
|
|
dac00d17ff | ||
|
|
9ca7cd4060 | ||
|
|
aa31628970 | ||
|
|
bed694fcf5 | ||
|
|
4b4af69fa1 | ||
|
|
9d96190a5b | ||
|
|
fa44d48c09 | ||
|
|
4ef961c278 | ||
|
|
292a837d5c | ||
|
|
aa7b915d84 | ||
|
|
c46fe73236 | ||
|
|
039b2c129c | ||
|
|
8f2e5e4808 | ||
|
|
c4da8e4f78 | ||
|
|
bcab9078a4 | ||
|
|
b3c6c1ea92 | ||
|
|
a3af8662bd | ||
|
|
35940d0bc8 | ||
|
|
26994cdcb7 | ||
|
|
017159a829 | ||
|
|
b4e9c85e08 | ||
|
|
189146cd84 | ||
|
|
af34153ffa | ||
|
|
bf2ff3ffbb | ||
|
|
6423c9efd6 | ||
|
|
58ab0d4ece | ||
|
|
83a738bf4d | ||
|
|
3640671fc6 | ||
|
|
1da623b30e | ||
|
|
b10ca64646 | ||
|
|
2128763ee6 | ||
|
|
a27e7ed39c | ||
|
|
f07b7eaa47 | ||
|
|
6ce18de84c | ||
|
|
8631b756e7 | ||
|
|
7414d98412 | ||
|
|
d7b19892e8 | ||
|
|
96df396eaf | ||
|
|
2f6f640317 | ||
|
|
c4a0a50f3a | ||
|
|
658f8a3842 | ||
|
|
bfb876a1e3 | ||
|
|
90c34b1f4e | ||
|
|
3f9164ea77 | ||
|
|
7fd6fecbf5 | ||
|
|
8029f72363 | ||
|
|
c7fdce5d3b | ||
|
|
84f48aa369 | ||
|
|
2e9a0a9c12 | ||
|
|
c1f6f2b950 | ||
|
|
ede21bca13 | ||
|
|
8dd9a9f9cb | ||
|
|
04f92cd133 | ||
|
|
8be8d2393b | ||
|
|
0a879681be | ||
|
|
2ca1587a49 | ||
|
|
ec2cd2d708 | ||
|
|
5d0dbece93 | ||
|
|
df1e4b414b | ||
|
|
40760991e7 | ||
|
|
464f5f86cf | ||
|
|
7b09e9fccd | ||
|
|
6cba7d4298 | ||
|
|
9730f62e49 | ||
|
|
e0c1c87f54 | ||
|
|
931b3d2b83 | ||
|
|
e5d561baee | ||
|
|
2867593e7a | ||
|
|
dd52fee563 | ||
|
|
8e1f885827 | ||
|
|
2d39a58f90 | ||
|
|
9c4fa2ae26 | ||
|
|
de52d84e82 | ||
|
|
ce9b55059a | ||
|
|
bcd370a6a0 | ||
|
|
c8216850ab | ||
|
|
f5feedb90b | ||
|
|
a4371cd187 | ||
|
|
9d5ba4c834 | ||
|
|
1639dee1bb | ||
|
|
9363f430f2 | ||
|
|
9192a09073 | ||
|
|
b915eb9755 | ||
|
|
1cfcc2b592 | ||
|
|
7138dd02b7 | ||
|
|
b4276643b7 | ||
|
|
2ef00763bf | ||
|
|
54364928fc | ||
|
|
09b3b4932b | ||
|
|
29d6670119 | ||
|
|
2f654b5f1a | ||
|
|
e53b9f5992 | ||
|
|
addb234e61 | ||
|
|
76eca3b659 | ||
|
|
f90dec4c0e | ||
|
|
8900a59d4c | ||
|
|
6685138200 | ||
|
|
4d3e65b980 | ||
|
|
e9282bb546 |
1
.gitignore
vendored
1
.gitignore
vendored
@@ -3,5 +3,4 @@ __pycache__
|
||||
dist/
|
||||
build/
|
||||
*.egg-info/
|
||||
jc/parsers.old/
|
||||
.github/
|
||||
|
||||
@@ -1,5 +1,99 @@
|
||||
jc changelog
|
||||
|
||||
20200803 v1.13.2
|
||||
- Add key/value file parser (wrapper for ini parser)
|
||||
- Add date command parser
|
||||
- Update traceroute parser to more gracefully handle missing header row
|
||||
- Update traceroute parser to handle annotations
|
||||
- Update traceroute parser to only return successful probes
|
||||
|
||||
20200727 v1.13.1
|
||||
- Add route -6 tests
|
||||
|
||||
20200727 v1.13.0
|
||||
- Add ping and ping6 command parser tested on linux, macos, and freebsd
|
||||
- Add traceroute and traceroute6 command parser tested on linux, macos, and freebsd
|
||||
- Add tracepath command parser tested on linux
|
||||
- Update ini parser to support files only containing key/value pairs
|
||||
- Update uname parser exception with a hint to use "uname -a"
|
||||
- Update route parser to support IPv6 tables
|
||||
|
||||
20200711 v1.12.1
|
||||
- Fix tests when using older version of pygments library
|
||||
|
||||
20200710 v1.12.0
|
||||
- Add sysctl command parser tested on linux, macOS, and freebsd
|
||||
- Update the cli code to allow older versions of the pygments library (2.3.0) for debian packaging
|
||||
- Code cleanup on the cli
|
||||
- Add tests for the cli
|
||||
- Vendorize cgitb as tracebackplus for verbose debug messages
|
||||
|
||||
20200625 v1.11.8
|
||||
- Add verbose debug option using -dd argument
|
||||
|
||||
20200622 v1.11.7
|
||||
- Fix iptables parser issue which would not output the last chain
|
||||
|
||||
20200614 v1.11.6
|
||||
- Improve and standardize empty data check for all parsers
|
||||
|
||||
20200612 v1.11.5
|
||||
- Update airport_s parser to fix error on parsing empty data
|
||||
- Update arp parser to fix error on parsing empty data
|
||||
- Update blkid parser to fix error on parsing empty data
|
||||
- Update crontab parser to fix error on parsing empty data
|
||||
- Update crontab_u parser to fix error on parsing empty data
|
||||
- Update df parser to fix error on parsing empty data
|
||||
- Update free parser to fix error on parsing empty data
|
||||
- Update lsblk parser to fix error on parsing empty data
|
||||
- Update lsmod parser to fix error on parsing empty data
|
||||
- Update mount parser to fix error on parsing empty data
|
||||
- Update netstat parser to fix error on parsing empty data
|
||||
- Update ntpq parser to fix error on parsing empty data
|
||||
- Update ps parser to fix error on parsing empty data
|
||||
- Update route parser to fix error on parsing empty data
|
||||
- Update systemctl parser to fix error on parsing empty data
|
||||
- Update systemctl_lj parser to fix error on parsing empty data
|
||||
- Update systemctl_ls parser to fix error on parsing empty data
|
||||
- Update systemctl_luf parser to fix error on parsing empty data
|
||||
- Update uptime parser to fix error on parsing empty data
|
||||
- Update w parser to fix error on parsing empty data
|
||||
- Update xml parser to fix error on parsing empty data
|
||||
- Add tests to all parsers for no data condition
|
||||
- Update ss parser to fix integer fields
|
||||
|
||||
20200610 v1.11.4
|
||||
- Update ls parser to fix error on parsing an empty directory
|
||||
|
||||
20200609 v1.11.3
|
||||
- Add local parser plugin feature (contributed by Dean Serenevy)
|
||||
|
||||
20200530 v1.11.2
|
||||
- Update netstat parser to add freebsd support
|
||||
- Update netstat parser to add route_flags_pretty field
|
||||
- Update netstat parser to change osx_inode field name to unix_inode
|
||||
- Update netstat parser to change osx_flags field name to unix_flags
|
||||
- Update netstat parser to strip whitespace from state field
|
||||
- Update route parser to add flags_pretty field
|
||||
- Update arp parser to add permanent field (freebsd and osx)
|
||||
- Update arp parser to add expires field (freebsd)
|
||||
- Update w parser to strip whitespace from what field
|
||||
- Update last parser to fix FreeBSD issues
|
||||
- Update stat parser to change osx_flags field name to unix_flags
|
||||
- Update stat parser to add unix_device field for freebsd and osx
|
||||
- Fix freebsd compatibility message for df, fstab, mount, ntpq, stat, and uname parsers
|
||||
- Fix compatibility message for platforms that include the version number at the end (e.g. freebsd12)
|
||||
|
||||
20200523 v1.11.1
|
||||
- Update stat command parser to change osx_flags field to string
|
||||
|
||||
20200522 v1.11.0
|
||||
- Add dmidecode command parser
|
||||
- Update stat command parser to add OSX support
|
||||
- Update netstat command parser to add OSX support
|
||||
- Update netstat command parser to add -r (route) functionality for linux and OSX
|
||||
- Update netstat command parser to add -i (interface) functionality for linux and OSX
|
||||
|
||||
20200511 v1.10.12
|
||||
- Remove shebang from jc/cli.py for Fedora packaging
|
||||
|
||||
2651
EXAMPLES.md
Normal file
2651
EXAMPLES.md
Normal file
File diff suppressed because it is too large
Load Diff
@@ -1,6 +1,6 @@
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2019 Kelly Brazil
|
||||
Copyright (c) 2020 Kelly Brazil
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
|
||||
@@ -11,8 +11,10 @@ pydocmd simple jc.parsers.blkid+ > ../docs/parsers/blkid.md
|
||||
pydocmd simple jc.parsers.crontab+ > ../docs/parsers/crontab.md
|
||||
pydocmd simple jc.parsers.crontab_u+ > ../docs/parsers/crontab_u.md
|
||||
pydocmd simple jc.parsers.csv+ > ../docs/parsers/csv.md
|
||||
pydocmd simple jc.parsers.date+ > ../docs/parsers/date.md
|
||||
pydocmd simple jc.parsers.df+ > ../docs/parsers/df.md
|
||||
pydocmd simple jc.parsers.dig+ > ../docs/parsers/dig.md
|
||||
pydocmd simple jc.parsers.dmidecode+ > ../docs/parsers/dmidecode.md
|
||||
pydocmd simple jc.parsers.du+ > ../docs/parsers/du.md
|
||||
pydocmd simple jc.parsers.env+ > ../docs/parsers/env.md
|
||||
pydocmd simple jc.parsers.file+ > ../docs/parsers/file.md
|
||||
@@ -27,6 +29,7 @@ pydocmd simple jc.parsers.ifconfig+ > ../docs/parsers/ifconfig.md
|
||||
pydocmd simple jc.parsers.ini+ > ../docs/parsers/ini.md
|
||||
pydocmd simple jc.parsers.iptables+ > ../docs/parsers/iptables.md
|
||||
pydocmd simple jc.parsers.jobs+ > ../docs/parsers/jobs.md
|
||||
pydocmd simple jc.parsers.kv+ > ../docs/parsers/kv.md
|
||||
pydocmd simple jc.parsers.last+ > ../docs/parsers/last.md
|
||||
pydocmd simple jc.parsers.ls+ > ../docs/parsers/ls.md
|
||||
pydocmd simple jc.parsers.lsblk+ > ../docs/parsers/lsblk.md
|
||||
@@ -36,6 +39,7 @@ pydocmd simple jc.parsers.mount+ > ../docs/parsers/mount.md
|
||||
pydocmd simple jc.parsers.netstat+ > ../docs/parsers/netstat.md
|
||||
pydocmd simple jc.parsers.ntpq+ > ../docs/parsers/ntpq.md
|
||||
pydocmd simple jc.parsers.passwd+ > ../docs/parsers/passwd.md
|
||||
pydocmd simple jc.parsers.ping+ > ../docs/parsers/ping.md
|
||||
pydocmd simple jc.parsers.pip_list+ > ../docs/parsers/pip_list.md
|
||||
pydocmd simple jc.parsers.pip_show+ > ../docs/parsers/pip_show.md
|
||||
pydocmd simple jc.parsers.ps+ > ../docs/parsers/ps.md
|
||||
@@ -43,11 +47,14 @@ pydocmd simple jc.parsers.route+ > ../docs/parsers/route.md
|
||||
pydocmd simple jc.parsers.shadow+ > ../docs/parsers/shadow.md
|
||||
pydocmd simple jc.parsers.ss+ > ../docs/parsers/ss.md
|
||||
pydocmd simple jc.parsers.stat+ > ../docs/parsers/stat.md
|
||||
pydocmd simple jc.parsers.sysctl+ > ../docs/parsers/sysctl.md
|
||||
pydocmd simple jc.parsers.systemctl+ > ../docs/parsers/systemctl.md
|
||||
pydocmd simple jc.parsers.systemctl_lj+ > ../docs/parsers/systemctl_lj.md
|
||||
pydocmd simple jc.parsers.systemctl_ls+ > ../docs/parsers/systemctl_ls.md
|
||||
pydocmd simple jc.parsers.systemctl_luf+ > ../docs/parsers/systemctl_luf.md
|
||||
pydocmd simple jc.parsers.timedatectl+ > ../docs/parsers/timedatectl.md
|
||||
pydocmd simple jc.parsers.tracepath+ > ../docs/parsers/tracepath.md
|
||||
pydocmd simple jc.parsers.traceroute+ > ../docs/parsers/traceroute.md
|
||||
pydocmd simple jc.parsers.uname+ > ../docs/parsers/uname.md
|
||||
pydocmd simple jc.parsers.uptime+ > ../docs/parsers/uptime.md
|
||||
pydocmd simple jc.parsers.w+ > ../docs/parsers/w.md
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
|
||||
# jc.parsers.airport
|
||||
jc - JSON CLI output utility airport -I Parser
|
||||
|
||||
@@ -52,11 +53,13 @@ Examples:
|
||||
"channel": "48,80"
|
||||
}
|
||||
|
||||
|
||||
## info
|
||||
```python
|
||||
info(self, /, *args, **kwargs)
|
||||
info()
|
||||
```
|
||||
|
||||
|
||||
## process
|
||||
```python
|
||||
process(proc_data)
|
||||
@@ -90,6 +93,7 @@ Returns:
|
||||
"channel": string
|
||||
}
|
||||
|
||||
|
||||
## parse
|
||||
```python
|
||||
parse(data, raw=False, quiet=False)
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
|
||||
# jc.parsers.airport_s
|
||||
jc - JSON CLI output utility airport -s Parser
|
||||
|
||||
@@ -84,11 +85,13 @@ Examples:
|
||||
...
|
||||
]
|
||||
|
||||
|
||||
## info
|
||||
```python
|
||||
info(self, /, *args, **kwargs)
|
||||
info()
|
||||
```
|
||||
|
||||
|
||||
## process
|
||||
```python
|
||||
process(proc_data)
|
||||
@@ -117,6 +120,7 @@ Returns:
|
||||
}
|
||||
]
|
||||
|
||||
|
||||
## parse
|
||||
```python
|
||||
parse(data, raw=False, quiet=False)
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
|
||||
# jc.parsers.arp
|
||||
jc - JSON CLI output utility arp Parser
|
||||
|
||||
@@ -59,6 +60,8 @@ Examples:
|
||||
"hwtype": "ether",
|
||||
"hwaddress": "00:50:56:f0:98:26",
|
||||
"iface": "ens33"
|
||||
"permanent": false,
|
||||
"expires": 1182
|
||||
},
|
||||
{
|
||||
"name": "gateway",
|
||||
@@ -66,6 +69,8 @@ Examples:
|
||||
"hwtype": "ether",
|
||||
"hwaddress": "00:50:56:f7:4a:fc",
|
||||
"iface": "ens33"
|
||||
"permanent": false,
|
||||
"expires": 110
|
||||
}
|
||||
]
|
||||
|
||||
@@ -77,6 +82,8 @@ Examples:
|
||||
"hwtype": "ether",
|
||||
"hwaddress": "00:50:56:fe:7a:b4",
|
||||
"iface": "ens33"
|
||||
"permanent": false,
|
||||
"expires": "1182"
|
||||
},
|
||||
{
|
||||
"name": "_gateway",
|
||||
@@ -84,14 +91,18 @@ Examples:
|
||||
"hwtype": "ether",
|
||||
"hwaddress": "00:50:56:f7:4a:fc",
|
||||
"iface": "ens33"
|
||||
"permanent": false,
|
||||
"expires": "110"
|
||||
}
|
||||
]
|
||||
|
||||
|
||||
## info
|
||||
```python
|
||||
info(self, /, *args, **kwargs)
|
||||
info()
|
||||
```
|
||||
|
||||
|
||||
## process
|
||||
```python
|
||||
process(proc_data)
|
||||
@@ -114,10 +125,13 @@ Returns:
|
||||
"hwtype": string,
|
||||
"hwaddress": string,
|
||||
"flags_mask": string,
|
||||
"iface": string
|
||||
"iface": string,
|
||||
"permanent": boolean,
|
||||
"expires": integer
|
||||
}
|
||||
]
|
||||
|
||||
|
||||
## parse
|
||||
```python
|
||||
parse(data, raw=False, quiet=False)
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
|
||||
# jc.parsers.blkid
|
||||
jc - JSON CLI output utility blkid Parser
|
||||
|
||||
@@ -75,11 +76,13 @@ Examples:
|
||||
}
|
||||
]
|
||||
|
||||
|
||||
## info
|
||||
```python
|
||||
info(self, /, *args, **kwargs)
|
||||
info()
|
||||
```
|
||||
|
||||
|
||||
## process
|
||||
```python
|
||||
process(proc_data)
|
||||
@@ -129,6 +132,7 @@ Returns:
|
||||
}
|
||||
]
|
||||
|
||||
|
||||
## parse
|
||||
```python
|
||||
parse(data, raw=False, quiet=False)
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
|
||||
# jc.parsers.crontab
|
||||
jc - JSON CLI output utility crontab command and file Parser
|
||||
|
||||
@@ -128,11 +129,13 @@ Examples:
|
||||
]
|
||||
}
|
||||
|
||||
|
||||
## info
|
||||
```python
|
||||
info(self, /, *args, **kwargs)
|
||||
info()
|
||||
```
|
||||
|
||||
|
||||
## process
|
||||
```python
|
||||
process(proc_data)
|
||||
@@ -178,6 +181,7 @@ Returns:
|
||||
}
|
||||
|
||||
|
||||
|
||||
## parse
|
||||
```python
|
||||
parse(data, raw=False, quiet=False)
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
|
||||
# jc.parsers.crontab_u
|
||||
jc - JSON CLI output utility crontab file Parser
|
||||
|
||||
@@ -129,11 +130,13 @@ Examples:
|
||||
|
||||
|
||||
|
||||
|
||||
## info
|
||||
```python
|
||||
info(self, /, *args, **kwargs)
|
||||
info()
|
||||
```
|
||||
|
||||
|
||||
## process
|
||||
```python
|
||||
process(proc_data)
|
||||
@@ -180,6 +183,7 @@ Returns:
|
||||
}
|
||||
|
||||
|
||||
|
||||
## parse
|
||||
```python
|
||||
parse(data, raw=False, quiet=False)
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
|
||||
# jc.parsers.csv
|
||||
jc - JSON CLI output utility csv Parser
|
||||
|
||||
@@ -59,11 +60,13 @@ Examples:
|
||||
...
|
||||
]
|
||||
|
||||
|
||||
## info
|
||||
```python
|
||||
info(self, /, *args, **kwargs)
|
||||
info()
|
||||
```
|
||||
|
||||
|
||||
## process
|
||||
```python
|
||||
process(proc_data)
|
||||
@@ -86,6 +89,7 @@ Returns:
|
||||
}
|
||||
]
|
||||
|
||||
|
||||
## parse
|
||||
```python
|
||||
parse(data, raw=False, quiet=False)
|
||||
|
||||
93
docs/parsers/date.md
Normal file
93
docs/parsers/date.md
Normal file
@@ -0,0 +1,93 @@
|
||||
|
||||
# jc.parsers.date
|
||||
jc - JSON CLI output utility date Parser
|
||||
|
||||
Usage:
|
||||
|
||||
specify --date as the first argument if the piped input is coming from date
|
||||
|
||||
Compatibility:
|
||||
|
||||
'linux', 'darwin', 'freebsd'
|
||||
|
||||
Examples:
|
||||
|
||||
$ date | jc --date -p
|
||||
{
|
||||
"year": 2020,
|
||||
"month_num": 7,
|
||||
"day": 31,
|
||||
"hour": 16,
|
||||
"minute": 48,
|
||||
"second": 11,
|
||||
"month": "Jul",
|
||||
"weekday": "Fri",
|
||||
"weekday_num": 6,
|
||||
"timezone": "PDT"
|
||||
}
|
||||
|
||||
$ date | jc --date -p -r
|
||||
{
|
||||
"year": "2020",
|
||||
"month": "Jul",
|
||||
"day": "31",
|
||||
"weekday": "Fri",
|
||||
"hour": "16",
|
||||
"minute": "50",
|
||||
"second": "01",
|
||||
"timezone": "PDT"
|
||||
}
|
||||
|
||||
|
||||
## info
|
||||
```python
|
||||
info()
|
||||
```
|
||||
|
||||
|
||||
## process
|
||||
```python
|
||||
process(proc_data)
|
||||
```
|
||||
|
||||
Final processing to conform to the schema.
|
||||
|
||||
Parameters:
|
||||
|
||||
proc_data: (dictionary) raw structured data to process
|
||||
|
||||
Returns:
|
||||
|
||||
Dictionary. Structured data with the following schema:
|
||||
|
||||
{
|
||||
"year": integer,
|
||||
"month_num": integer,
|
||||
"day": integer,
|
||||
"hour": integer,
|
||||
"minute": integer,
|
||||
"second": integer,
|
||||
"month": string,
|
||||
"weekday": string,
|
||||
"weekday_num": integer,
|
||||
"timezone": string
|
||||
}
|
||||
|
||||
|
||||
## 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:
|
||||
|
||||
Dictionary. Raw or processed structured data.
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
|
||||
# jc.parsers.df
|
||||
jc - JSON CLI output utility df Parser
|
||||
|
||||
@@ -7,7 +8,7 @@ Usage:
|
||||
|
||||
Compatibility:
|
||||
|
||||
'linux', 'darwin'
|
||||
'linux', 'darwin', 'freebsd'
|
||||
|
||||
Examples:
|
||||
|
||||
@@ -69,11 +70,13 @@ Examples:
|
||||
...
|
||||
]
|
||||
|
||||
|
||||
## info
|
||||
```python
|
||||
info(self, /, *args, **kwargs)
|
||||
info()
|
||||
```
|
||||
|
||||
|
||||
## process
|
||||
```python
|
||||
process(proc_data)
|
||||
@@ -106,6 +109,7 @@ Returns:
|
||||
}
|
||||
]
|
||||
|
||||
|
||||
## parse
|
||||
```python
|
||||
parse(data, raw=False, quiet=False)
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
|
||||
# jc.parsers.dig
|
||||
jc - JSON CLI output utility dig Parser
|
||||
|
||||
@@ -321,11 +322,13 @@ Examples:
|
||||
}
|
||||
]
|
||||
|
||||
|
||||
## info
|
||||
```python
|
||||
info(self, /, *args, **kwargs)
|
||||
info()
|
||||
```
|
||||
|
||||
|
||||
## process
|
||||
```python
|
||||
process(proc_data)
|
||||
@@ -393,6 +396,7 @@ Returns:
|
||||
}
|
||||
]
|
||||
|
||||
|
||||
## parse
|
||||
```python
|
||||
parse(data, raw=False, quiet=False)
|
||||
|
||||
157
docs/parsers/dmidecode.md
Normal file
157
docs/parsers/dmidecode.md
Normal file
@@ -0,0 +1,157 @@
|
||||
|
||||
# jc.parsers.dmidecode
|
||||
jc - JSON CLI output utility dmidecode Parser
|
||||
|
||||
Usage:
|
||||
|
||||
specify --dmidecode as the first argument if the piped input is coming from dmidecode
|
||||
|
||||
Compatibility:
|
||||
|
||||
'linux'
|
||||
|
||||
Examples:
|
||||
|
||||
# dmidecode | jc --dmidecode -p
|
||||
[
|
||||
{
|
||||
"handle": "0x0000",
|
||||
"type": 0,
|
||||
"bytes": 24,
|
||||
"description": "BIOS Information",
|
||||
"values": {
|
||||
"vendor": "Phoenix Technologies LTD",
|
||||
"version": "6.00",
|
||||
"release_date": "04/13/2018",
|
||||
"address": "0xEA490",
|
||||
"runtime_size": "88944 bytes",
|
||||
"rom_size": "64 kB",
|
||||
"characteristics": [
|
||||
"ISA is supported",
|
||||
"PCI is supported",
|
||||
"PC Card (PCMCIA) is supported",
|
||||
"PNP is supported",
|
||||
"APM is supported",
|
||||
"BIOS is upgradeable",
|
||||
"BIOS shadowing is allowed",
|
||||
"ESCD support is available",
|
||||
"Boot from CD is supported",
|
||||
"Selectable boot is supported",
|
||||
"EDD is supported",
|
||||
"Print screen service is supported (int 5h)",
|
||||
"8042 keyboard services are supported (int 9h)",
|
||||
"Serial services are supported (int 14h)",
|
||||
"Printer services are supported (int 17h)",
|
||||
"CGA/mono video services are supported (int 10h)",
|
||||
"ACPI is supported",
|
||||
"Smart battery is supported",
|
||||
"BIOS boot specification is supported",
|
||||
"Function key-initiated network boot is supported",
|
||||
"Targeted content distribution is supported"
|
||||
],
|
||||
"bios_revision": "4.6",
|
||||
"firmware_revision": "0.0"
|
||||
}
|
||||
},
|
||||
...
|
||||
]
|
||||
|
||||
# dmidecode | jc --dmidecode -p -r
|
||||
[
|
||||
{
|
||||
"handle": "0x0000",
|
||||
"type": "0",
|
||||
"bytes": "24",
|
||||
"description": "BIOS Information",
|
||||
"values": {
|
||||
"vendor": "Phoenix Technologies LTD",
|
||||
"version": "6.00",
|
||||
"release_date": "04/13/2018",
|
||||
"address": "0xEA490",
|
||||
"runtime_size": "88944 bytes",
|
||||
"rom_size": "64 kB",
|
||||
"characteristics": [
|
||||
"ISA is supported",
|
||||
"PCI is supported",
|
||||
"PC Card (PCMCIA) is supported",
|
||||
"PNP is supported",
|
||||
"APM is supported",
|
||||
"BIOS is upgradeable",
|
||||
"BIOS shadowing is allowed",
|
||||
"ESCD support is available",
|
||||
"Boot from CD is supported",
|
||||
"Selectable boot is supported",
|
||||
"EDD is supported",
|
||||
"Print screen service is supported (int 5h)",
|
||||
"8042 keyboard services are supported (int 9h)",
|
||||
"Serial services are supported (int 14h)",
|
||||
"Printer services are supported (int 17h)",
|
||||
"CGA/mono video services are supported (int 10h)",
|
||||
"ACPI is supported",
|
||||
"Smart battery is supported",
|
||||
"BIOS boot specification is supported",
|
||||
"Function key-initiated network boot is supported",
|
||||
"Targeted content distribution is supported"
|
||||
],
|
||||
"bios_revision": "4.6",
|
||||
"firmware_revision": "0.0"
|
||||
}
|
||||
},
|
||||
...
|
||||
]
|
||||
|
||||
|
||||
## info
|
||||
```python
|
||||
info()
|
||||
```
|
||||
|
||||
|
||||
## process
|
||||
```python
|
||||
process(proc_data)
|
||||
```
|
||||
|
||||
Final processing to conform to the schema.
|
||||
|
||||
Parameters:
|
||||
|
||||
proc_data: (dictionary) raw structured data to process
|
||||
|
||||
Returns:
|
||||
|
||||
List of dictionaries. Structured data with the following schema:
|
||||
|
||||
[
|
||||
{
|
||||
"handle": string,
|
||||
"type": integer,
|
||||
"bytes": integer,
|
||||
"description": string,
|
||||
"values": { (null if empty)
|
||||
"lowercase_no_spaces_keys": string,
|
||||
"multiline_key_values": [
|
||||
string,
|
||||
]
|
||||
}
|
||||
}
|
||||
]
|
||||
|
||||
|
||||
## 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.
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
|
||||
# jc.parsers.du
|
||||
jc - JSON CLI output utility du Parser
|
||||
|
||||
@@ -69,11 +70,13 @@ Examples:
|
||||
...
|
||||
]
|
||||
|
||||
|
||||
## info
|
||||
```python
|
||||
info(self, /, *args, **kwargs)
|
||||
info()
|
||||
```
|
||||
|
||||
|
||||
## process
|
||||
```python
|
||||
process(proc_data)
|
||||
@@ -96,6 +99,7 @@ Returns:
|
||||
}
|
||||
]
|
||||
|
||||
|
||||
## parse
|
||||
```python
|
||||
parse(data, raw=False, quiet=False)
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
|
||||
# jc.parsers.env
|
||||
jc - JSON CLI output utility env Parser
|
||||
|
||||
@@ -49,11 +50,13 @@ Examples:
|
||||
"_": "/usr/bin/env"
|
||||
}
|
||||
|
||||
|
||||
## info
|
||||
```python
|
||||
info(self, /, *args, **kwargs)
|
||||
info()
|
||||
```
|
||||
|
||||
|
||||
## process
|
||||
```python
|
||||
process(proc_data)
|
||||
@@ -76,6 +79,7 @@ Returns:
|
||||
}
|
||||
]
|
||||
|
||||
|
||||
## parse
|
||||
```python
|
||||
parse(data, raw=False, quiet=False)
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
|
||||
# jc.parsers.file
|
||||
jc - JSON CLI output utility file command Parser
|
||||
|
||||
@@ -44,11 +45,13 @@ Examples:
|
||||
...
|
||||
]
|
||||
|
||||
|
||||
## info
|
||||
```python
|
||||
info(self, /, *args, **kwargs)
|
||||
info()
|
||||
```
|
||||
|
||||
|
||||
## process
|
||||
```python
|
||||
process(proc_data)
|
||||
@@ -71,6 +74,7 @@ Returns:
|
||||
}
|
||||
]
|
||||
|
||||
|
||||
## parse
|
||||
```python
|
||||
parse(data, raw=False, quiet=False)
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
|
||||
# jc.parsers.free
|
||||
jc - JSON CLI output utility free Parser
|
||||
|
||||
@@ -49,11 +50,13 @@ Examples:
|
||||
}
|
||||
]
|
||||
|
||||
|
||||
## info
|
||||
```python
|
||||
info(self, /, *args, **kwargs)
|
||||
info()
|
||||
```
|
||||
|
||||
|
||||
## process
|
||||
```python
|
||||
process(proc_data)
|
||||
@@ -81,6 +84,7 @@ Returns:
|
||||
}
|
||||
]
|
||||
|
||||
|
||||
## parse
|
||||
```python
|
||||
parse(data, raw=False, quiet=False)
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
|
||||
# jc.parsers.fstab
|
||||
jc - JSON CLI output utility fstab Parser
|
||||
|
||||
@@ -7,7 +8,7 @@ Usage:
|
||||
|
||||
Compatibility:
|
||||
|
||||
'linux'
|
||||
'linux', 'freebsd'
|
||||
|
||||
Examples:
|
||||
|
||||
@@ -67,11 +68,13 @@ Examples:
|
||||
}
|
||||
]
|
||||
|
||||
|
||||
## info
|
||||
```python
|
||||
info(self, /, *args, **kwargs)
|
||||
info()
|
||||
```
|
||||
|
||||
|
||||
## process
|
||||
```python
|
||||
process(proc_data)
|
||||
@@ -98,6 +101,7 @@ Returns:
|
||||
}
|
||||
]
|
||||
|
||||
|
||||
## parse
|
||||
```python
|
||||
parse(data, raw=False, quiet=False)
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
|
||||
# jc.parsers.group
|
||||
jc - JSON CLI output utility /etc/group file Parser
|
||||
|
||||
@@ -91,11 +92,13 @@ Examples:
|
||||
...
|
||||
]
|
||||
|
||||
|
||||
## info
|
||||
```python
|
||||
info(self, /, *args, **kwargs)
|
||||
info()
|
||||
```
|
||||
|
||||
|
||||
## process
|
||||
```python
|
||||
process(proc_data)
|
||||
@@ -122,6 +125,7 @@ Returns:
|
||||
}
|
||||
]
|
||||
|
||||
|
||||
## parse
|
||||
```python
|
||||
parse(data, raw=False, quiet=False)
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
|
||||
# jc.parsers.gshadow
|
||||
jc - JSON CLI output utility /etc/gshadow file Parser
|
||||
|
||||
@@ -57,11 +58,13 @@ Examples:
|
||||
...
|
||||
]
|
||||
|
||||
|
||||
## info
|
||||
```python
|
||||
info(self, /, *args, **kwargs)
|
||||
info()
|
||||
```
|
||||
|
||||
|
||||
## process
|
||||
```python
|
||||
process(proc_data)
|
||||
@@ -90,6 +93,7 @@ Returns:
|
||||
}
|
||||
]
|
||||
|
||||
|
||||
## parse
|
||||
```python
|
||||
parse(data, raw=False, quiet=False)
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
|
||||
# jc.parsers.history
|
||||
jc - JSON CLI output utility history Parser
|
||||
|
||||
@@ -41,11 +42,13 @@ Examples:
|
||||
...
|
||||
}
|
||||
|
||||
|
||||
## info
|
||||
```python
|
||||
info(self, /, *args, **kwargs)
|
||||
info()
|
||||
```
|
||||
|
||||
|
||||
## process
|
||||
```python
|
||||
process(proc_data)
|
||||
@@ -68,6 +71,7 @@ Returns:
|
||||
}
|
||||
]
|
||||
|
||||
|
||||
## parse
|
||||
```python
|
||||
parse(data, raw=False, quiet=False)
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
|
||||
# jc.parsers.hosts
|
||||
jc - JSON CLI output utility hosts Parser
|
||||
|
||||
@@ -58,11 +59,13 @@ Examples:
|
||||
}
|
||||
]
|
||||
|
||||
|
||||
## info
|
||||
```python
|
||||
info(self, /, *args, **kwargs)
|
||||
info()
|
||||
```
|
||||
|
||||
|
||||
## process
|
||||
```python
|
||||
process(proc_data)
|
||||
@@ -87,6 +90,7 @@ Returns:
|
||||
}
|
||||
]
|
||||
|
||||
|
||||
## parse
|
||||
```python
|
||||
parse(data, raw=False, quiet=False)
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
|
||||
# jc.parsers.id
|
||||
jc - JSON CLI output utility id Parser
|
||||
|
||||
@@ -67,11 +68,13 @@ Examples:
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
## info
|
||||
```python
|
||||
info(self, /, *args, **kwargs)
|
||||
info()
|
||||
```
|
||||
|
||||
|
||||
## process
|
||||
```python
|
||||
process(proc_data)
|
||||
@@ -114,6 +117,7 @@ Returns:
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
## parse
|
||||
```python
|
||||
parse(data, raw=False, quiet=False)
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
|
||||
# jc.parsers.ifconfig
|
||||
jc - JSON CLI output utility ifconfig Parser
|
||||
|
||||
@@ -142,19 +143,16 @@ Examples:
|
||||
}
|
||||
]
|
||||
|
||||
|
||||
## info
|
||||
```python
|
||||
info(self, /, *args, **kwargs)
|
||||
info()
|
||||
```
|
||||
|
||||
|
||||
## IfconfigParser
|
||||
```python
|
||||
IfconfigParser(self, console_output)
|
||||
```
|
||||
|
||||
## InterfaceNotFound
|
||||
```python
|
||||
InterfaceNotFound(self, /, *args, **kwargs)
|
||||
IfconfigParser(console_output)
|
||||
```
|
||||
|
||||
|
||||
@@ -206,6 +204,7 @@ Returns:
|
||||
}
|
||||
]
|
||||
|
||||
|
||||
## parse
|
||||
```python
|
||||
parse(data, raw=False, quiet=False)
|
||||
|
||||
@@ -1,9 +1,12 @@
|
||||
|
||||
# jc.parsers.ini
|
||||
jc - JSON CLI output utility INI Parser
|
||||
|
||||
Usage:
|
||||
|
||||
specify --ini as the first argument if the piped input is coming from an INI file
|
||||
Specify --ini as the first argument if the piped input is coming from an INI file or any
|
||||
simple key/value pair file. Delimiter can be '=' or ':'. Missing values are supported.
|
||||
Comment prefix can be '#' or ';'. Comments must be on their own line.
|
||||
|
||||
Compatibility:
|
||||
|
||||
@@ -43,11 +46,13 @@ Examples:
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
## info
|
||||
```python
|
||||
info(self, /, *args, **kwargs)
|
||||
info()
|
||||
```
|
||||
|
||||
|
||||
## process
|
||||
```python
|
||||
process(proc_data)
|
||||
@@ -61,13 +66,17 @@ Parameters:
|
||||
|
||||
Returns:
|
||||
|
||||
Dictionary representing an ini document:
|
||||
Dictionary representing an ini or simple key/value pair document:
|
||||
|
||||
{
|
||||
ini document converted to a dictionary
|
||||
see configparser standard library documentation for more details
|
||||
ini or key/value document converted to a dictionary - see configparser standard
|
||||
library documentation for more details.
|
||||
|
||||
Note: Values starting and ending with quotation marks will have the marks removed.
|
||||
If you would like to keep the quotation marks, use the -r or raw=True argument.
|
||||
}
|
||||
|
||||
|
||||
## parse
|
||||
```python
|
||||
parse(data, raw=False, quiet=False)
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
|
||||
# jc.parsers.iptables
|
||||
jc - JSON CLI output utility ipables Parser
|
||||
|
||||
@@ -131,11 +132,13 @@ Examples:
|
||||
...
|
||||
]
|
||||
|
||||
|
||||
## info
|
||||
```python
|
||||
info(self, /, *args, **kwargs)
|
||||
info()
|
||||
```
|
||||
|
||||
|
||||
## process
|
||||
```python
|
||||
process(proc_data)
|
||||
@@ -172,6 +175,7 @@ Returns:
|
||||
}
|
||||
]
|
||||
|
||||
|
||||
## parse
|
||||
```python
|
||||
parse(data, raw=False, quiet=False)
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
|
||||
# jc.parsers.jobs
|
||||
jc - JSON CLI output utility jobs Parser
|
||||
|
||||
@@ -73,11 +74,13 @@ Example:
|
||||
}
|
||||
]
|
||||
|
||||
|
||||
## info
|
||||
```python
|
||||
info(self, /, *args, **kwargs)
|
||||
info()
|
||||
```
|
||||
|
||||
|
||||
## process
|
||||
```python
|
||||
process(proc_data)
|
||||
@@ -103,6 +106,7 @@ Returns:
|
||||
}
|
||||
]
|
||||
|
||||
|
||||
## parse
|
||||
```python
|
||||
parse(data, raw=False, quiet=False)
|
||||
|
||||
61
docs/parsers/kv.md
Normal file
61
docs/parsers/kv.md
Normal file
@@ -0,0 +1,61 @@
|
||||
|
||||
# jc.parsers.kv
|
||||
jc - JSON CLI output utility Key/Value File Parser
|
||||
|
||||
Usage:
|
||||
|
||||
Specify --kv as the first argument if the piped input is coming from a simple
|
||||
key/value pair file. Delimiter can be '=' or ':'. Missing values are supported.
|
||||
Comment prefix can be '#' or ';'. Comments must be on their own line.
|
||||
|
||||
Compatibility:
|
||||
|
||||
'linux', 'darwin', 'cygwin', 'win32', 'aix', 'freebsd'
|
||||
|
||||
Examples:
|
||||
|
||||
$ cat keyvalue.txt
|
||||
# this file contains key/value pairs
|
||||
name = John Doe
|
||||
address=555 California Drive
|
||||
age: 34
|
||||
; comments can include # or ;
|
||||
# delimiter can be = or :
|
||||
# quoted values have quotation marks stripped by default
|
||||
# but can be preserved with the -r argument
|
||||
occupation:"Engineer"
|
||||
|
||||
$ cat keyvalue.txt | jc --ini -p
|
||||
{
|
||||
"name": "John Doe",
|
||||
"address": "555 California Drive",
|
||||
"age": "34",
|
||||
"occupation": "Engineer"
|
||||
}
|
||||
|
||||
|
||||
## info
|
||||
```python
|
||||
info()
|
||||
```
|
||||
|
||||
|
||||
## parse
|
||||
```python
|
||||
parse(data, raw=False, quiet=False)
|
||||
```
|
||||
|
||||
Main text parsing function
|
||||
|
||||
Note: this is just a wrapper for jc.parsers.ini
|
||||
|
||||
Parameters:
|
||||
|
||||
data: (string) text data to parse
|
||||
raw: (boolean) output preprocessed JSON if True
|
||||
quiet: (boolean) suppress warning messages if True
|
||||
|
||||
Returns:
|
||||
|
||||
Dictionary representing the key/value file
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
|
||||
# jc.parsers.last
|
||||
jc - JSON CLI output utility last Parser
|
||||
|
||||
@@ -68,11 +69,13 @@ Examples:
|
||||
]
|
||||
|
||||
|
||||
|
||||
## info
|
||||
```python
|
||||
info(self, /, *args, **kwargs)
|
||||
info()
|
||||
```
|
||||
|
||||
|
||||
## process
|
||||
```python
|
||||
process(proc_data)
|
||||
@@ -99,6 +102,7 @@ Returns:
|
||||
}
|
||||
]
|
||||
|
||||
|
||||
## parse
|
||||
```python
|
||||
parse(data, raw=False, quiet=False)
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
|
||||
# jc.parsers.ls
|
||||
jc - JSON CLI output utility ls Parser
|
||||
|
||||
@@ -145,11 +146,13 @@ Examples:
|
||||
"date": "May 3 2019"
|
||||
}
|
||||
|
||||
|
||||
## info
|
||||
```python
|
||||
info(self, /, *args, **kwargs)
|
||||
info()
|
||||
```
|
||||
|
||||
|
||||
## process
|
||||
```python
|
||||
process(proc_data)
|
||||
@@ -178,6 +181,7 @@ Returns:
|
||||
}
|
||||
]
|
||||
|
||||
|
||||
## parse
|
||||
```python
|
||||
parse(data, raw=False, quiet=False)
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
|
||||
# jc.parsers.lsblk
|
||||
jc - JSON CLI output utility lsblk Parser
|
||||
|
||||
@@ -212,11 +213,13 @@ Examples:
|
||||
...
|
||||
]
|
||||
|
||||
|
||||
## info
|
||||
```python
|
||||
info(self, /, *args, **kwargs)
|
||||
info()
|
||||
```
|
||||
|
||||
|
||||
## process
|
||||
```python
|
||||
process(proc_data)
|
||||
@@ -277,6 +280,7 @@ Returns:
|
||||
}
|
||||
]
|
||||
|
||||
|
||||
## parse
|
||||
```python
|
||||
parse(data, raw=False, quiet=False)
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
|
||||
# jc.parsers.lsmod
|
||||
jc - JSON CLI output utility lsmod Parser
|
||||
|
||||
@@ -103,11 +104,13 @@ Examples:
|
||||
...
|
||||
]
|
||||
|
||||
|
||||
## info
|
||||
```python
|
||||
info(self, /, *args, **kwargs)
|
||||
info()
|
||||
```
|
||||
|
||||
|
||||
## process
|
||||
```python
|
||||
process(proc_data)
|
||||
@@ -134,6 +137,7 @@ Returns:
|
||||
}
|
||||
]
|
||||
|
||||
|
||||
## parse
|
||||
```python
|
||||
parse(data, raw=False, quiet=False)
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
|
||||
# jc.parsers.lsof
|
||||
jc - JSON CLI output utility lsof Parser
|
||||
|
||||
@@ -93,11 +94,13 @@ Examples:
|
||||
...
|
||||
]
|
||||
|
||||
|
||||
## info
|
||||
```python
|
||||
info(self, /, *args, **kwargs)
|
||||
info()
|
||||
```
|
||||
|
||||
|
||||
## process
|
||||
```python
|
||||
process(proc_data)
|
||||
@@ -128,6 +131,7 @@ Returns:
|
||||
}
|
||||
]
|
||||
|
||||
|
||||
## parse
|
||||
```python
|
||||
parse(data, raw=False, quiet=False)
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
|
||||
# jc.parsers.mount
|
||||
jc - JSON CLI output utility mount Parser
|
||||
|
||||
@@ -7,7 +8,7 @@ Usage:
|
||||
|
||||
Compatibility:
|
||||
|
||||
'linux', 'darwin'
|
||||
'linux', 'darwin', 'freebsd'
|
||||
|
||||
Example:
|
||||
|
||||
@@ -53,11 +54,13 @@ Example:
|
||||
...
|
||||
]
|
||||
|
||||
|
||||
## info
|
||||
```python
|
||||
info(self, /, *args, **kwargs)
|
||||
info()
|
||||
```
|
||||
|
||||
|
||||
## process
|
||||
```python
|
||||
process(proc_data)
|
||||
@@ -84,6 +87,7 @@ Returns:
|
||||
}
|
||||
]
|
||||
|
||||
|
||||
## parse
|
||||
```python
|
||||
parse(data, raw=False, quiet=False)
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
|
||||
# jc.parsers.netstat
|
||||
jc - JSON CLI output utility netstat Parser
|
||||
|
||||
@@ -5,13 +6,18 @@ Usage:
|
||||
|
||||
Specify --netstat as the first argument if the piped input is coming from netstat
|
||||
|
||||
Caveats:
|
||||
|
||||
- Use of multiple 'l' options is not supported on OSX (e.g. 'netstat -rlll')
|
||||
- Use of the 'A' option is not supported on OSX when using the 'r' option (e.g. netstat -rA)
|
||||
|
||||
Compatibility:
|
||||
|
||||
'linux'
|
||||
'linux', 'darwin', 'freebsd'
|
||||
|
||||
Examples:
|
||||
|
||||
$ sudo netstat -apee | jc --netstat -p
|
||||
# netstat -apee | jc --netstat -p
|
||||
[
|
||||
{
|
||||
"proto": "tcp",
|
||||
@@ -161,159 +167,92 @@ Examples:
|
||||
...
|
||||
]
|
||||
|
||||
$ sudo netstat -apee | jc --netstat -p -r
|
||||
$ netstat -r | jc --netstat -p
|
||||
[
|
||||
{
|
||||
"proto": "tcp",
|
||||
"recv_q": "0",
|
||||
"send_q": "0",
|
||||
"local_address": "localhost",
|
||||
"foreign_address": "0.0.0.0",
|
||||
"state": "LISTEN",
|
||||
"user": "systemd-resolve",
|
||||
"inode": "26958",
|
||||
"program_name": "systemd-resolve",
|
||||
"kind": "network",
|
||||
"pid": "887",
|
||||
"local_port": "domain",
|
||||
"foreign_port": "*",
|
||||
"transport_protocol": "tcp",
|
||||
"network_protocol": "ipv4"
|
||||
"destination": "default",
|
||||
"gateway": "gateway",
|
||||
"genmask": "0.0.0.0",
|
||||
"route_flags": "UG",
|
||||
"mss": 0,
|
||||
"window": 0,
|
||||
"irtt": 0,
|
||||
"iface": "ens33",
|
||||
"kind": "route",
|
||||
"route_flags_pretty": [
|
||||
"UP",
|
||||
"GATEWAY"
|
||||
]
|
||||
},
|
||||
{
|
||||
"proto": "tcp",
|
||||
"recv_q": "0",
|
||||
"send_q": "0",
|
||||
"local_address": "0.0.0.0",
|
||||
"foreign_address": "0.0.0.0",
|
||||
"state": "LISTEN",
|
||||
"user": "root",
|
||||
"inode": "30499",
|
||||
"program_name": "sshd",
|
||||
"kind": "network",
|
||||
"pid": "1186",
|
||||
"local_port": "ssh",
|
||||
"foreign_port": "*",
|
||||
"transport_protocol": "tcp",
|
||||
"network_protocol": "ipv4"
|
||||
"destination": "172.17.0.0",
|
||||
"gateway": "0.0.0.0",
|
||||
"genmask": "255.255.0.0",
|
||||
"route_flags": "U",
|
||||
"mss": 0,
|
||||
"window": 0,
|
||||
"irtt": 0,
|
||||
"iface": "docker0",
|
||||
"kind": "route",
|
||||
"route_flags_pretty": [
|
||||
"UP"
|
||||
]
|
||||
},
|
||||
{
|
||||
"proto": "tcp",
|
||||
"recv_q": "0",
|
||||
"send_q": "0",
|
||||
"local_address": "localhost",
|
||||
"foreign_address": "localhost",
|
||||
"state": "ESTABLISHED",
|
||||
"user": "root",
|
||||
"inode": "46829",
|
||||
"program_name": "sshd: root",
|
||||
"kind": "network",
|
||||
"pid": "2242",
|
||||
"local_port": "ssh",
|
||||
"foreign_port": "52186",
|
||||
"transport_protocol": "tcp",
|
||||
"network_protocol": "ipv4"
|
||||
},
|
||||
{
|
||||
"proto": "tcp",
|
||||
"recv_q": "0",
|
||||
"send_q": "0",
|
||||
"local_address": "localhost",
|
||||
"foreign_address": "localhost",
|
||||
"state": "ESTABLISHED",
|
||||
"user": "root",
|
||||
"inode": "46828",
|
||||
"program_name": "ssh",
|
||||
"kind": "network",
|
||||
"pid": "2241",
|
||||
"local_port": "52186",
|
||||
"foreign_port": "ssh",
|
||||
"transport_protocol": "tcp",
|
||||
"network_protocol": "ipv4"
|
||||
},
|
||||
{
|
||||
"proto": "tcp6",
|
||||
"recv_q": "0",
|
||||
"send_q": "0",
|
||||
"local_address": "[::]",
|
||||
"foreign_address": "[::]",
|
||||
"state": "LISTEN",
|
||||
"user": "root",
|
||||
"inode": "30510",
|
||||
"program_name": "sshd",
|
||||
"kind": "network",
|
||||
"pid": "1186",
|
||||
"local_port": "ssh",
|
||||
"foreign_port": "*",
|
||||
"transport_protocol": "tcp",
|
||||
"network_protocol": "ipv6"
|
||||
},
|
||||
{
|
||||
"proto": "udp",
|
||||
"recv_q": "0",
|
||||
"send_q": "0",
|
||||
"local_address": "localhost",
|
||||
"foreign_address": "0.0.0.0",
|
||||
"state": null,
|
||||
"user": "systemd-resolve",
|
||||
"inode": "26957",
|
||||
"program_name": "systemd-resolve",
|
||||
"kind": "network",
|
||||
"pid": "887",
|
||||
"local_port": "domain",
|
||||
"foreign_port": "*",
|
||||
"transport_protocol": "udp",
|
||||
"network_protocol": "ipv4"
|
||||
},
|
||||
{
|
||||
"proto": "raw6",
|
||||
"recv_q": "0",
|
||||
"send_q": "0",
|
||||
"local_address": "[::]",
|
||||
"foreign_address": "[::]",
|
||||
"state": "7",
|
||||
"user": "systemd-network",
|
||||
"inode": "27001",
|
||||
"program_name": "systemd-network",
|
||||
"kind": "network",
|
||||
"pid": "867",
|
||||
"local_port": "ipv6-icmp",
|
||||
"foreign_port": "*",
|
||||
"transport_protocol": null,
|
||||
"network_protocol": "ipv6"
|
||||
},
|
||||
{
|
||||
"proto": "unix",
|
||||
"refcnt": "2",
|
||||
"flags": null,
|
||||
"type": "DGRAM",
|
||||
"state": null,
|
||||
"inode": "33322",
|
||||
"program_name": "systemd",
|
||||
"path": "/run/user/1000/systemd/notify",
|
||||
"kind": "socket",
|
||||
"pid": " 1607"
|
||||
},
|
||||
{
|
||||
"proto": "unix",
|
||||
"refcnt": "2",
|
||||
"flags": "ACC",
|
||||
"type": "SEQPACKET",
|
||||
"state": "LISTENING",
|
||||
"inode": "20835",
|
||||
"program_name": "init",
|
||||
"path": "/run/udev/control",
|
||||
"kind": "socket",
|
||||
"pid": " 1"
|
||||
},
|
||||
...
|
||||
"destination": "192.168.71.0",
|
||||
"gateway": "0.0.0.0",
|
||||
"genmask": "255.255.255.0",
|
||||
"route_flags": "U",
|
||||
"mss": 0,
|
||||
"window": 0,
|
||||
"irtt": 0,
|
||||
"iface": "ens33",
|
||||
"kind": "route",
|
||||
"route_flags_pretty": [
|
||||
"UP"
|
||||
]
|
||||
}
|
||||
]
|
||||
|
||||
$ netstat -i | jc --netstat -p
|
||||
[
|
||||
{
|
||||
"iface": "ens33",
|
||||
"mtu": 1500,
|
||||
"rx_ok": 476,
|
||||
"rx_err": 0,
|
||||
"rx_drp": 0,
|
||||
"rx_ovr": 0,
|
||||
"tx_ok": 312,
|
||||
"tx_err": 0,
|
||||
"tx_drp": 0,
|
||||
"tx_ovr": 0,
|
||||
"flg": "BMRU",
|
||||
"kind": "interface"
|
||||
},
|
||||
{
|
||||
"iface": "lo",
|
||||
"mtu": 65536,
|
||||
"rx_ok": 0,
|
||||
"rx_err": 0,
|
||||
"rx_drp": 0,
|
||||
"rx_ovr": 0,
|
||||
"tx_ok": 0,
|
||||
"tx_err": 0,
|
||||
"tx_drp": 0,
|
||||
"tx_ovr": 0,
|
||||
"flg": "LRU",
|
||||
"kind": "interface"
|
||||
}
|
||||
]
|
||||
|
||||
|
||||
## info
|
||||
```python
|
||||
info(self, /, *args, **kwargs)
|
||||
info()
|
||||
```
|
||||
|
||||
|
||||
## process
|
||||
```python
|
||||
process(proc_data)
|
||||
@@ -331,31 +270,104 @@ Returns:
|
||||
|
||||
[
|
||||
{
|
||||
"proto": string,
|
||||
"recv_q": integer,
|
||||
"send_q": integer,
|
||||
"transport_protocol" string,
|
||||
"network_protocol": string,
|
||||
"local_address": string,
|
||||
"local_port": string,
|
||||
"local_port_num": integer,
|
||||
"foreign_address": string,
|
||||
"foreign_port": string,
|
||||
"foreign_port_num": integer,
|
||||
"state": string,
|
||||
"program_name": string,
|
||||
"pid": integer,
|
||||
"user": string,
|
||||
"security_context": string,
|
||||
"refcnt": integer,
|
||||
"flags": string,
|
||||
"type": string,
|
||||
"inode": integer,
|
||||
"path": string,
|
||||
"kind": string
|
||||
"proto": string,
|
||||
"recv_q": integer,
|
||||
"send_q": integer,
|
||||
"transport_protocol" string,
|
||||
"network_protocol": string,
|
||||
"local_address": string,
|
||||
"local_port": string,
|
||||
"local_port_num": integer,
|
||||
"foreign_address": string,
|
||||
"foreign_port": string,
|
||||
"foreign_port_num": integer,
|
||||
"state": string,
|
||||
"program_name": string,
|
||||
"pid": integer,
|
||||
"user": string,
|
||||
"security_context": string,
|
||||
"refcnt": integer,
|
||||
"flags": string,
|
||||
"type": string,
|
||||
"inode": integer,
|
||||
"path": string,
|
||||
"kind": string,
|
||||
"address": string,
|
||||
"unix_inode": string,
|
||||
"conn": string,
|
||||
"refs": string,
|
||||
"nextref": string,
|
||||
"name": string,
|
||||
"unit": integer,
|
||||
"vendor": integer,
|
||||
"class": integer,
|
||||
"subcla": integer,
|
||||
"unix_flags": integer,
|
||||
"pcbcount": integer,
|
||||
"rcvbuf": integer,
|
||||
"sndbuf": integer,
|
||||
"rxbytes": integer,
|
||||
"txbytes": integer,
|
||||
"destination": string,
|
||||
"gateway": string,
|
||||
"route_flags": string,
|
||||
"route_flags_pretty": [
|
||||
string,
|
||||
]
|
||||
"route_refs": integer,
|
||||
"use": integer,
|
||||
"mtu": integer,
|
||||
"expire": string,
|
||||
"genmask": string,
|
||||
"mss": integer,
|
||||
"window": integer,
|
||||
"irtt": integer,
|
||||
"iface": string,
|
||||
"metric": integer,
|
||||
"network": string,
|
||||
"address": string,
|
||||
"ipkts": integer, - = null
|
||||
"ierrs": integer, - = null
|
||||
"idrop": integer, - = null
|
||||
"opkts": integer, - = null
|
||||
"oerrs": integer, - = null
|
||||
"coll": integer, - = null
|
||||
"rx_ok": integer,
|
||||
"rx_err": integer,
|
||||
"rx_drp": integer,
|
||||
"rx_ovr": integer,
|
||||
"tx_ok": integer,
|
||||
"tx_err": integer,
|
||||
"tx_drp": integer,
|
||||
"tx_ovr": integer,
|
||||
"flg": string,
|
||||
"ibytes": integer,
|
||||
"obytes": integer,
|
||||
"r_mbuf": integer,
|
||||
"s_mbuf": integer,
|
||||
"r_clus": integer,
|
||||
"s_clus": integer,
|
||||
"r_hiwa": integer,
|
||||
"s_hiwa": integer,
|
||||
"r_lowa": integer,
|
||||
"s_lowa": integer,
|
||||
"r_bcnt": integer,
|
||||
"s_bcnt": integer,
|
||||
"r_bmax": integer,
|
||||
"s_bmax": integer,
|
||||
"rexmit": integer,
|
||||
"ooorcv": integer,
|
||||
"0_win": integer,
|
||||
"rexmt": float,
|
||||
"persist": float,
|
||||
"keep": float,
|
||||
"2msl": float,
|
||||
"delack": float,
|
||||
"rcvtime": float,
|
||||
}
|
||||
]
|
||||
|
||||
|
||||
## parse
|
||||
```python
|
||||
parse(data, raw=False, quiet=False)
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
|
||||
# jc.parsers.ntpq
|
||||
jc - JSON CLI output utility ntpq Parser
|
||||
|
||||
@@ -7,7 +8,7 @@ Usage:
|
||||
|
||||
Compatibility:
|
||||
|
||||
'linux'
|
||||
'linux', 'freebsd'
|
||||
|
||||
Examples:
|
||||
|
||||
@@ -179,11 +180,13 @@ Examples:
|
||||
}
|
||||
]
|
||||
|
||||
|
||||
## info
|
||||
```python
|
||||
info(self, /, *args, **kwargs)
|
||||
info()
|
||||
```
|
||||
|
||||
|
||||
## process
|
||||
```python
|
||||
process(proc_data)
|
||||
@@ -216,6 +219,7 @@ Returns:
|
||||
]
|
||||
|
||||
|
||||
|
||||
## parse
|
||||
```python
|
||||
parse(data, raw=False, quiet=False)
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
|
||||
# jc.parsers.passwd
|
||||
jc - JSON CLI output utility /etc/passwd file Parser
|
||||
|
||||
@@ -75,11 +76,13 @@ Examples:
|
||||
...
|
||||
]
|
||||
|
||||
|
||||
## info
|
||||
```python
|
||||
info(self, /, *args, **kwargs)
|
||||
info()
|
||||
```
|
||||
|
||||
|
||||
## process
|
||||
```python
|
||||
process(proc_data)
|
||||
@@ -107,6 +110,7 @@ Returns:
|
||||
}
|
||||
]
|
||||
|
||||
|
||||
## parse
|
||||
```python
|
||||
parse(data, raw=False, quiet=False)
|
||||
|
||||
175
docs/parsers/ping.md
Normal file
175
docs/parsers/ping.md
Normal file
@@ -0,0 +1,175 @@
|
||||
|
||||
# jc.parsers.ping
|
||||
jc - JSON CLI output utility ping Parser
|
||||
|
||||
Usage:
|
||||
|
||||
specify --ping as the first argument if the piped input is coming from ping
|
||||
|
||||
Note: Use the ping -c (count) option, otherwise data will not be piped to jc.
|
||||
|
||||
Compatibility:
|
||||
|
||||
'linux', 'darwin', 'freebsd'
|
||||
|
||||
Examples:
|
||||
|
||||
$ ping -c 3 -p ff cnn.com | jc --ping -p
|
||||
{
|
||||
"destination_ip": "151.101.1.67",
|
||||
"data_bytes": 56,
|
||||
"pattern": "0xff",
|
||||
"destination": "cnn.com",
|
||||
"packets_transmitted": 3,
|
||||
"packets_received": 3,
|
||||
"packet_loss_percent": 0.0,
|
||||
"duplicates": 0,
|
||||
"round_trip_ms_min": 28.015,
|
||||
"round_trip_ms_avg": 32.848,
|
||||
"round_trip_ms_max": 39.376,
|
||||
"round_trip_ms_stddev": 4.79,
|
||||
"responses": [
|
||||
{
|
||||
"type": "reply",
|
||||
"bytes": 64,
|
||||
"response_ip": "151.101.1.67",
|
||||
"icmp_seq": 0,
|
||||
"ttl": 59,
|
||||
"time_ms": 28.015,
|
||||
"duplicate": false
|
||||
},
|
||||
{
|
||||
"type": "reply",
|
||||
"bytes": 64,
|
||||
"response_ip": "151.101.1.67",
|
||||
"icmp_seq": 1,
|
||||
"ttl": 59,
|
||||
"time_ms": 39.376,
|
||||
"duplicate": false
|
||||
},
|
||||
{
|
||||
"type": "reply",
|
||||
"bytes": 64,
|
||||
"response_ip": "151.101.1.67",
|
||||
"icmp_seq": 2,
|
||||
"ttl": 59,
|
||||
"time_ms": 31.153,
|
||||
"duplicate": false
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
|
||||
$ ping -c 3 -p ff cnn.com | jc --ping -p -r
|
||||
{
|
||||
"destination_ip": "151.101.129.67",
|
||||
"data_bytes": "56",
|
||||
"pattern": "0xff",
|
||||
"destination": "cnn.com",
|
||||
"packets_transmitted": "3",
|
||||
"packets_received": "3",
|
||||
"packet_loss_percent": "0.0",
|
||||
"duplicates": "0",
|
||||
"round_trip_ms_min": "25.078",
|
||||
"round_trip_ms_avg": "29.543",
|
||||
"round_trip_ms_max": "32.553",
|
||||
"round_trip_ms_stddev": "3.221",
|
||||
"responses": [
|
||||
{
|
||||
"type": "reply",
|
||||
"bytes": "64",
|
||||
"response_ip": "151.101.129.67",
|
||||
"icmp_seq": "0",
|
||||
"ttl": "59",
|
||||
"time_ms": "25.078",
|
||||
"duplicate": false
|
||||
},
|
||||
{
|
||||
"type": "reply",
|
||||
"bytes": "64",
|
||||
"response_ip": "151.101.129.67",
|
||||
"icmp_seq": "1",
|
||||
"ttl": "59",
|
||||
"time_ms": "30.999",
|
||||
"duplicate": false
|
||||
},
|
||||
{
|
||||
"type": "reply",
|
||||
"bytes": "64",
|
||||
"response_ip": "151.101.129.67",
|
||||
"icmp_seq": "2",
|
||||
"ttl": "59",
|
||||
"time_ms": "32.553",
|
||||
"duplicate": false
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
|
||||
## info
|
||||
```python
|
||||
info()
|
||||
```
|
||||
|
||||
|
||||
## process
|
||||
```python
|
||||
process(proc_data)
|
||||
```
|
||||
|
||||
Final processing to conform to the schema.
|
||||
|
||||
Parameters:
|
||||
|
||||
proc_data: (dictionary) raw structured data to process
|
||||
|
||||
Returns:
|
||||
|
||||
Dictionary. Structured data with the following schema:
|
||||
|
||||
{
|
||||
"source_ip": string,
|
||||
"destination_ip": string,
|
||||
"data_bytes": integer,
|
||||
"pattern": string, (null if not set)
|
||||
"destination": string,
|
||||
"packets_transmitted": integer,
|
||||
"packets_received": integer,
|
||||
"packet_loss_percent": float,
|
||||
"duplicates": integer,
|
||||
"round_trip_ms_min": float,
|
||||
"round_trip_ms_avg": float,
|
||||
"round_trip_ms_max": float,
|
||||
"round_trip_ms_stddev": float,
|
||||
"responses": [
|
||||
{
|
||||
"type": string, ('reply' or 'timeout')
|
||||
"timestamp": float,
|
||||
"bytes": integer,
|
||||
"response_ip": string,
|
||||
"icmp_seq": integer,
|
||||
"ttl": integer,
|
||||
"time_ms": float,
|
||||
"duplicate": boolean
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
|
||||
## 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:
|
||||
|
||||
Dictionary. Raw or processed structured data.
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
|
||||
# jc.parsers.pip_list
|
||||
jc - JSON CLI output utility pip-list Parser
|
||||
|
||||
@@ -28,11 +29,13 @@ Examples:
|
||||
...
|
||||
]
|
||||
|
||||
|
||||
## info
|
||||
```python
|
||||
info(self, /, *args, **kwargs)
|
||||
info()
|
||||
```
|
||||
|
||||
|
||||
## process
|
||||
```python
|
||||
process(proc_data)
|
||||
@@ -56,6 +59,7 @@ Returns:
|
||||
}
|
||||
]
|
||||
|
||||
|
||||
## parse
|
||||
```python
|
||||
parse(data, raw=False, quiet=False)
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
|
||||
# jc.parsers.pip_show
|
||||
jc - JSON CLI output utility pip-show Parser
|
||||
|
||||
@@ -39,11 +40,13 @@ Examples:
|
||||
}
|
||||
]
|
||||
|
||||
|
||||
## info
|
||||
```python
|
||||
info(self, /, *args, **kwargs)
|
||||
info()
|
||||
```
|
||||
|
||||
|
||||
## process
|
||||
```python
|
||||
process(proc_data)
|
||||
@@ -75,6 +78,7 @@ Returns:
|
||||
]
|
||||
|
||||
|
||||
|
||||
## parse
|
||||
```python
|
||||
parse(data, raw=False, quiet=False)
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
|
||||
# jc.parsers.ps
|
||||
jc - JSON CLI output utility ps Parser
|
||||
|
||||
@@ -173,11 +174,13 @@ Examples:
|
||||
...
|
||||
]
|
||||
|
||||
|
||||
## info
|
||||
```python
|
||||
info(self, /, *args, **kwargs)
|
||||
info()
|
||||
```
|
||||
|
||||
|
||||
## process
|
||||
```python
|
||||
process(proc_data)
|
||||
@@ -215,6 +218,7 @@ Returns:
|
||||
}
|
||||
]
|
||||
|
||||
|
||||
## parse
|
||||
```python
|
||||
parse(data, raw=False, quiet=False)
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
|
||||
# jc.parsers.route
|
||||
jc - JSON CLI output utility route Parser
|
||||
|
||||
@@ -15,53 +16,48 @@ Examples:
|
||||
[
|
||||
{
|
||||
"destination": "default",
|
||||
"gateway": "gateway",
|
||||
"gateway": "_gateway",
|
||||
"genmask": "0.0.0.0",
|
||||
"flags": "UG",
|
||||
"metric": 100,
|
||||
"metric": 202,
|
||||
"ref": 0,
|
||||
"use": 0,
|
||||
"iface": "ens33",
|
||||
"mss": 0,
|
||||
"window": 0,
|
||||
"irtt": 0
|
||||
},
|
||||
{
|
||||
"destination": "172.17.0.0",
|
||||
"gateway": "0.0.0.0",
|
||||
"genmask": "255.255.0.0",
|
||||
"flags": "U",
|
||||
"metric": 0,
|
||||
"ref": 0,
|
||||
"use": 0,
|
||||
"iface": "docker",
|
||||
"mss": 0,
|
||||
"window": 0,
|
||||
"irtt": 0
|
||||
"irtt": 0,
|
||||
"flags_pretty": [
|
||||
"UP",
|
||||
"GATEWAY"
|
||||
]
|
||||
},
|
||||
{
|
||||
"destination": "192.168.71.0",
|
||||
"gateway": "0.0.0.0",
|
||||
"genmask": "255.255.255.0",
|
||||
"flags": "U",
|
||||
"metric": 100,
|
||||
"metric": 202,
|
||||
"ref": 0,
|
||||
"use": 0,
|
||||
"iface": "ens33",
|
||||
"mss": 0,
|
||||
"window": 0,
|
||||
"irtt": 0
|
||||
"irtt": 0,
|
||||
"flags_pretty": [
|
||||
"UP"
|
||||
]
|
||||
}
|
||||
]
|
||||
|
||||
|
||||
$ route -ee | jc --route -p -r
|
||||
[
|
||||
{
|
||||
"destination": "default",
|
||||
"gateway": "gateway",
|
||||
"gateway": "_gateway",
|
||||
"genmask": "0.0.0.0",
|
||||
"flags": "UG",
|
||||
"metric": "100",
|
||||
"metric": "202",
|
||||
"ref": "0",
|
||||
"use": "0",
|
||||
"iface": "ens33",
|
||||
@@ -69,25 +65,12 @@ Examples:
|
||||
"window": "0",
|
||||
"irtt": "0"
|
||||
},
|
||||
{
|
||||
"destination": "172.17.0.0",
|
||||
"gateway": "0.0.0.0",
|
||||
"genmask": "255.255.0.0",
|
||||
"flags": "U",
|
||||
"metric": "0",
|
||||
"ref": "0",
|
||||
"use": "0",
|
||||
"iface": "docker",
|
||||
"mss": "0",
|
||||
"window": "0",
|
||||
"irtt": "0"
|
||||
},
|
||||
{
|
||||
"destination": "192.168.71.0",
|
||||
"gateway": "0.0.0.0",
|
||||
"genmask": "255.255.255.0",
|
||||
"flags": "U",
|
||||
"metric": "100",
|
||||
"metric": "202",
|
||||
"ref": "0",
|
||||
"use": "0",
|
||||
"iface": "ens33",
|
||||
@@ -97,11 +80,14 @@ Examples:
|
||||
}
|
||||
]
|
||||
|
||||
|
||||
|
||||
## info
|
||||
```python
|
||||
info(self, /, *args, **kwargs)
|
||||
info()
|
||||
```
|
||||
|
||||
|
||||
## process
|
||||
```python
|
||||
process(proc_data)
|
||||
@@ -119,20 +105,24 @@ Returns:
|
||||
|
||||
[
|
||||
{
|
||||
"destination": string,
|
||||
"gateway": string,
|
||||
"genmask": string,
|
||||
"flags": string,
|
||||
"metric": integer,
|
||||
"ref": integer,
|
||||
"use": integer,
|
||||
"mss": integer,
|
||||
"window": integer,
|
||||
"irtt": integer,
|
||||
"iface": string
|
||||
"destination": string,
|
||||
"gateway": string,
|
||||
"genmask": string,
|
||||
"flags": string,
|
||||
"flags_pretty": [
|
||||
string,
|
||||
]
|
||||
"metric": integer,
|
||||
"ref": integer,
|
||||
"use": integer,
|
||||
"mss": integer,
|
||||
"window": integer,
|
||||
"irtt": integer,
|
||||
"iface": string
|
||||
}
|
||||
]
|
||||
|
||||
|
||||
## parse
|
||||
```python
|
||||
parse(data, raw=False, quiet=False)
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
|
||||
# jc.parsers.shadow
|
||||
jc - JSON CLI output utility /etc/shadow file Parser
|
||||
|
||||
@@ -81,11 +82,13 @@ Examples:
|
||||
...
|
||||
]
|
||||
|
||||
|
||||
## info
|
||||
```python
|
||||
info(self, /, *args, **kwargs)
|
||||
info()
|
||||
```
|
||||
|
||||
|
||||
## process
|
||||
```python
|
||||
process(proc_data)
|
||||
@@ -114,6 +117,7 @@ Returns:
|
||||
}
|
||||
]
|
||||
|
||||
|
||||
## parse
|
||||
```python
|
||||
parse(data, raw=False, quiet=False)
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
|
||||
# jc.parsers.ss
|
||||
jc - JSON CLI output utility ss Parser
|
||||
|
||||
@@ -247,11 +248,13 @@ Examples:
|
||||
}
|
||||
]
|
||||
|
||||
|
||||
## info
|
||||
```python
|
||||
info(self, /, *args, **kwargs)
|
||||
info()
|
||||
```
|
||||
|
||||
|
||||
## process
|
||||
```python
|
||||
process(proc_data)
|
||||
@@ -289,6 +292,7 @@ Returns:
|
||||
|
||||
Information from https://www.cyberciti.biz/files/ss.html used to define field names
|
||||
|
||||
|
||||
## parse
|
||||
```python
|
||||
parse(data, raw=False, quiet=False)
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
|
||||
# jc.parsers.stat
|
||||
jc - JSON CLI output utility stat Parser
|
||||
|
||||
@@ -7,7 +8,7 @@ Usage:
|
||||
|
||||
Compatibility:
|
||||
|
||||
'linux'
|
||||
'linux', 'darwin', 'freebsd'
|
||||
|
||||
Examples:
|
||||
|
||||
@@ -101,11 +102,13 @@ Examples:
|
||||
..
|
||||
]
|
||||
|
||||
|
||||
## info
|
||||
```python
|
||||
info(self, /, *args, **kwargs)
|
||||
info()
|
||||
```
|
||||
|
||||
|
||||
## process
|
||||
```python
|
||||
process(proc_data)
|
||||
@@ -141,10 +144,15 @@ Returns:
|
||||
"access_time": string, # - = null
|
||||
"modify_time": string, # - = null
|
||||
"change_time": string, # - = null
|
||||
"birth_time": string # - = null
|
||||
"birth_time": string, # - = null
|
||||
"unix_device": integer,
|
||||
"rdev": integer,
|
||||
"block_size": integer,
|
||||
"unix_flags": string
|
||||
}
|
||||
]
|
||||
|
||||
|
||||
## parse
|
||||
```python
|
||||
parse(data, raw=False, quiet=False)
|
||||
|
||||
88
docs/parsers/sysctl.md
Normal file
88
docs/parsers/sysctl.md
Normal file
@@ -0,0 +1,88 @@
|
||||
|
||||
# jc.parsers.sysctl
|
||||
jc - JSON CLI output utility sysctl -a Parser
|
||||
|
||||
Usage:
|
||||
|
||||
specify --sysctl as the first argument if the piped input is coming from sysctl -a
|
||||
|
||||
Note: since sysctl output is not easily parsable only a very simple key/value object
|
||||
will be output. An attempt is made to convert obvious integers and floats. If no
|
||||
conversion is desired, use the -r (raw) option.
|
||||
|
||||
Compatibility:
|
||||
|
||||
'linux', 'darwin', 'freebsd'
|
||||
|
||||
Examples:
|
||||
|
||||
$ sysctl | jc --sysctl -p
|
||||
{
|
||||
"user.cs_path": "/usr/bin:/bin:/usr/sbin:/sbin",
|
||||
"user.bc_base_max": 99,
|
||||
"user.bc_dim_max": 2048,
|
||||
"user.bc_scale_max": 99,
|
||||
"user.bc_string_max": 1000,
|
||||
"user.coll_weights_max": 2,
|
||||
"user.expr_nest_max": 32
|
||||
...
|
||||
}
|
||||
|
||||
$ sysctl | jc --sysctl -p -r
|
||||
{
|
||||
"user.cs_path": "/usr/bin:/bin:/usr/sbin:/sbin",
|
||||
"user.bc_base_max": "99",
|
||||
"user.bc_dim_max": "2048",
|
||||
"user.bc_scale_max": "99",
|
||||
"user.bc_string_max": "1000",
|
||||
"user.coll_weights_max": "2",
|
||||
"user.expr_nest_max": "32",
|
||||
...
|
||||
}
|
||||
|
||||
|
||||
## info
|
||||
```python
|
||||
info()
|
||||
```
|
||||
|
||||
|
||||
## process
|
||||
```python
|
||||
process(proc_data)
|
||||
```
|
||||
|
||||
Final processing to conform to the schema.
|
||||
|
||||
Parameters:
|
||||
|
||||
proc_data: (dictionary) raw structured data to process
|
||||
|
||||
Returns:
|
||||
|
||||
Dictionary. Structured data with the following schema:
|
||||
|
||||
{
|
||||
"foo": string/integer/float, # best guess based on value
|
||||
"bar": string/integer/float,
|
||||
"baz": string/integer/float
|
||||
}
|
||||
|
||||
|
||||
## 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:
|
||||
|
||||
Dictionary. Raw or processed structured data.
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
|
||||
# jc.parsers.systemctl
|
||||
jc - JSON CLI output utility systemctl Parser
|
||||
|
||||
@@ -37,11 +38,13 @@ Examples:
|
||||
...
|
||||
]
|
||||
|
||||
|
||||
## info
|
||||
```python
|
||||
info(self, /, *args, **kwargs)
|
||||
info()
|
||||
```
|
||||
|
||||
|
||||
## process
|
||||
```python
|
||||
process(proc_data)
|
||||
@@ -67,6 +70,7 @@ Returns:
|
||||
}
|
||||
]
|
||||
|
||||
|
||||
## parse
|
||||
```python
|
||||
parse(data, raw=False, quiet=False)
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
|
||||
# jc.parsers.systemctl_lj
|
||||
jc - JSON CLI output utility systemctl-lj Parser
|
||||
|
||||
@@ -56,11 +57,13 @@ Examples:
|
||||
]
|
||||
|
||||
|
||||
|
||||
## info
|
||||
```python
|
||||
info(self, /, *args, **kwargs)
|
||||
info()
|
||||
```
|
||||
|
||||
|
||||
## process
|
||||
```python
|
||||
process(proc_data)
|
||||
@@ -85,6 +88,7 @@ Returns:
|
||||
}
|
||||
]
|
||||
|
||||
|
||||
## parse
|
||||
```python
|
||||
parse(data, raw=False, quiet=False)
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
|
||||
# jc.parsers.systemctl_ls
|
||||
jc - JSON CLI output utility systemctl-ls Parser
|
||||
|
||||
@@ -31,11 +32,13 @@ Examples:
|
||||
...
|
||||
]
|
||||
|
||||
|
||||
## info
|
||||
```python
|
||||
info(self, /, *args, **kwargs)
|
||||
info()
|
||||
```
|
||||
|
||||
|
||||
## process
|
||||
```python
|
||||
process(proc_data)
|
||||
@@ -59,6 +62,7 @@ Returns:
|
||||
}
|
||||
]
|
||||
|
||||
|
||||
## parse
|
||||
```python
|
||||
parse(data, raw=False, quiet=False)
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
|
||||
# jc.parsers.systemctl_luf
|
||||
jc - JSON CLI output utility systemctl-luf Parser
|
||||
|
||||
@@ -28,11 +29,13 @@ Examples:
|
||||
...
|
||||
]
|
||||
|
||||
|
||||
## info
|
||||
```python
|
||||
info(self, /, *args, **kwargs)
|
||||
info()
|
||||
```
|
||||
|
||||
|
||||
## process
|
||||
```python
|
||||
process(proc_data)
|
||||
@@ -55,6 +58,7 @@ Returns:
|
||||
}
|
||||
]
|
||||
|
||||
|
||||
## parse
|
||||
```python
|
||||
parse(data, raw=False, quiet=False)
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
|
||||
# jc.parsers.timedatectl
|
||||
jc - JSON CLI output utility timedatectl Parser
|
||||
|
||||
@@ -35,11 +36,13 @@ Examples:
|
||||
"dst_active": "yes"
|
||||
}
|
||||
|
||||
|
||||
## info
|
||||
```python
|
||||
info(self, /, *args, **kwargs)
|
||||
info()
|
||||
```
|
||||
|
||||
|
||||
## process
|
||||
```python
|
||||
process(proc_data)
|
||||
@@ -68,6 +71,7 @@ Returns:
|
||||
"dst_active": boolean
|
||||
}
|
||||
|
||||
|
||||
## parse
|
||||
```python
|
||||
parse(data, raw=False, quiet=False)
|
||||
|
||||
162
docs/parsers/tracepath.md
Normal file
162
docs/parsers/tracepath.md
Normal file
@@ -0,0 +1,162 @@
|
||||
|
||||
# jc.parsers.tracepath
|
||||
jc - JSON CLI output utility tracepath Parser
|
||||
|
||||
Usage:
|
||||
|
||||
specify --tracepath as the first argument if the piped input is coming from tracepath
|
||||
|
||||
Compatibility:
|
||||
|
||||
'linux'
|
||||
|
||||
Examples:
|
||||
|
||||
$ tracepath6 3ffe:2400:0:109::2 | jc --tracepath -p
|
||||
{
|
||||
"pmtu": 1480,
|
||||
"forward_hops": 2,
|
||||
"return_hops": 2,
|
||||
"hops": [
|
||||
{
|
||||
"ttl": 1,
|
||||
"guess": true,
|
||||
"host": "[LOCALHOST]",
|
||||
"reply_ms": null,
|
||||
"pmtu": 1500,
|
||||
"asymmetric_difference": null,
|
||||
"reached": false
|
||||
},
|
||||
{
|
||||
"ttl": 1,
|
||||
"guess": false,
|
||||
"host": "dust.inr.ac.ru",
|
||||
"reply_ms": 0.411,
|
||||
"pmtu": null,
|
||||
"asymmetric_difference": null,
|
||||
"reached": false
|
||||
},
|
||||
{
|
||||
"ttl": 2,
|
||||
"guess": false,
|
||||
"host": "dust.inr.ac.ru",
|
||||
"reply_ms": 0.39,
|
||||
"pmtu": 1480,
|
||||
"asymmetric_difference": 1,
|
||||
"reached": false
|
||||
},
|
||||
{
|
||||
"ttl": 2,
|
||||
"guess": false,
|
||||
"host": "3ffe:2400:0:109::2",
|
||||
"reply_ms": 463.514,
|
||||
"pmtu": null,
|
||||
"asymmetric_difference": null,
|
||||
"reached": true
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
$ tracepath6 3ffe:2400:0:109::2 | jc --tracepath -p -r
|
||||
{
|
||||
"pmtu": "1480",
|
||||
"forward_hops": "2",
|
||||
"return_hops": "2",
|
||||
"hops": [
|
||||
{
|
||||
"ttl": "1",
|
||||
"guess": true,
|
||||
"host": "[LOCALHOST]",
|
||||
"reply_ms": null,
|
||||
"pmtu": "1500",
|
||||
"asymmetric_difference": null,
|
||||
"reached": false
|
||||
},
|
||||
{
|
||||
"ttl": "1",
|
||||
"guess": false,
|
||||
"host": "dust.inr.ac.ru",
|
||||
"reply_ms": "0.411",
|
||||
"pmtu": null,
|
||||
"asymmetric_difference": null,
|
||||
"reached": false
|
||||
},
|
||||
{
|
||||
"ttl": "2",
|
||||
"guess": false,
|
||||
"host": "dust.inr.ac.ru",
|
||||
"reply_ms": "0.390",
|
||||
"pmtu": "1480",
|
||||
"asymmetric_difference": "1",
|
||||
"reached": false
|
||||
},
|
||||
{
|
||||
"ttl": "2",
|
||||
"guess": false,
|
||||
"host": "3ffe:2400:0:109::2",
|
||||
"reply_ms": "463.514",
|
||||
"pmtu": null,
|
||||
"asymmetric_difference": null,
|
||||
"reached": true
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
|
||||
|
||||
## info
|
||||
```python
|
||||
info()
|
||||
```
|
||||
|
||||
|
||||
## process
|
||||
```python
|
||||
process(proc_data)
|
||||
```
|
||||
|
||||
Final processing to conform to the schema.
|
||||
|
||||
Parameters:
|
||||
|
||||
proc_data: (dictionary) raw structured data to process
|
||||
|
||||
Returns:
|
||||
|
||||
Dictionary. Structured data with the following schema:
|
||||
|
||||
{
|
||||
"pmtu": integer,
|
||||
"forward_hops": integer,
|
||||
"return_hops": integer,
|
||||
"hops": [
|
||||
{
|
||||
"ttl": integer,
|
||||
"guess": boolean,
|
||||
"host": string,
|
||||
"reply_ms": float,
|
||||
"pmtu": integer,
|
||||
"asymmetric_difference": integer,
|
||||
"reached": boolean
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
|
||||
## 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:
|
||||
|
||||
Dictionary. Raw or processed structured data.
|
||||
|
||||
155
docs/parsers/traceroute.md
Normal file
155
docs/parsers/traceroute.md
Normal file
@@ -0,0 +1,155 @@
|
||||
|
||||
# jc.parsers.traceroute
|
||||
jc - JSON CLI output utility traceroute Parser
|
||||
|
||||
Usage:
|
||||
|
||||
specify --traceroute as the first argument if the piped input is coming from traceroute
|
||||
|
||||
Note: On some operating systems you will need to redirect STDERR to STDOUT for destination
|
||||
info since the header line is sent to STDERR. A warning message will be printed to
|
||||
STDERR if the header row is not found.
|
||||
|
||||
e.g. $ traceroute 8.8.8.8 2>&1 | jc --traceroute
|
||||
|
||||
Compatibility:
|
||||
|
||||
'linux', 'darwin', 'freebsd'
|
||||
|
||||
Examples:
|
||||
|
||||
$ traceroute google.com | jc --traceroute -p
|
||||
{
|
||||
"destination_ip": "216.58.194.46",
|
||||
"destination_name": "google.com",
|
||||
"hops": [
|
||||
{
|
||||
"hop": 1,
|
||||
"probes": [
|
||||
{
|
||||
"annotation": null,
|
||||
"asn": null,
|
||||
"ip": "216.230.231.141",
|
||||
"name": "216-230-231-141.static.houston.tx.oplink.net",
|
||||
"rtt": 198.574
|
||||
},
|
||||
{
|
||||
"annotation": null,
|
||||
"asn": null,
|
||||
"ip": "216.230.231.141",
|
||||
"name": "216-230-231-141.static.houston.tx.oplink.net",
|
||||
"rtt": null
|
||||
},
|
||||
{
|
||||
"annotation": null,
|
||||
"asn": null,
|
||||
"ip": "216.230.231.141",
|
||||
"name": "216-230-231-141.static.houston.tx.oplink.net",
|
||||
"rtt": 198.65
|
||||
}
|
||||
]
|
||||
},
|
||||
...
|
||||
]
|
||||
}
|
||||
|
||||
$ traceroute google.com | jc --traceroute -p -r
|
||||
{
|
||||
"destination_ip": "216.58.194.46",
|
||||
"destination_name": "google.com",
|
||||
"hops": [
|
||||
{
|
||||
"hop": "1",
|
||||
"probes": [
|
||||
{
|
||||
"annotation": null,
|
||||
"asn": null,
|
||||
"ip": "216.230.231.141",
|
||||
"name": "216-230-231-141.static.houston.tx.oplink.net",
|
||||
"rtt": "198.574"
|
||||
},
|
||||
{
|
||||
"annotation": null,
|
||||
"asn": null,
|
||||
"ip": "216.230.231.141",
|
||||
"name": "216-230-231-141.static.houston.tx.oplink.net",
|
||||
"rtt": null
|
||||
},
|
||||
{
|
||||
"annotation": null,
|
||||
"asn": null,
|
||||
"ip": "216.230.231.141",
|
||||
"name": "216-230-231-141.static.houston.tx.oplink.net",
|
||||
"rtt": "198.650"
|
||||
}
|
||||
]
|
||||
},
|
||||
...
|
||||
]
|
||||
}
|
||||
|
||||
|
||||
## info
|
||||
```python
|
||||
info()
|
||||
```
|
||||
|
||||
|
||||
## Hop
|
||||
```python
|
||||
Hop(idx)
|
||||
```
|
||||
|
||||
|
||||
## process
|
||||
```python
|
||||
process(proc_data)
|
||||
```
|
||||
|
||||
Final processing to conform to the schema.
|
||||
|
||||
Parameters:
|
||||
|
||||
proc_data: (dictionary) raw structured data to process
|
||||
|
||||
Returns:
|
||||
|
||||
Dictionary. Structured data with the following schema:
|
||||
|
||||
{
|
||||
"destination_ip": string,
|
||||
"destination_name": string,
|
||||
"hops": [
|
||||
{
|
||||
"hop": integer,
|
||||
"probes": [
|
||||
{
|
||||
"annotation": string,
|
||||
"asn": integer,
|
||||
"ip": string,
|
||||
"name": string,
|
||||
"rtt": float
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
|
||||
## 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:
|
||||
|
||||
Dictionary. Raw or processed structured data.
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
|
||||
# jc.parsers.uname
|
||||
jc - JSON CLI output utility uname Parser
|
||||
|
||||
@@ -11,7 +12,7 @@ Limitations:
|
||||
|
||||
Compatibility:
|
||||
|
||||
'linux', 'darwin'
|
||||
'linux', 'darwin', 'freebsd'
|
||||
|
||||
Example:
|
||||
|
||||
@@ -27,11 +28,13 @@ Example:
|
||||
"kernel_version": "#74-Ubuntu SMP Tue Sep 17 17:06:04 UTC 2019"
|
||||
}
|
||||
|
||||
|
||||
## info
|
||||
```python
|
||||
info(self, /, *args, **kwargs)
|
||||
info()
|
||||
```
|
||||
|
||||
|
||||
## process
|
||||
```python
|
||||
process(proc_data)
|
||||
@@ -58,6 +61,7 @@ Returns:
|
||||
"kernel_version": string
|
||||
}
|
||||
|
||||
|
||||
## parse
|
||||
```python
|
||||
parse(data, raw=False, quiet=False)
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
|
||||
# jc.parsers.uptime
|
||||
jc - JSON CLI output utility uptime Parser
|
||||
|
||||
@@ -31,11 +32,13 @@ Example:
|
||||
"load_15m": "0.05"
|
||||
}
|
||||
|
||||
|
||||
## info
|
||||
```python
|
||||
info(self, /, *args, **kwargs)
|
||||
info()
|
||||
```
|
||||
|
||||
|
||||
## process
|
||||
```python
|
||||
process(proc_data)
|
||||
@@ -60,6 +63,7 @@ Returns:
|
||||
"load_15m": float
|
||||
}
|
||||
|
||||
|
||||
## parse
|
||||
```python
|
||||
parse(data, raw=False, quiet=False)
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
|
||||
# jc.parsers.w
|
||||
jc - JSON CLI output utility w Parser
|
||||
|
||||
@@ -79,11 +80,13 @@ Examples:
|
||||
}
|
||||
]
|
||||
|
||||
|
||||
## info
|
||||
```python
|
||||
info(self, /, *args, **kwargs)
|
||||
info()
|
||||
```
|
||||
|
||||
|
||||
## process
|
||||
```python
|
||||
process(proc_data)
|
||||
@@ -112,6 +115,7 @@ Returns:
|
||||
}
|
||||
]
|
||||
|
||||
|
||||
## parse
|
||||
```python
|
||||
parse(data, raw=False, quiet=False)
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
|
||||
# jc.parsers.who
|
||||
jc - JSON CLI output utility who Parser
|
||||
|
||||
@@ -99,11 +100,13 @@ Examples:
|
||||
}
|
||||
]
|
||||
|
||||
|
||||
## info
|
||||
```python
|
||||
info(self, /, *args, **kwargs)
|
||||
info()
|
||||
```
|
||||
|
||||
|
||||
## process
|
||||
```python
|
||||
process(proc_data)
|
||||
@@ -133,6 +136,7 @@ Returns:
|
||||
}
|
||||
]
|
||||
|
||||
|
||||
## parse
|
||||
```python
|
||||
parse(data, raw=False, quiet=False)
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
|
||||
# jc.parsers.xml
|
||||
jc - JSON CLI output utility XML Parser
|
||||
|
||||
@@ -55,11 +56,13 @@ Examples:
|
||||
...
|
||||
}
|
||||
|
||||
|
||||
## info
|
||||
```python
|
||||
info(self, /, *args, **kwargs)
|
||||
info()
|
||||
```
|
||||
|
||||
|
||||
## process
|
||||
```python
|
||||
process(proc_data)
|
||||
@@ -80,6 +83,7 @@ Returns:
|
||||
See https://github.com/martinblech/xmltodict for details
|
||||
}
|
||||
|
||||
|
||||
## parse
|
||||
```python
|
||||
parse(data, raw=False, quiet=False)
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
|
||||
# jc.parsers.yaml
|
||||
jc - JSON CLI output utility YAML Parser
|
||||
|
||||
@@ -67,11 +68,13 @@ Examples:
|
||||
}
|
||||
]
|
||||
|
||||
|
||||
## info
|
||||
```python
|
||||
info(self, /, *args, **kwargs)
|
||||
info()
|
||||
```
|
||||
|
||||
|
||||
## process
|
||||
```python
|
||||
process(proc_data)
|
||||
@@ -94,6 +97,7 @@ Returns:
|
||||
}
|
||||
]
|
||||
|
||||
|
||||
## parse
|
||||
```python
|
||||
parse(data, raw=False, quiet=False)
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
|
||||
# jc
|
||||
JC - JSON CLI output utility
|
||||
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
|
||||
# utils
|
||||
jc - JSON CLI output utility utils
|
||||
|
||||
## warning_message
|
||||
```python
|
||||
warning_message(message)
|
||||
@@ -15,6 +17,7 @@ Returns:
|
||||
|
||||
no return, just prints output to STDERR
|
||||
|
||||
|
||||
## error_message
|
||||
```python
|
||||
error_message(message)
|
||||
@@ -30,6 +33,7 @@ Returns:
|
||||
|
||||
no return, just prints output to STDERR
|
||||
|
||||
|
||||
## compatibility
|
||||
```python
|
||||
compatibility(mod_name, compatible)
|
||||
@@ -48,3 +52,19 @@ Returns:
|
||||
|
||||
no return, just prints output to STDERR
|
||||
|
||||
|
||||
## has_data
|
||||
```python
|
||||
has_data(data)
|
||||
```
|
||||
|
||||
Checks if the input contains data. If there are any non-whitespace characters then return True, else return False
|
||||
|
||||
Parameters:
|
||||
|
||||
data: (string) input to check whether it contains data
|
||||
|
||||
Returns:
|
||||
|
||||
Boolean True if input string (data) contains non-whitespace characters, otherwise False
|
||||
|
||||
|
||||
611
jc/appdirs.py
Normal file
611
jc/appdirs.py
Normal file
@@ -0,0 +1,611 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# Copyright (c) 2005-2010 ActiveState Software Inc.
|
||||
# Copyright (c) 2013 Eddy Petrișor
|
||||
|
||||
'''
|
||||
# This is the MIT license
|
||||
|
||||
Copyright (c) 2010 ActiveState Software Inc.
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a
|
||||
copy of this software and associated documentation files (the
|
||||
"Software"), to deal in the Software without restriction, including
|
||||
without limitation the rights to use, copy, modify, merge, publish,
|
||||
distribute, sublicense, and/or sell copies of the Software, and to
|
||||
permit persons to whom the Software is furnished to do so, subject to
|
||||
the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included
|
||||
in all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
|
||||
OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
|
||||
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
|
||||
TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
||||
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
'''
|
||||
|
||||
"""Utilities for determining application-specific dirs.
|
||||
|
||||
See <https://github.com/ActiveState/appdirs> for details and usage.
|
||||
"""
|
||||
# Dev Notes:
|
||||
# - MSDN on where to store app data files:
|
||||
# http://support.microsoft.com/default.aspx?scid=kb;en-us;310294#XSLTH3194121123120121120120
|
||||
# - Mac OS X: http://developer.apple.com/documentation/MacOSX/Conceptual/BPFileSystem/index.html
|
||||
# - XDG spec for Un*x: https://standards.freedesktop.org/basedir-spec/basedir-spec-latest.html
|
||||
|
||||
__version__ = "1.4.4"
|
||||
__version_info__ = tuple(int(segment) for segment in __version__.split("."))
|
||||
|
||||
|
||||
import sys
|
||||
import os
|
||||
|
||||
PY3 = sys.version_info[0] == 3
|
||||
|
||||
if PY3:
|
||||
unicode = str
|
||||
|
||||
if sys.platform.startswith('java'):
|
||||
import platform
|
||||
os_name = platform.java_ver()[3][0]
|
||||
if os_name.startswith('Windows'): # "Windows XP", "Windows 7", etc.
|
||||
system = 'win32'
|
||||
elif os_name.startswith('Mac'): # "Mac OS X", etc.
|
||||
system = 'darwin'
|
||||
else: # "Linux", "SunOS", "FreeBSD", etc.
|
||||
# Setting this to "linux2" is not ideal, but only Windows or Mac
|
||||
# are actually checked for and the rest of the module expects
|
||||
# *sys.platform* style strings.
|
||||
system = 'linux2'
|
||||
else:
|
||||
system = sys.platform
|
||||
|
||||
|
||||
|
||||
def user_data_dir(appname=None, appauthor=None, version=None, roaming=False):
|
||||
r"""Return full path to the user-specific data dir for this application.
|
||||
|
||||
"appname" is the name of application.
|
||||
If None, just the system directory is returned.
|
||||
"appauthor" (only used on Windows) is the name of the
|
||||
appauthor or distributing body for this application. Typically
|
||||
it is the owning company name. This falls back to appname. You may
|
||||
pass False to disable it.
|
||||
"version" is an optional version path element to append to the
|
||||
path. You might want to use this if you want multiple versions
|
||||
of your app to be able to run independently. If used, this
|
||||
would typically be "<major>.<minor>".
|
||||
Only applied when appname is present.
|
||||
"roaming" (boolean, default False) can be set True to use the Windows
|
||||
roaming appdata directory. That means that for users on a Windows
|
||||
network setup for roaming profiles, this user data will be
|
||||
sync'd on login. See
|
||||
<http://technet.microsoft.com/en-us/library/cc766489(WS.10).aspx>
|
||||
for a discussion of issues.
|
||||
|
||||
Typical user data directories are:
|
||||
Mac OS X: ~/Library/Application Support/<AppName>
|
||||
Unix: ~/.local/share/<AppName> # or in $XDG_DATA_HOME, if defined
|
||||
Win XP (not roaming): C:\Documents and Settings\<username>\Application Data\<AppAuthor>\<AppName>
|
||||
Win XP (roaming): C:\Documents and Settings\<username>\Local Settings\Application Data\<AppAuthor>\<AppName>
|
||||
Win 7 (not roaming): C:\Users\<username>\AppData\Local\<AppAuthor>\<AppName>
|
||||
Win 7 (roaming): C:\Users\<username>\AppData\Roaming\<AppAuthor>\<AppName>
|
||||
|
||||
For Unix, we follow the XDG spec and support $XDG_DATA_HOME.
|
||||
That means, by default "~/.local/share/<AppName>".
|
||||
"""
|
||||
if system == "win32":
|
||||
if appauthor is None:
|
||||
appauthor = appname
|
||||
const = roaming and "CSIDL_APPDATA" or "CSIDL_LOCAL_APPDATA"
|
||||
path = os.path.normpath(_get_win_folder(const))
|
||||
if appname:
|
||||
if appauthor is not False:
|
||||
path = os.path.join(path, appauthor, appname)
|
||||
else:
|
||||
path = os.path.join(path, appname)
|
||||
elif system == 'darwin':
|
||||
path = os.path.expanduser('~/Library/Application Support/')
|
||||
if appname:
|
||||
path = os.path.join(path, appname)
|
||||
else:
|
||||
path = os.getenv('XDG_DATA_HOME', os.path.expanduser("~/.local/share"))
|
||||
if appname:
|
||||
path = os.path.join(path, appname)
|
||||
if appname and version:
|
||||
path = os.path.join(path, version)
|
||||
return path
|
||||
|
||||
|
||||
def site_data_dir(appname=None, appauthor=None, version=None, multipath=False):
|
||||
r"""Return full path to the user-shared data dir for this application.
|
||||
|
||||
"appname" is the name of application.
|
||||
If None, just the system directory is returned.
|
||||
"appauthor" (only used on Windows) is the name of the
|
||||
appauthor or distributing body for this application. Typically
|
||||
it is the owning company name. This falls back to appname. You may
|
||||
pass False to disable it.
|
||||
"version" is an optional version path element to append to the
|
||||
path. You might want to use this if you want multiple versions
|
||||
of your app to be able to run independently. If used, this
|
||||
would typically be "<major>.<minor>".
|
||||
Only applied when appname is present.
|
||||
"multipath" is an optional parameter only applicable to *nix
|
||||
which indicates that the entire list of data dirs should be
|
||||
returned. By default, the first item from XDG_DATA_DIRS is
|
||||
returned, or '/usr/local/share/<AppName>',
|
||||
if XDG_DATA_DIRS is not set
|
||||
|
||||
Typical site data directories are:
|
||||
Mac OS X: /Library/Application Support/<AppName>
|
||||
Unix: /usr/local/share/<AppName> or /usr/share/<AppName>
|
||||
Win XP: C:\Documents and Settings\All Users\Application Data\<AppAuthor>\<AppName>
|
||||
Vista: (Fail! "C:\ProgramData" is a hidden *system* directory on Vista.)
|
||||
Win 7: C:\ProgramData\<AppAuthor>\<AppName> # Hidden, but writeable on Win 7.
|
||||
|
||||
For Unix, this is using the $XDG_DATA_DIRS[0] default.
|
||||
|
||||
WARNING: Do not use this on Windows. See the Vista-Fail note above for why.
|
||||
"""
|
||||
if system == "win32":
|
||||
if appauthor is None:
|
||||
appauthor = appname
|
||||
path = os.path.normpath(_get_win_folder("CSIDL_COMMON_APPDATA"))
|
||||
if appname:
|
||||
if appauthor is not False:
|
||||
path = os.path.join(path, appauthor, appname)
|
||||
else:
|
||||
path = os.path.join(path, appname)
|
||||
elif system == 'darwin':
|
||||
path = os.path.expanduser('/Library/Application Support')
|
||||
if appname:
|
||||
path = os.path.join(path, appname)
|
||||
else:
|
||||
# XDG default for $XDG_DATA_DIRS
|
||||
# only first, if multipath is False
|
||||
path = os.getenv('XDG_DATA_DIRS',
|
||||
os.pathsep.join(['/usr/local/share', '/usr/share']))
|
||||
pathlist = [os.path.expanduser(x.rstrip(os.sep)) for x in path.split(os.pathsep)]
|
||||
if appname:
|
||||
if version:
|
||||
appname = os.path.join(appname, version)
|
||||
pathlist = [os.sep.join([x, appname]) for x in pathlist]
|
||||
|
||||
if multipath:
|
||||
path = os.pathsep.join(pathlist)
|
||||
else:
|
||||
path = pathlist[0]
|
||||
return path
|
||||
|
||||
if appname and version:
|
||||
path = os.path.join(path, version)
|
||||
return path
|
||||
|
||||
|
||||
def user_config_dir(appname=None, appauthor=None, version=None, roaming=False):
|
||||
r"""Return full path to the user-specific config dir for this application.
|
||||
|
||||
"appname" is the name of application.
|
||||
If None, just the system directory is returned.
|
||||
"appauthor" (only used on Windows) is the name of the
|
||||
appauthor or distributing body for this application. Typically
|
||||
it is the owning company name. This falls back to appname. You may
|
||||
pass False to disable it.
|
||||
"version" is an optional version path element to append to the
|
||||
path. You might want to use this if you want multiple versions
|
||||
of your app to be able to run independently. If used, this
|
||||
would typically be "<major>.<minor>".
|
||||
Only applied when appname is present.
|
||||
"roaming" (boolean, default False) can be set True to use the Windows
|
||||
roaming appdata directory. That means that for users on a Windows
|
||||
network setup for roaming profiles, this user data will be
|
||||
sync'd on login. See
|
||||
<http://technet.microsoft.com/en-us/library/cc766489(WS.10).aspx>
|
||||
for a discussion of issues.
|
||||
|
||||
Typical user config directories are:
|
||||
Mac OS X: ~/Library/Preferences/<AppName>
|
||||
Unix: ~/.config/<AppName> # or in $XDG_CONFIG_HOME, if defined
|
||||
Win *: same as user_data_dir
|
||||
|
||||
For Unix, we follow the XDG spec and support $XDG_CONFIG_HOME.
|
||||
That means, by default "~/.config/<AppName>".
|
||||
"""
|
||||
if system == "win32":
|
||||
path = user_data_dir(appname, appauthor, None, roaming)
|
||||
elif system == 'darwin':
|
||||
path = os.path.expanduser('~/Library/Preferences/')
|
||||
if appname:
|
||||
path = os.path.join(path, appname)
|
||||
else:
|
||||
path = os.getenv('XDG_CONFIG_HOME', os.path.expanduser("~/.config"))
|
||||
if appname:
|
||||
path = os.path.join(path, appname)
|
||||
if appname and version:
|
||||
path = os.path.join(path, version)
|
||||
return path
|
||||
|
||||
|
||||
def site_config_dir(appname=None, appauthor=None, version=None, multipath=False):
|
||||
r"""Return full path to the user-shared data dir for this application.
|
||||
|
||||
"appname" is the name of application.
|
||||
If None, just the system directory is returned.
|
||||
"appauthor" (only used on Windows) is the name of the
|
||||
appauthor or distributing body for this application. Typically
|
||||
it is the owning company name. This falls back to appname. You may
|
||||
pass False to disable it.
|
||||
"version" is an optional version path element to append to the
|
||||
path. You might want to use this if you want multiple versions
|
||||
of your app to be able to run independently. If used, this
|
||||
would typically be "<major>.<minor>".
|
||||
Only applied when appname is present.
|
||||
"multipath" is an optional parameter only applicable to *nix
|
||||
which indicates that the entire list of config dirs should be
|
||||
returned. By default, the first item from XDG_CONFIG_DIRS is
|
||||
returned, or '/etc/xdg/<AppName>', if XDG_CONFIG_DIRS is not set
|
||||
|
||||
Typical site config directories are:
|
||||
Mac OS X: same as site_data_dir
|
||||
Unix: /etc/xdg/<AppName> or $XDG_CONFIG_DIRS[i]/<AppName> for each value in
|
||||
$XDG_CONFIG_DIRS
|
||||
Win *: same as site_data_dir
|
||||
Vista: (Fail! "C:\ProgramData" is a hidden *system* directory on Vista.)
|
||||
|
||||
For Unix, this is using the $XDG_CONFIG_DIRS[0] default, if multipath=False
|
||||
|
||||
WARNING: Do not use this on Windows. See the Vista-Fail note above for why.
|
||||
"""
|
||||
if system == 'win32':
|
||||
path = site_data_dir(appname, appauthor)
|
||||
if appname and version:
|
||||
path = os.path.join(path, version)
|
||||
elif system == 'darwin':
|
||||
path = os.path.expanduser('/Library/Preferences')
|
||||
if appname:
|
||||
path = os.path.join(path, appname)
|
||||
else:
|
||||
# XDG default for $XDG_CONFIG_DIRS
|
||||
# only first, if multipath is False
|
||||
path = os.getenv('XDG_CONFIG_DIRS', '/etc/xdg')
|
||||
pathlist = [os.path.expanduser(x.rstrip(os.sep)) for x in path.split(os.pathsep)]
|
||||
if appname:
|
||||
if version:
|
||||
appname = os.path.join(appname, version)
|
||||
pathlist = [os.sep.join([x, appname]) for x in pathlist]
|
||||
|
||||
if multipath:
|
||||
path = os.pathsep.join(pathlist)
|
||||
else:
|
||||
path = pathlist[0]
|
||||
return path
|
||||
|
||||
|
||||
def user_cache_dir(appname=None, appauthor=None, version=None, opinion=True):
|
||||
r"""Return full path to the user-specific cache dir for this application.
|
||||
|
||||
"appname" is the name of application.
|
||||
If None, just the system directory is returned.
|
||||
"appauthor" (only used on Windows) is the name of the
|
||||
appauthor or distributing body for this application. Typically
|
||||
it is the owning company name. This falls back to appname. You may
|
||||
pass False to disable it.
|
||||
"version" is an optional version path element to append to the
|
||||
path. You might want to use this if you want multiple versions
|
||||
of your app to be able to run independently. If used, this
|
||||
would typically be "<major>.<minor>".
|
||||
Only applied when appname is present.
|
||||
"opinion" (boolean) can be False to disable the appending of
|
||||
"Cache" to the base app data dir for Windows. See
|
||||
discussion below.
|
||||
|
||||
Typical user cache directories are:
|
||||
Mac OS X: ~/Library/Caches/<AppName>
|
||||
Unix: ~/.cache/<AppName> (XDG default)
|
||||
Win XP: C:\Documents and Settings\<username>\Local Settings\Application Data\<AppAuthor>\<AppName>\Cache
|
||||
Vista: C:\Users\<username>\AppData\Local\<AppAuthor>\<AppName>\Cache
|
||||
|
||||
On Windows the only suggestion in the MSDN docs is that local settings go in
|
||||
the `CSIDL_LOCAL_APPDATA` directory. This is identical to the non-roaming
|
||||
app data dir (the default returned by `user_data_dir` above). Apps typically
|
||||
put cache data somewhere *under* the given dir here. Some examples:
|
||||
...\Mozilla\Firefox\Profiles\<ProfileName>\Cache
|
||||
...\Acme\SuperApp\Cache\1.0
|
||||
OPINION: This function appends "Cache" to the `CSIDL_LOCAL_APPDATA` value.
|
||||
This can be disabled with the `opinion=False` option.
|
||||
"""
|
||||
if system == "win32":
|
||||
if appauthor is None:
|
||||
appauthor = appname
|
||||
path = os.path.normpath(_get_win_folder("CSIDL_LOCAL_APPDATA"))
|
||||
if appname:
|
||||
if appauthor is not False:
|
||||
path = os.path.join(path, appauthor, appname)
|
||||
else:
|
||||
path = os.path.join(path, appname)
|
||||
if opinion:
|
||||
path = os.path.join(path, "Cache")
|
||||
elif system == 'darwin':
|
||||
path = os.path.expanduser('~/Library/Caches')
|
||||
if appname:
|
||||
path = os.path.join(path, appname)
|
||||
else:
|
||||
path = os.getenv('XDG_CACHE_HOME', os.path.expanduser('~/.cache'))
|
||||
if appname:
|
||||
path = os.path.join(path, appname)
|
||||
if appname and version:
|
||||
path = os.path.join(path, version)
|
||||
return path
|
||||
|
||||
|
||||
def user_state_dir(appname=None, appauthor=None, version=None, roaming=False):
|
||||
r"""Return full path to the user-specific state dir for this application.
|
||||
|
||||
"appname" is the name of application.
|
||||
If None, just the system directory is returned.
|
||||
"appauthor" (only used on Windows) is the name of the
|
||||
appauthor or distributing body for this application. Typically
|
||||
it is the owning company name. This falls back to appname. You may
|
||||
pass False to disable it.
|
||||
"version" is an optional version path element to append to the
|
||||
path. You might want to use this if you want multiple versions
|
||||
of your app to be able to run independently. If used, this
|
||||
would typically be "<major>.<minor>".
|
||||
Only applied when appname is present.
|
||||
"roaming" (boolean, default False) can be set True to use the Windows
|
||||
roaming appdata directory. That means that for users on a Windows
|
||||
network setup for roaming profiles, this user data will be
|
||||
sync'd on login. See
|
||||
<http://technet.microsoft.com/en-us/library/cc766489(WS.10).aspx>
|
||||
for a discussion of issues.
|
||||
|
||||
Typical user state directories are:
|
||||
Mac OS X: same as user_data_dir
|
||||
Unix: ~/.local/state/<AppName> # or in $XDG_STATE_HOME, if defined
|
||||
Win *: same as user_data_dir
|
||||
|
||||
For Unix, we follow this Debian proposal <https://wiki.debian.org/XDGBaseDirectorySpecification#state>
|
||||
to extend the XDG spec and support $XDG_STATE_HOME.
|
||||
|
||||
That means, by default "~/.local/state/<AppName>".
|
||||
"""
|
||||
if system in ["win32", "darwin"]:
|
||||
path = user_data_dir(appname, appauthor, None, roaming)
|
||||
else:
|
||||
path = os.getenv('XDG_STATE_HOME', os.path.expanduser("~/.local/state"))
|
||||
if appname:
|
||||
path = os.path.join(path, appname)
|
||||
if appname and version:
|
||||
path = os.path.join(path, version)
|
||||
return path
|
||||
|
||||
|
||||
def user_log_dir(appname=None, appauthor=None, version=None, opinion=True):
|
||||
r"""Return full path to the user-specific log dir for this application.
|
||||
|
||||
"appname" is the name of application.
|
||||
If None, just the system directory is returned.
|
||||
"appauthor" (only used on Windows) is the name of the
|
||||
appauthor or distributing body for this application. Typically
|
||||
it is the owning company name. This falls back to appname. You may
|
||||
pass False to disable it.
|
||||
"version" is an optional version path element to append to the
|
||||
path. You might want to use this if you want multiple versions
|
||||
of your app to be able to run independently. If used, this
|
||||
would typically be "<major>.<minor>".
|
||||
Only applied when appname is present.
|
||||
"opinion" (boolean) can be False to disable the appending of
|
||||
"Logs" to the base app data dir for Windows, and "log" to the
|
||||
base cache dir for Unix. See discussion below.
|
||||
|
||||
Typical user log directories are:
|
||||
Mac OS X: ~/Library/Logs/<AppName>
|
||||
Unix: ~/.cache/<AppName>/log # or under $XDG_CACHE_HOME if defined
|
||||
Win XP: C:\Documents and Settings\<username>\Local Settings\Application Data\<AppAuthor>\<AppName>\Logs
|
||||
Vista: C:\Users\<username>\AppData\Local\<AppAuthor>\<AppName>\Logs
|
||||
|
||||
On Windows the only suggestion in the MSDN docs is that local settings
|
||||
go in the `CSIDL_LOCAL_APPDATA` directory. (Note: I'm interested in
|
||||
examples of what some windows apps use for a logs dir.)
|
||||
|
||||
OPINION: This function appends "Logs" to the `CSIDL_LOCAL_APPDATA`
|
||||
value for Windows and appends "log" to the user cache dir for Unix.
|
||||
This can be disabled with the `opinion=False` option.
|
||||
"""
|
||||
if system == "darwin":
|
||||
path = os.path.join(
|
||||
os.path.expanduser('~/Library/Logs'),
|
||||
appname)
|
||||
elif system == "win32":
|
||||
path = user_data_dir(appname, appauthor, version)
|
||||
version = False
|
||||
if opinion:
|
||||
path = os.path.join(path, "Logs")
|
||||
else:
|
||||
path = user_cache_dir(appname, appauthor, version)
|
||||
version = False
|
||||
if opinion:
|
||||
path = os.path.join(path, "log")
|
||||
if appname and version:
|
||||
path = os.path.join(path, version)
|
||||
return path
|
||||
|
||||
|
||||
class AppDirs(object):
|
||||
"""Convenience wrapper for getting application dirs."""
|
||||
def __init__(self, appname=None, appauthor=None, version=None,
|
||||
roaming=False, multipath=False):
|
||||
self.appname = appname
|
||||
self.appauthor = appauthor
|
||||
self.version = version
|
||||
self.roaming = roaming
|
||||
self.multipath = multipath
|
||||
|
||||
@property
|
||||
def user_data_dir(self):
|
||||
return user_data_dir(self.appname, self.appauthor,
|
||||
version=self.version, roaming=self.roaming)
|
||||
|
||||
@property
|
||||
def site_data_dir(self):
|
||||
return site_data_dir(self.appname, self.appauthor,
|
||||
version=self.version, multipath=self.multipath)
|
||||
|
||||
@property
|
||||
def user_config_dir(self):
|
||||
return user_config_dir(self.appname, self.appauthor,
|
||||
version=self.version, roaming=self.roaming)
|
||||
|
||||
@property
|
||||
def site_config_dir(self):
|
||||
return site_config_dir(self.appname, self.appauthor,
|
||||
version=self.version, multipath=self.multipath)
|
||||
|
||||
@property
|
||||
def user_cache_dir(self):
|
||||
return user_cache_dir(self.appname, self.appauthor,
|
||||
version=self.version)
|
||||
|
||||
@property
|
||||
def user_state_dir(self):
|
||||
return user_state_dir(self.appname, self.appauthor,
|
||||
version=self.version)
|
||||
|
||||
@property
|
||||
def user_log_dir(self):
|
||||
return user_log_dir(self.appname, self.appauthor,
|
||||
version=self.version)
|
||||
|
||||
|
||||
#---- internal support stuff
|
||||
|
||||
def _get_win_folder_from_registry(csidl_name):
|
||||
"""This is a fallback technique at best. I'm not sure if using the
|
||||
registry for this guarantees us the correct answer for all CSIDL_*
|
||||
names.
|
||||
"""
|
||||
if PY3:
|
||||
import winreg as _winreg
|
||||
else:
|
||||
import _winreg
|
||||
|
||||
shell_folder_name = {
|
||||
"CSIDL_APPDATA": "AppData",
|
||||
"CSIDL_COMMON_APPDATA": "Common AppData",
|
||||
"CSIDL_LOCAL_APPDATA": "Local AppData",
|
||||
}[csidl_name]
|
||||
|
||||
key = _winreg.OpenKey(
|
||||
_winreg.HKEY_CURRENT_USER,
|
||||
r"Software\Microsoft\Windows\CurrentVersion\Explorer\Shell Folders"
|
||||
)
|
||||
dir, type = _winreg.QueryValueEx(key, shell_folder_name)
|
||||
return dir
|
||||
|
||||
|
||||
def _get_win_folder_with_ctypes(csidl_name):
|
||||
import ctypes
|
||||
|
||||
csidl_const = {
|
||||
"CSIDL_APPDATA": 26,
|
||||
"CSIDL_COMMON_APPDATA": 35,
|
||||
"CSIDL_LOCAL_APPDATA": 28,
|
||||
}[csidl_name]
|
||||
|
||||
buf = ctypes.create_unicode_buffer(1024)
|
||||
ctypes.windll.shell32.SHGetFolderPathW(None, csidl_const, None, 0, buf)
|
||||
|
||||
# Downgrade to short path name if have highbit chars. See
|
||||
# <http://bugs.activestate.com/show_bug.cgi?id=85099>.
|
||||
has_high_char = False
|
||||
for c in buf:
|
||||
if ord(c) > 255:
|
||||
has_high_char = True
|
||||
break
|
||||
if has_high_char:
|
||||
buf2 = ctypes.create_unicode_buffer(1024)
|
||||
if ctypes.windll.kernel32.GetShortPathNameW(buf.value, buf2, 1024):
|
||||
buf = buf2
|
||||
|
||||
return buf.value
|
||||
|
||||
def _get_win_folder_with_jna(csidl_name):
|
||||
import array
|
||||
from com.sun import jna
|
||||
from com.sun.jna.platform import win32
|
||||
|
||||
buf_size = win32.WinDef.MAX_PATH * 2
|
||||
buf = array.zeros('c', buf_size)
|
||||
shell = win32.Shell32.INSTANCE
|
||||
shell.SHGetFolderPath(None, getattr(win32.ShlObj, csidl_name), None, win32.ShlObj.SHGFP_TYPE_CURRENT, buf)
|
||||
dir = jna.Native.toString(buf.tostring()).rstrip("\0")
|
||||
|
||||
# Downgrade to short path name if have highbit chars. See
|
||||
# <http://bugs.activestate.com/show_bug.cgi?id=85099>.
|
||||
has_high_char = False
|
||||
for c in dir:
|
||||
if ord(c) > 255:
|
||||
has_high_char = True
|
||||
break
|
||||
if has_high_char:
|
||||
buf = array.zeros('c', buf_size)
|
||||
kernel = win32.Kernel32.INSTANCE
|
||||
if kernel.GetShortPathName(dir, buf, buf_size):
|
||||
dir = jna.Native.toString(buf.tostring()).rstrip("\0")
|
||||
|
||||
return dir
|
||||
|
||||
if system == "win32":
|
||||
try:
|
||||
from ctypes import windll
|
||||
except ImportError:
|
||||
try:
|
||||
import com.sun.jna
|
||||
except ImportError:
|
||||
_get_win_folder = _get_win_folder_from_registry
|
||||
else:
|
||||
_get_win_folder = _get_win_folder_with_jna
|
||||
else:
|
||||
_get_win_folder = _get_win_folder_with_ctypes
|
||||
|
||||
|
||||
#---- self test code
|
||||
|
||||
if __name__ == "__main__":
|
||||
appname = "MyApp"
|
||||
appauthor = "MyCompany"
|
||||
|
||||
props = ("user_data_dir",
|
||||
"user_config_dir",
|
||||
"user_cache_dir",
|
||||
"user_state_dir",
|
||||
"user_log_dir",
|
||||
"site_data_dir",
|
||||
"site_config_dir")
|
||||
|
||||
print("-- app dirs %s --" % __version__)
|
||||
|
||||
print("-- app dirs (with optional 'version')")
|
||||
dirs = AppDirs(appname, appauthor, version="1.0")
|
||||
for prop in props:
|
||||
print("%s: %s" % (prop, getattr(dirs, prop)))
|
||||
|
||||
print("\n-- app dirs (without optional 'version')")
|
||||
dirs = AppDirs(appname, appauthor)
|
||||
for prop in props:
|
||||
print("%s: %s" % (prop, getattr(dirs, prop)))
|
||||
|
||||
print("\n-- app dirs (without optional 'appauthor')")
|
||||
dirs = AppDirs(appname)
|
||||
for prop in props:
|
||||
print("%s: %s" % (prop, getattr(dirs, prop)))
|
||||
|
||||
print("\n-- app dirs (with disabled 'appauthor')")
|
||||
dirs = AppDirs(appname, appauthor=False)
|
||||
for prop in props:
|
||||
print("%s: %s" % (prop, getattr(dirs, prop)))
|
||||
205
jc/cli.py
205
jc/cli.py
@@ -1,24 +1,28 @@
|
||||
"""jc - JSON CLI output utility
|
||||
JC cli module
|
||||
"""
|
||||
|
||||
import sys
|
||||
import os
|
||||
import os.path
|
||||
import re
|
||||
import shlex
|
||||
import importlib
|
||||
import textwrap
|
||||
import signal
|
||||
import json
|
||||
import pygments
|
||||
from pygments import highlight
|
||||
from pygments.style import Style
|
||||
from pygments.token import (Name, Number, String, Keyword)
|
||||
from pygments.lexers import JsonLexer
|
||||
from pygments.formatters import Terminal256Formatter
|
||||
import jc.utils
|
||||
import jc.appdirs as appdirs
|
||||
|
||||
|
||||
class info():
|
||||
version = '1.10.12'
|
||||
description = 'jc cli output JSON conversion tool'
|
||||
version = '1.13.2'
|
||||
description = 'JSON CLI output utility'
|
||||
author = 'Kelly Brazil'
|
||||
author_email = 'kellyjonbrazil@gmail.com'
|
||||
|
||||
@@ -33,8 +37,10 @@ parsers = [
|
||||
'crontab',
|
||||
'crontab-u',
|
||||
'csv',
|
||||
'date',
|
||||
'df',
|
||||
'dig',
|
||||
'dmidecode',
|
||||
'du',
|
||||
'env',
|
||||
'file',
|
||||
@@ -49,6 +55,7 @@ parsers = [
|
||||
'ini',
|
||||
'iptables',
|
||||
'jobs',
|
||||
'kv',
|
||||
'last',
|
||||
'ls',
|
||||
'lsblk',
|
||||
@@ -58,6 +65,7 @@ parsers = [
|
||||
'netstat',
|
||||
'ntpq',
|
||||
'passwd',
|
||||
'ping',
|
||||
'pip-list',
|
||||
'pip-show',
|
||||
'ps',
|
||||
@@ -65,11 +73,14 @@ parsers = [
|
||||
'shadow',
|
||||
'ss',
|
||||
'stat',
|
||||
'sysctl',
|
||||
'systemctl',
|
||||
'systemctl-lj',
|
||||
'systemctl-ls',
|
||||
'systemctl-luf',
|
||||
'timedatectl',
|
||||
'tracepath',
|
||||
'traceroute',
|
||||
'uname',
|
||||
'uptime',
|
||||
'w',
|
||||
@@ -78,9 +89,67 @@ parsers = [
|
||||
'yaml'
|
||||
]
|
||||
|
||||
# List of custom or override parsers.
|
||||
# Allow any <user_data_dir>/jc/jcparsers/*.py
|
||||
local_parsers = []
|
||||
data_dir = appdirs.user_data_dir('jc', 'jc')
|
||||
local_parsers_dir = os.path.join(data_dir, 'jcparsers')
|
||||
if os.path.isdir(local_parsers_dir):
|
||||
sys.path.append(data_dir)
|
||||
for name in os.listdir(local_parsers_dir):
|
||||
if re.match(r'\w+\.py', name) and os.path.isfile(os.path.join(local_parsers_dir, name)):
|
||||
plugin_name = name[0:-3]
|
||||
local_parsers.append(plugin_name)
|
||||
if plugin_name not in parsers:
|
||||
parsers.append(plugin_name)
|
||||
|
||||
def set_env_colors():
|
||||
|
||||
# We only support 2.3.0+, pygments changed color names in 2.4.0.
|
||||
# startswith is sufficient and avoids potential exceptions from split and int.
|
||||
if pygments.__version__.startswith('2.3.'):
|
||||
PYGMENT_COLOR = {
|
||||
'black': '#ansiblack',
|
||||
'red': '#ansidarkred',
|
||||
'green': '#ansidarkgreen',
|
||||
'yellow': '#ansibrown',
|
||||
'blue': '#ansidarkblue',
|
||||
'magenta': '#ansipurple',
|
||||
'cyan': '#ansiteal',
|
||||
'gray': '#ansilightgray',
|
||||
'brightblack': '#ansidarkgray',
|
||||
'brightred': '#ansired',
|
||||
'brightgreen': '#ansigreen',
|
||||
'brightyellow': '#ansiyellow',
|
||||
'brightblue': '#ansiblue',
|
||||
'brightmagenta': '#ansifuchsia',
|
||||
'brightcyan': '#ansiturquoise',
|
||||
'white': '#ansiwhite',
|
||||
}
|
||||
else:
|
||||
PYGMENT_COLOR = {
|
||||
'black': 'ansiblack',
|
||||
'red': 'ansired',
|
||||
'green': 'ansigreen',
|
||||
'yellow': 'ansiyellow',
|
||||
'blue': 'ansiblue',
|
||||
'magenta': 'ansimagenta',
|
||||
'cyan': 'ansicyan',
|
||||
'gray': 'ansigray',
|
||||
'brightblack': 'ansibrightblack',
|
||||
'brightred': 'ansibrightred',
|
||||
'brightgreen': 'ansibrightgreen',
|
||||
'brightyellow': 'ansibrightyellow',
|
||||
'brightblue': 'ansibrightblue',
|
||||
'brightmagenta': 'ansibrightmagenta',
|
||||
'brightcyan': 'ansibrightcyan',
|
||||
'white': 'ansiwhite',
|
||||
}
|
||||
|
||||
|
||||
def set_env_colors(env_colors=None):
|
||||
"""
|
||||
Return a dictionary to be used in Pygments custom style class.
|
||||
|
||||
Grab custom colors from JC_COLORS environment variable. JC_COLORS env variable takes 4 comma
|
||||
separated string values and should be in the format of:
|
||||
|
||||
@@ -96,40 +165,36 @@ def set_env_colors():
|
||||
JC_COLORS=default,default,default,default
|
||||
|
||||
"""
|
||||
env_colors = os.getenv('JC_COLORS')
|
||||
input_error = False
|
||||
|
||||
if env_colors:
|
||||
color_list = env_colors.split(',')
|
||||
else:
|
||||
color_list = ['default', 'default', 'default', 'default']
|
||||
|
||||
if len(color_list) != 4:
|
||||
input_error = True
|
||||
|
||||
if env_colors and len(color_list) != 4:
|
||||
print('jc: Warning: could not parse JC_COLORS environment variable\n', file=sys.stderr)
|
||||
input_error = True
|
||||
|
||||
if env_colors:
|
||||
for color in color_list:
|
||||
if color not in ['black', 'red', 'green', 'yellow', 'blue', 'magenta', 'cyan', 'gray', 'brightblack', 'brightred',
|
||||
'brightgreen', 'brightyellow', 'brightblue', 'brightmagenta', 'brightcyan', 'white', 'default']:
|
||||
print('jc: Warning: could not parse JC_COLORS environment variable\n', file=sys.stderr)
|
||||
input_error = True
|
||||
for color in color_list:
|
||||
if color != 'default' and color not in PYGMENT_COLOR:
|
||||
input_error = True
|
||||
|
||||
# if there is an issue with the env variable, just set all colors to default and move on
|
||||
if input_error:
|
||||
print('jc: Warning: could not parse JC_COLORS environment variable\n', file=sys.stderr)
|
||||
color_list = ['default', 'default', 'default', 'default']
|
||||
|
||||
# Try the color set in the JC_COLORS env variable first. If it is set to default, then fall back to default colors
|
||||
return {
|
||||
Name.Tag: f'bold ansi{color_list[0]}' if not color_list[0] == 'default' else f'bold ansiblue', # key names
|
||||
Keyword: f'ansi{color_list[1]}' if not color_list[1] == 'default' else f'ansibrightblack', # true, false, null
|
||||
Number: f'ansi{color_list[2]}' if not color_list[2] == 'default' else f'ansimagenta', # numbers
|
||||
String: f'ansi{color_list[3]}' if not color_list[3] == 'default' else f'ansigreen' # strings
|
||||
Name.Tag: f'bold {PYGMENT_COLOR[color_list[0]]}' if not color_list[0] == 'default' else f"bold {PYGMENT_COLOR['blue']}", # key names
|
||||
Keyword: PYGMENT_COLOR[color_list[1]] if not color_list[1] == 'default' else PYGMENT_COLOR['brightblack'], # true, false, null
|
||||
Number: PYGMENT_COLOR[color_list[2]] if not color_list[2] == 'default' else PYGMENT_COLOR['magenta'], # numbers
|
||||
String: PYGMENT_COLOR[color_list[3]] if not color_list[3] == 'default' else PYGMENT_COLOR['green'] # strings
|
||||
}
|
||||
|
||||
|
||||
def piped_output():
|
||||
"""returns False if stdout is a TTY. True if output is being piped to another program"""
|
||||
"""Return False if stdout is a TTY. True if output is being piped to another program"""
|
||||
if sys.stdout.isatty():
|
||||
return False
|
||||
else:
|
||||
@@ -137,33 +202,34 @@ def piped_output():
|
||||
|
||||
|
||||
def ctrlc(signum, frame):
|
||||
"""exit with error on SIGINT"""
|
||||
"""Exit with error on SIGINT"""
|
||||
sys.exit(1)
|
||||
|
||||
|
||||
def parser_shortname(parser_argument):
|
||||
"""short name of the parser with dashes and no -- prefix"""
|
||||
"""Return short name of the parser with dashes and no -- prefix"""
|
||||
return parser_argument[2:]
|
||||
|
||||
|
||||
def parser_argument(parser):
|
||||
"""short name of the parser with dashes and with -- prefix"""
|
||||
"""Return short name of the parser with dashes and with -- prefix"""
|
||||
return f'--{parser}'
|
||||
|
||||
|
||||
def parser_mod_shortname(parser):
|
||||
"""short name of the parser's module name (no -- prefix and dashes converted to underscores)"""
|
||||
"""Return short name of the parser's module name (no -- prefix and dashes converted to underscores)"""
|
||||
return parser.replace('--', '').replace('-', '_')
|
||||
|
||||
|
||||
def parser_module(parser):
|
||||
"""import the module just in time and return the module object"""
|
||||
importlib.import_module('jc.parsers.' + parser_mod_shortname(parser))
|
||||
return getattr(jc.parsers, parser_mod_shortname(parser))
|
||||
"""Import the module just in time and return the module object"""
|
||||
shortname = parser_mod_shortname(parser)
|
||||
path = ('jcparsers.' if shortname in local_parsers else 'jc.parsers.')
|
||||
return importlib.import_module(path + shortname)
|
||||
|
||||
|
||||
def parsers_text(indent=0, pad=0):
|
||||
"""return the argument and description information from each parser"""
|
||||
"""Return the argument and description information from each parser"""
|
||||
ptext = ''
|
||||
for parser in parsers:
|
||||
parser_arg = parser_argument(parser)
|
||||
@@ -181,7 +247,7 @@ def parsers_text(indent=0, pad=0):
|
||||
|
||||
|
||||
def about_jc():
|
||||
"""return jc info and the contents of each parser.info as a dictionary"""
|
||||
"""Return jc info and the contents of each parser.info as a dictionary"""
|
||||
parser_list = []
|
||||
|
||||
for parser in parsers:
|
||||
@@ -211,7 +277,7 @@ def about_jc():
|
||||
|
||||
|
||||
def helptext(message):
|
||||
"""return the help text with the list of parsers"""
|
||||
"""Return the help text with the list of parsers"""
|
||||
parsers_string = parsers_text(indent=12, pad=17)
|
||||
|
||||
helptext_string = f'''
|
||||
@@ -227,7 +293,7 @@ def helptext(message):
|
||||
{parsers_string}
|
||||
Options:
|
||||
-a about jc
|
||||
-d debug - show trace messages
|
||||
-d debug - show traceback (-dd for verbose traceback)
|
||||
-m monochrome output
|
||||
-p pretty print output
|
||||
-q quiet - suppress warnings
|
||||
@@ -240,30 +306,30 @@ def helptext(message):
|
||||
|
||||
jc -p ls -al
|
||||
'''
|
||||
print(textwrap.dedent(helptext_string), file=sys.stderr)
|
||||
|
||||
|
||||
def json_out(data, pretty=False, mono=False, piped_out=False):
|
||||
# set colors
|
||||
class JcStyle(Style):
|
||||
styles = set_env_colors()
|
||||
return textwrap.dedent(helptext_string)
|
||||
|
||||
|
||||
def json_out(data, pretty=False, env_colors=None, mono=False, piped_out=False):
|
||||
"""Return a JSON formatted string. String may include color codes or be pretty printed."""
|
||||
if not mono and not piped_out:
|
||||
# set colors
|
||||
class JcStyle(Style):
|
||||
styles = set_env_colors(env_colors)
|
||||
|
||||
if pretty:
|
||||
print(highlight(json.dumps(data, indent=2), JsonLexer(), Terminal256Formatter(style=JcStyle))[0:-1])
|
||||
return str(highlight(json.dumps(data, indent=2), JsonLexer(), Terminal256Formatter(style=JcStyle))[0:-1])
|
||||
else:
|
||||
print(highlight(json.dumps(data), JsonLexer(), Terminal256Formatter(style=JcStyle))[0:-1])
|
||||
return str(highlight(json.dumps(data), JsonLexer(), Terminal256Formatter(style=JcStyle))[0:-1])
|
||||
else:
|
||||
if pretty:
|
||||
print(json.dumps(data, indent=2))
|
||||
return json.dumps(data, indent=2)
|
||||
else:
|
||||
print(json.dumps(data))
|
||||
return json.dumps(data)
|
||||
|
||||
|
||||
def generate_magic_command(args):
|
||||
"""
|
||||
Returns a tuple with a boolean and a command, where the boolean signifies that
|
||||
Return a tuple with a boolean and a command, where the boolean signifies that
|
||||
the command is valid, and the command is either a command string or None.
|
||||
"""
|
||||
|
||||
@@ -296,7 +362,7 @@ def generate_magic_command(args):
|
||||
magic_dict = {}
|
||||
parser_info = about_jc()['parsers']
|
||||
|
||||
# Create a dictionary of magic_commands to their respective parsers.
|
||||
# create a dictionary of magic_commands to their respective parsers.
|
||||
for entry in parser_info:
|
||||
# Update the dict with all of the magic commands for this parser, if they exist.
|
||||
magic_dict.update({mc: entry['argument'] for mc in entry.get('magic_commands', [])})
|
||||
@@ -305,7 +371,7 @@ def generate_magic_command(args):
|
||||
one_word_command = args_given[0]
|
||||
two_word_command = ' '.join(args_given[0:2])
|
||||
|
||||
# Try to get a parser for two_word_command, otherwise get one for one_word_command
|
||||
# try to get a parser for two_word_command, otherwise get one for one_word_command
|
||||
found_parser = magic_dict.get(two_word_command, magic_dict.get(one_word_command))
|
||||
|
||||
# construct a new command line using the standard syntax: COMMAND | jc --PARSER -OPTIONS
|
||||
@@ -318,6 +384,7 @@ def generate_magic_command(args):
|
||||
|
||||
|
||||
def magic():
|
||||
"""Runs the command generated by generate_magic_command() to support magic syntax"""
|
||||
valid_command, run_command = generate_magic_command(sys.argv)
|
||||
if valid_command:
|
||||
os.system(run_command)
|
||||
@@ -325,7 +392,7 @@ def magic():
|
||||
elif run_command is None:
|
||||
return
|
||||
else:
|
||||
helptext(f'parser not found for "{run_command}"')
|
||||
print(helptext(f'parser not found for "{run_command}"'), file=sys.stderr)
|
||||
sys.exit(1)
|
||||
|
||||
|
||||
@@ -339,6 +406,8 @@ def main():
|
||||
except AttributeError:
|
||||
pass
|
||||
|
||||
jc_colors = os.getenv('JC_COLORS')
|
||||
|
||||
# try magic syntax first: e.g. jc -p ls -al
|
||||
magic()
|
||||
|
||||
@@ -350,54 +419,54 @@ def main():
|
||||
options.extend(opt[1:])
|
||||
|
||||
debug = 'd' in options
|
||||
verbose_debug = True if options.count('d') > 1 else False
|
||||
mono = 'm' in options
|
||||
pretty = 'p' in options
|
||||
quiet = 'q' in options
|
||||
raw = 'r' in options
|
||||
|
||||
if verbose_debug:
|
||||
import jc.tracebackplus
|
||||
jc.tracebackplus.enable(context=11)
|
||||
|
||||
if 'a' in options:
|
||||
json_out(about_jc(), pretty=pretty, mono=mono, piped_out=piped_output())
|
||||
print(json_out(about_jc(), pretty=pretty, env_colors=jc_colors, mono=mono, piped_out=piped_output()))
|
||||
sys.exit(0)
|
||||
|
||||
if sys.stdin.isatty():
|
||||
helptext('missing piped data')
|
||||
print(helptext('missing piped data'), file=sys.stderr)
|
||||
sys.exit(1)
|
||||
|
||||
data = sys.stdin.read()
|
||||
|
||||
found = False
|
||||
|
||||
if debug:
|
||||
for arg in sys.argv:
|
||||
parser_name = parser_shortname(arg)
|
||||
for arg in sys.argv:
|
||||
parser_name = parser_shortname(arg)
|
||||
|
||||
if parser_name in parsers:
|
||||
# load parser module just in time so we don't need to load all modules
|
||||
parser = parser_module(arg)
|
||||
if parser_name in parsers:
|
||||
# load parser module just in time so we don't need to load all modules
|
||||
parser = parser_module(arg)
|
||||
try:
|
||||
result = parser.parse(data, raw=raw, quiet=quiet)
|
||||
found = True
|
||||
break
|
||||
else:
|
||||
for arg in sys.argv:
|
||||
parser_name = parser_shortname(arg)
|
||||
|
||||
if parser_name in parsers:
|
||||
# load parser module just in time so we don't need to load all modules
|
||||
parser = parser_module(arg)
|
||||
try:
|
||||
result = parser.parse(data, raw=raw, quiet=quiet)
|
||||
found = True
|
||||
break
|
||||
except Exception:
|
||||
except Exception:
|
||||
if debug:
|
||||
raise
|
||||
else:
|
||||
import jc.utils
|
||||
jc.utils.error_message(
|
||||
f'{parser_name} parser could not parse the input data. Did you use the correct parser?\n For details use the -d option.')
|
||||
f'{parser_name} parser could not parse the input data. Did you use the correct parser?\n'
|
||||
' For details use the -d or -dd option.')
|
||||
sys.exit(1)
|
||||
|
||||
if not found:
|
||||
helptext('missing or incorrect arguments')
|
||||
print(helptext('missing or incorrect arguments'), file=sys.stderr)
|
||||
sys.exit(1)
|
||||
|
||||
json_out(result, pretty=pretty, mono=mono, piped_out=piped_output())
|
||||
print(json_out(result, pretty=pretty, env_colors=jc_colors, mono=mono, piped_out=piped_output()))
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
|
||||
@@ -55,7 +55,7 @@ import jc.utils
|
||||
|
||||
|
||||
class info():
|
||||
version = '1.0'
|
||||
version = '1.1'
|
||||
description = 'airport -I command parser'
|
||||
author = 'Kelly Brazil'
|
||||
author_email = 'kellyjonbrazil@gmail.com'
|
||||
@@ -131,9 +131,11 @@ def parse(data, raw=False, quiet=False):
|
||||
|
||||
raw_output = {}
|
||||
|
||||
for line in filter(None, data.splitlines()):
|
||||
linedata = line.split(':', maxsplit=1)
|
||||
raw_output[linedata[0].strip().lower().replace(' ', '_').replace('.', '_')] = linedata[1].strip()
|
||||
if jc.utils.has_data(data):
|
||||
|
||||
for line in filter(None, data.splitlines()):
|
||||
linedata = line.split(':', maxsplit=1)
|
||||
raw_output[linedata[0].strip().lower().replace(' ', '_').replace('.', '_')] = linedata[1].strip()
|
||||
|
||||
if raw:
|
||||
return raw_output
|
||||
|
||||
@@ -88,7 +88,7 @@ import jc.parsers.universal
|
||||
|
||||
|
||||
class info():
|
||||
version = '1.0'
|
||||
version = '1.2'
|
||||
description = 'airport -s command parser'
|
||||
author = 'Kelly Brazil'
|
||||
author_email = 'kellyjonbrazil@gmail.com'
|
||||
@@ -170,15 +170,17 @@ def parse(data, raw=False, quiet=False):
|
||||
if not quiet:
|
||||
jc.utils.compatibility(__name__, info.compatible)
|
||||
|
||||
cleandata = data.splitlines()
|
||||
raw_output = []
|
||||
cleandata = list(filter(None, data.splitlines()))
|
||||
|
||||
# fix headers
|
||||
cleandata[0] = cleandata[0].lower()
|
||||
cleandata[0] = cleandata[0].replace('-', '_')
|
||||
cleandata[0] = cleandata[0].replace('security (auth/unicast/group)', 'security')
|
||||
if jc.utils.has_data(data):
|
||||
# fix headers
|
||||
cleandata[0] = cleandata[0].lower()
|
||||
cleandata[0] = cleandata[0].replace('-', '_')
|
||||
cleandata[0] = cleandata[0].replace('security (auth/unicast/group)', 'security')
|
||||
|
||||
# parse the data
|
||||
raw_output = jc.parsers.universal.sparse_table_parse(cleandata)
|
||||
# parse the data
|
||||
raw_output = jc.parsers.universal.sparse_table_parse(cleandata)
|
||||
|
||||
if raw:
|
||||
return raw_output
|
||||
|
||||
@@ -58,6 +58,8 @@ Examples:
|
||||
"hwtype": "ether",
|
||||
"hwaddress": "00:50:56:f0:98:26",
|
||||
"iface": "ens33"
|
||||
"permanent": false,
|
||||
"expires": 1182
|
||||
},
|
||||
{
|
||||
"name": "gateway",
|
||||
@@ -65,6 +67,8 @@ Examples:
|
||||
"hwtype": "ether",
|
||||
"hwaddress": "00:50:56:f7:4a:fc",
|
||||
"iface": "ens33"
|
||||
"permanent": false,
|
||||
"expires": 110
|
||||
}
|
||||
]
|
||||
|
||||
@@ -76,6 +80,8 @@ Examples:
|
||||
"hwtype": "ether",
|
||||
"hwaddress": "00:50:56:fe:7a:b4",
|
||||
"iface": "ens33"
|
||||
"permanent": false,
|
||||
"expires": "1182"
|
||||
},
|
||||
{
|
||||
"name": "_gateway",
|
||||
@@ -83,6 +89,8 @@ Examples:
|
||||
"hwtype": "ether",
|
||||
"hwaddress": "00:50:56:f7:4a:fc",
|
||||
"iface": "ens33"
|
||||
"permanent": false,
|
||||
"expires": "110"
|
||||
}
|
||||
]
|
||||
"""
|
||||
@@ -91,7 +99,7 @@ import jc.parsers.universal
|
||||
|
||||
|
||||
class info():
|
||||
version = '1.3'
|
||||
version = '1.6'
|
||||
description = 'arp command parser'
|
||||
author = 'Kelly Brazil'
|
||||
author_email = 'kellyjonbrazil@gmail.com'
|
||||
@@ -123,7 +131,9 @@ def process(proc_data):
|
||||
"hwtype": string,
|
||||
"hwaddress": string,
|
||||
"flags_mask": string,
|
||||
"iface": string
|
||||
"iface": string,
|
||||
"permanent": boolean,
|
||||
"expires": integer
|
||||
}
|
||||
]
|
||||
"""
|
||||
@@ -133,6 +143,14 @@ def process(proc_data):
|
||||
if 'name' in entry and entry['name'] == '?':
|
||||
entry['name'] = None
|
||||
|
||||
int_list = ['expires']
|
||||
for key in int_list:
|
||||
if key in entry:
|
||||
try:
|
||||
entry[key] = int(entry[key])
|
||||
except (ValueError):
|
||||
entry[key] = None
|
||||
|
||||
return proc_data
|
||||
|
||||
|
||||
@@ -153,60 +171,65 @@ def parse(data, raw=False, quiet=False):
|
||||
if not quiet:
|
||||
jc.utils.compatibility(__name__, info.compatible)
|
||||
|
||||
cleandata = data.splitlines()
|
||||
raw_output = []
|
||||
cleandata = list(filter(None, data.splitlines()))
|
||||
|
||||
# remove final Entries row if -v was used
|
||||
if cleandata[-1].startswith('Entries:'):
|
||||
cleandata.pop(-1)
|
||||
if jc.utils.has_data(data):
|
||||
|
||||
# detect if osx style was used
|
||||
if cleandata[0][-1] == ']':
|
||||
raw_output = []
|
||||
for line in cleandata:
|
||||
splitline = line.split()
|
||||
output_line = {
|
||||
'name': splitline[0],
|
||||
'address': splitline[1].lstrip('(').rstrip(')'),
|
||||
'hwtype': splitline[-1].lstrip('[').rstrip(']'),
|
||||
'hwaddress': splitline[3],
|
||||
'iface': splitline[5]
|
||||
}
|
||||
raw_output.append(output_line)
|
||||
# remove final Entries row if -v was used
|
||||
if cleandata[-1].startswith('Entries:'):
|
||||
cleandata.pop(-1)
|
||||
|
||||
if raw:
|
||||
return raw_output
|
||||
# detect if freebsd/osx style was used
|
||||
if cleandata[0][-1] == ']':
|
||||
for line in cleandata:
|
||||
splitline = line.split()
|
||||
output_line = {
|
||||
'name': splitline[0],
|
||||
'address': splitline[1].lstrip('(').rstrip(')'),
|
||||
'hwtype': splitline[-1].lstrip('[').rstrip(']'),
|
||||
'hwaddress': splitline[3],
|
||||
'iface': splitline[5]
|
||||
}
|
||||
|
||||
if 'permanent' in splitline:
|
||||
output_line['permanent'] = True
|
||||
else:
|
||||
output_line['permanent'] = False
|
||||
|
||||
if 'expires' in splitline:
|
||||
output_line['expires'] = splitline[-3]
|
||||
|
||||
raw_output.append(output_line)
|
||||
|
||||
if raw:
|
||||
return raw_output
|
||||
else:
|
||||
return process(raw_output)
|
||||
|
||||
# detect if linux style was used
|
||||
elif cleandata[0].startswith('Address'):
|
||||
|
||||
# fix header row to change Flags Mask to flags_mask
|
||||
cleandata[0] = cleandata[0].replace('Flags Mask', 'flags_mask')
|
||||
cleandata[0] = cleandata[0].lower()
|
||||
|
||||
raw_output = jc.parsers.universal.simple_table_parse(cleandata)
|
||||
|
||||
# otherwise, try bsd style
|
||||
else:
|
||||
return process(raw_output)
|
||||
for line in cleandata:
|
||||
line = line.split()
|
||||
output_line = {
|
||||
'name': line[0],
|
||||
'address': line[1].lstrip('(').rstrip(')'),
|
||||
'hwtype': line[4].lstrip('[').rstrip(']'),
|
||||
'hwaddress': line[3],
|
||||
'iface': line[6],
|
||||
}
|
||||
raw_output.append(output_line)
|
||||
|
||||
# detect if linux style was used
|
||||
elif cleandata[0].startswith('Address'):
|
||||
|
||||
# fix header row to change Flags Mask to flags_mask
|
||||
cleandata[0] = cleandata[0].replace('Flags Mask', 'flags_mask')
|
||||
cleandata[0] = cleandata[0].lower()
|
||||
|
||||
raw_output = jc.parsers.universal.simple_table_parse(cleandata)
|
||||
|
||||
if raw:
|
||||
return raw_output
|
||||
else:
|
||||
return process(raw_output)
|
||||
|
||||
# otherwise, try bsd style
|
||||
if raw:
|
||||
return raw_output
|
||||
else:
|
||||
raw_output = []
|
||||
for line in cleandata:
|
||||
line = line.split()
|
||||
output_line = {
|
||||
'name': line[0],
|
||||
'address': line[1].lstrip('(').rstrip(')'),
|
||||
'hwtype': line[4].lstrip('[').rstrip(']'),
|
||||
'hwaddress': line[3],
|
||||
'iface': line[6],
|
||||
}
|
||||
raw_output.append(output_line)
|
||||
|
||||
if raw:
|
||||
return raw_output
|
||||
else:
|
||||
return process(raw_output)
|
||||
return process(raw_output)
|
||||
|
||||
@@ -79,7 +79,7 @@ import jc.utils
|
||||
|
||||
|
||||
class info():
|
||||
version = '1.0'
|
||||
version = '1.2'
|
||||
description = 'blkid command parser'
|
||||
author = 'Kelly Brazil'
|
||||
author_email = 'kellyjonbrazil@gmail.com'
|
||||
@@ -176,7 +176,8 @@ def parse(data, raw=False, quiet=False):
|
||||
|
||||
raw_output = []
|
||||
|
||||
if data:
|
||||
if jc.utils.has_data(data):
|
||||
|
||||
# if the first field is a device, use normal parsing:
|
||||
if data.split(maxsplit=1)[0][-1] == ':':
|
||||
linedata = data.splitlines()
|
||||
|
||||
@@ -132,7 +132,7 @@ import jc.parsers.universal
|
||||
|
||||
|
||||
class info():
|
||||
version = '1.2'
|
||||
version = '1.4'
|
||||
description = 'crontab command and file parser'
|
||||
author = 'Kelly Brazil'
|
||||
author_email = 'kellyjonbrazil@gmail.com'
|
||||
@@ -225,44 +225,46 @@ def parse(data, raw=False, quiet=False):
|
||||
# Clear any blank lines
|
||||
cleandata = list(filter(None, cleandata))
|
||||
|
||||
# Clear any commented lines
|
||||
for i, line in reversed(list(enumerate(cleandata))):
|
||||
if line.strip().startswith('#'):
|
||||
cleandata.pop(i)
|
||||
if jc.utils.has_data(data):
|
||||
|
||||
# Pop any variable assignment lines
|
||||
cron_var = []
|
||||
for i, line in reversed(list(enumerate(cleandata))):
|
||||
if '=' in line:
|
||||
var_line = cleandata.pop(i)
|
||||
var_name = var_line.split('=', maxsplit=1)[0].strip()
|
||||
var_value = var_line.split('=', maxsplit=1)[1].strip()
|
||||
cron_var.append({'name': var_name,
|
||||
'value': var_value})
|
||||
# Clear any commented lines
|
||||
for i, line in reversed(list(enumerate(cleandata))):
|
||||
if line.strip().startswith('#'):
|
||||
cleandata.pop(i)
|
||||
|
||||
raw_output['variables'] = cron_var
|
||||
# Pop any variable assignment lines
|
||||
cron_var = []
|
||||
for i, line in reversed(list(enumerate(cleandata))):
|
||||
if '=' in line:
|
||||
var_line = cleandata.pop(i)
|
||||
var_name = var_line.split('=', maxsplit=1)[0].strip()
|
||||
var_value = var_line.split('=', maxsplit=1)[1].strip()
|
||||
cron_var.append({'name': var_name,
|
||||
'value': var_value})
|
||||
|
||||
# Pop any shortcut lines
|
||||
shortcut_list = []
|
||||
for i, line in reversed(list(enumerate(cleandata))):
|
||||
if line.strip().startswith('@'):
|
||||
shortcut_line = cleandata.pop(i)
|
||||
occurrence = shortcut_line.split(maxsplit=1)[0].strip().lstrip('@')
|
||||
cmd = shortcut_line.split(maxsplit=1)[1].strip()
|
||||
shortcut_list.append({'occurrence': occurrence,
|
||||
'command': cmd})
|
||||
raw_output['variables'] = cron_var
|
||||
|
||||
# Add header row for parsing
|
||||
cleandata[:0] = ['minute hour day_of_month month day_of_week command']
|
||||
# Pop any shortcut lines
|
||||
shortcut_list = []
|
||||
for i, line in reversed(list(enumerate(cleandata))):
|
||||
if line.strip().startswith('@'):
|
||||
shortcut_line = cleandata.pop(i)
|
||||
occurrence = shortcut_line.split(maxsplit=1)[0].strip().lstrip('@')
|
||||
cmd = shortcut_line.split(maxsplit=1)[1].strip()
|
||||
shortcut_list.append({'occurrence': occurrence,
|
||||
'command': cmd})
|
||||
|
||||
if len(cleandata) > 1:
|
||||
cron_list = jc.parsers.universal.simple_table_parse(cleandata)
|
||||
# Add header row for parsing
|
||||
cleandata[:0] = ['minute hour day_of_month month day_of_week command']
|
||||
|
||||
raw_output['schedule'] = cron_list
|
||||
if len(cleandata) > 1:
|
||||
cron_list = jc.parsers.universal.simple_table_parse(cleandata)
|
||||
|
||||
# Add shortcut entries back in
|
||||
for item in shortcut_list:
|
||||
raw_output['schedule'].append(item)
|
||||
raw_output['schedule'] = cron_list
|
||||
|
||||
# Add shortcut entries back in
|
||||
for item in shortcut_list:
|
||||
raw_output['schedule'].append(item)
|
||||
|
||||
if raw:
|
||||
return raw_output
|
||||
|
||||
@@ -133,7 +133,7 @@ import jc.parsers.universal
|
||||
|
||||
|
||||
class info():
|
||||
version = '1.1'
|
||||
version = '1.3'
|
||||
description = 'crontab file parser with user support'
|
||||
author = 'Kelly Brazil'
|
||||
author_email = 'kellyjonbrazil@gmail.com'
|
||||
@@ -226,46 +226,48 @@ def parse(data, raw=False, quiet=False):
|
||||
# Clear any blank lines
|
||||
cleandata = list(filter(None, cleandata))
|
||||
|
||||
# Clear any commented lines
|
||||
for i, line in reversed(list(enumerate(cleandata))):
|
||||
if line.strip().startswith('#'):
|
||||
cleandata.pop(i)
|
||||
if jc.utils.has_data(data):
|
||||
|
||||
# Pop any variable assignment lines
|
||||
cron_var = []
|
||||
for i, line in reversed(list(enumerate(cleandata))):
|
||||
if '=' in line:
|
||||
var_line = cleandata.pop(i)
|
||||
var_name = var_line.split('=', maxsplit=1)[0].strip()
|
||||
var_value = var_line.split('=', maxsplit=1)[1].strip()
|
||||
cron_var.append({'name': var_name,
|
||||
'value': var_value})
|
||||
# Clear any commented lines
|
||||
for i, line in reversed(list(enumerate(cleandata))):
|
||||
if line.strip().startswith('#'):
|
||||
cleandata.pop(i)
|
||||
|
||||
raw_output['variables'] = cron_var
|
||||
# Pop any variable assignment lines
|
||||
cron_var = []
|
||||
for i, line in reversed(list(enumerate(cleandata))):
|
||||
if '=' in line:
|
||||
var_line = cleandata.pop(i)
|
||||
var_name = var_line.split('=', maxsplit=1)[0].strip()
|
||||
var_value = var_line.split('=', maxsplit=1)[1].strip()
|
||||
cron_var.append({'name': var_name,
|
||||
'value': var_value})
|
||||
|
||||
# Pop any shortcut lines
|
||||
shortcut_list = []
|
||||
for i, line in reversed(list(enumerate(cleandata))):
|
||||
if line.strip().startswith('@'):
|
||||
shortcut_line = cleandata.pop(i)
|
||||
occurrence = shortcut_line.split(maxsplit=1)[0].strip().lstrip('@')
|
||||
usr = shortcut_line.split(maxsplit=2)[1].strip()
|
||||
cmd = shortcut_line.split(maxsplit=2)[2].strip()
|
||||
shortcut_list.append({'occurrence': occurrence,
|
||||
'user': usr,
|
||||
'command': cmd})
|
||||
raw_output['variables'] = cron_var
|
||||
|
||||
# Add header row for parsing
|
||||
cleandata[:0] = ['minute hour day_of_month month day_of_week user command']
|
||||
# Pop any shortcut lines
|
||||
shortcut_list = []
|
||||
for i, line in reversed(list(enumerate(cleandata))):
|
||||
if line.strip().startswith('@'):
|
||||
shortcut_line = cleandata.pop(i)
|
||||
occurrence = shortcut_line.split(maxsplit=1)[0].strip().lstrip('@')
|
||||
usr = shortcut_line.split(maxsplit=2)[1].strip()
|
||||
cmd = shortcut_line.split(maxsplit=2)[2].strip()
|
||||
shortcut_list.append({'occurrence': occurrence,
|
||||
'user': usr,
|
||||
'command': cmd})
|
||||
|
||||
if len(cleandata) > 1:
|
||||
cron_list = jc.parsers.universal.simple_table_parse(cleandata)
|
||||
# Add header row for parsing
|
||||
cleandata[:0] = ['minute hour day_of_month month day_of_week user command']
|
||||
|
||||
raw_output['schedule'] = cron_list
|
||||
if len(cleandata) > 1:
|
||||
cron_list = jc.parsers.universal.simple_table_parse(cleandata)
|
||||
|
||||
# Add shortcut entries back in
|
||||
for item in shortcut_list:
|
||||
raw_output['schedule'].append(item)
|
||||
raw_output['schedule'] = cron_list
|
||||
|
||||
# Add shortcut entries back in
|
||||
for item in shortcut_list:
|
||||
raw_output['schedule'].append(item)
|
||||
|
||||
if raw:
|
||||
return raw_output
|
||||
|
||||
@@ -63,7 +63,7 @@ import csv
|
||||
|
||||
|
||||
class info():
|
||||
version = '1.0'
|
||||
version = '1.1'
|
||||
description = 'CSV file parser'
|
||||
author = 'Kelly Brazil'
|
||||
author_email = 'kellyjonbrazil@gmail.com'
|
||||
@@ -123,7 +123,8 @@ def parse(data, raw=False, quiet=False):
|
||||
# Clear any blank lines
|
||||
cleandata = list(filter(None, cleandata))
|
||||
|
||||
if cleandata:
|
||||
if jc.utils.has_data(data):
|
||||
|
||||
dialect = None
|
||||
try:
|
||||
dialect = csv.Sniffer().sniff(data[:1024])
|
||||
|
||||
160
jc/parsers/date.py
Normal file
160
jc/parsers/date.py
Normal file
@@ -0,0 +1,160 @@
|
||||
"""jc - JSON CLI output utility date Parser
|
||||
|
||||
Usage:
|
||||
|
||||
specify --date as the first argument if the piped input is coming from date
|
||||
|
||||
Compatibility:
|
||||
|
||||
'linux', 'darwin', 'freebsd'
|
||||
|
||||
Examples:
|
||||
|
||||
$ date | jc --date -p
|
||||
{
|
||||
"year": 2020,
|
||||
"month_num": 7,
|
||||
"day": 31,
|
||||
"hour": 16,
|
||||
"minute": 48,
|
||||
"second": 11,
|
||||
"month": "Jul",
|
||||
"weekday": "Fri",
|
||||
"weekday_num": 6,
|
||||
"timezone": "PDT"
|
||||
}
|
||||
|
||||
$ date | jc --date -p -r
|
||||
{
|
||||
"year": "2020",
|
||||
"month": "Jul",
|
||||
"day": "31",
|
||||
"weekday": "Fri",
|
||||
"hour": "16",
|
||||
"minute": "50",
|
||||
"second": "01",
|
||||
"timezone": "PDT"
|
||||
}
|
||||
"""
|
||||
import jc.utils
|
||||
|
||||
|
||||
class info():
|
||||
version = '1.0'
|
||||
description = 'date command parser'
|
||||
author = 'Kelly Brazil'
|
||||
author_email = 'kellyjonbrazil@gmail.com'
|
||||
|
||||
# compatible options: linux, darwin, cygwin, win32, aix, freebsd
|
||||
compatible = ['linux', 'darwin', 'freebsd']
|
||||
magic_commands = ['date']
|
||||
|
||||
|
||||
__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. Structured data with the following schema:
|
||||
|
||||
{
|
||||
"year": integer,
|
||||
"month_num": integer,
|
||||
"day": integer,
|
||||
"hour": integer,
|
||||
"minute": integer,
|
||||
"second": integer,
|
||||
"month": string,
|
||||
"weekday": string,
|
||||
"weekday_num": integer,
|
||||
"timezone": string
|
||||
}
|
||||
"""
|
||||
month_map = {
|
||||
"Jan": 1,
|
||||
"Feb": 2,
|
||||
"Mar": 3,
|
||||
"Apr": 4,
|
||||
"May": 5,
|
||||
"Jun": 6,
|
||||
"Jul": 7,
|
||||
"Aug": 8,
|
||||
"Sep": 9,
|
||||
"Oct": 10,
|
||||
"Nov": 11,
|
||||
"Dec": 12
|
||||
}
|
||||
|
||||
weekday_map = {
|
||||
"Sun": 1,
|
||||
"Mon": 2,
|
||||
"Tue": 3,
|
||||
"Wed": 4,
|
||||
"Thu": 5,
|
||||
"Fri": 6,
|
||||
"Sat": 7
|
||||
}
|
||||
|
||||
if proc_data:
|
||||
return {
|
||||
"year": int(proc_data['year']),
|
||||
'month_num': month_map[proc_data['month']],
|
||||
"day": int(proc_data['day']),
|
||||
"hour": int(proc_data['hour']),
|
||||
"minute": int(proc_data['minute']),
|
||||
"second": int(proc_data['second']),
|
||||
"month": proc_data['month'],
|
||||
"weekday": proc_data['weekday'],
|
||||
"weekday_num": weekday_map[proc_data['weekday']],
|
||||
"timezone": proc_data['timezone']
|
||||
}
|
||||
else:
|
||||
return {}
|
||||
|
||||
|
||||
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:
|
||||
|
||||
Dictionary. Raw or processed structured data.
|
||||
"""
|
||||
if not quiet:
|
||||
jc.utils.compatibility(__name__, info.compatible)
|
||||
|
||||
raw_output = {}
|
||||
|
||||
if jc.utils.has_data(data):
|
||||
data = data.replace(':', ' ')
|
||||
split_data = data.split()
|
||||
|
||||
raw_output = {
|
||||
"year": split_data[7],
|
||||
"month": split_data[1],
|
||||
"day": split_data[2],
|
||||
"weekday": split_data[0],
|
||||
"hour": split_data[3],
|
||||
"minute": split_data[4],
|
||||
"second": split_data[5],
|
||||
"timezone": split_data[6]
|
||||
}
|
||||
|
||||
if raw:
|
||||
return raw_output
|
||||
else:
|
||||
return process(raw_output)
|
||||
@@ -6,7 +6,7 @@ Usage:
|
||||
|
||||
Compatibility:
|
||||
|
||||
'linux', 'darwin'
|
||||
'linux', 'darwin', 'freebsd'
|
||||
|
||||
Examples:
|
||||
|
||||
@@ -73,13 +73,13 @@ import jc.parsers.universal
|
||||
|
||||
|
||||
class info():
|
||||
version = '1.2'
|
||||
version = '1.5'
|
||||
description = 'df command parser'
|
||||
author = 'Kelly Brazil'
|
||||
author_email = 'kellyjonbrazil@gmail.com'
|
||||
|
||||
# compatible options: linux, darwin, cygwin, win32, aix, freebsd
|
||||
compatible = ['linux', 'darwin']
|
||||
compatible = ['linux', 'darwin', 'freebsd']
|
||||
magic_commands = ['df']
|
||||
|
||||
|
||||
@@ -184,14 +184,17 @@ def parse(data, raw=False, quiet=False):
|
||||
jc.utils.compatibility(__name__, info.compatible)
|
||||
|
||||
cleandata = data.splitlines()
|
||||
raw_output = []
|
||||
|
||||
# fix headers
|
||||
cleandata[0] = cleandata[0].lower()
|
||||
cleandata[0] = cleandata[0].replace('-', '_')
|
||||
cleandata[0] = cleandata[0].replace('mounted on', 'mounted_on')
|
||||
if jc.utils.has_data(data):
|
||||
|
||||
# parse the data
|
||||
raw_output = jc.parsers.universal.sparse_table_parse(cleandata)
|
||||
# fix headers
|
||||
cleandata[0] = cleandata[0].lower()
|
||||
cleandata[0] = cleandata[0].replace('-', '_')
|
||||
cleandata[0] = cleandata[0].replace('mounted on', 'mounted_on')
|
||||
|
||||
# parse the data
|
||||
raw_output = jc.parsers.universal.sparse_table_parse(cleandata)
|
||||
|
||||
if raw:
|
||||
return raw_output
|
||||
|
||||
@@ -324,7 +324,7 @@ import jc.utils
|
||||
|
||||
|
||||
class info():
|
||||
version = '1.2'
|
||||
version = '1.3'
|
||||
description = 'dig command parser'
|
||||
author = 'Kelly Brazil'
|
||||
author_email = 'kellyjonbrazil@gmail.com'
|
||||
@@ -574,100 +574,103 @@ def parse(data, raw=False, quiet=False):
|
||||
axfr = False
|
||||
|
||||
output_entry = {}
|
||||
for line in cleandata:
|
||||
|
||||
if line.startswith('; <<>> ') and ' axfr ' in line.lower():
|
||||
question = False
|
||||
authority = False
|
||||
answer = False
|
||||
axfr = True
|
||||
axfr_list = []
|
||||
continue
|
||||
if jc.utils.has_data(data):
|
||||
for line in cleandata:
|
||||
|
||||
if ';' not in line and axfr:
|
||||
axfr_list.append(parse_axfr(line))
|
||||
output_entry.update({'axfr': axfr_list})
|
||||
continue
|
||||
if line.startswith('; <<>> ') and ' axfr ' in line.lower():
|
||||
question = False
|
||||
authority = False
|
||||
answer = False
|
||||
axfr = True
|
||||
axfr_list = []
|
||||
continue
|
||||
|
||||
if line.startswith(';; ->>HEADER<<-'):
|
||||
output_entry = {}
|
||||
output_entry.update(parse_header(line))
|
||||
continue
|
||||
if ';' not in line and axfr:
|
||||
axfr_list.append(parse_axfr(line))
|
||||
output_entry.update({'axfr': axfr_list})
|
||||
continue
|
||||
|
||||
if line.startswith(';; flags:'):
|
||||
output_entry.update(parse_flags_line(line))
|
||||
continue
|
||||
if line.startswith(';; ->>HEADER<<-'):
|
||||
output_entry = {}
|
||||
output_entry.update(parse_header(line))
|
||||
continue
|
||||
|
||||
if line.startswith(';; QUESTION SECTION:'):
|
||||
question = True
|
||||
authority = False
|
||||
answer = False
|
||||
axfr = False
|
||||
continue
|
||||
if line.startswith(';; flags:'):
|
||||
output_entry.update(parse_flags_line(line))
|
||||
continue
|
||||
|
||||
if question:
|
||||
output_entry['question'] = parse_question(line)
|
||||
question = False
|
||||
authority = False
|
||||
answer = False
|
||||
axfr = False
|
||||
continue
|
||||
if line.startswith(';; QUESTION SECTION:'):
|
||||
question = True
|
||||
authority = False
|
||||
answer = False
|
||||
axfr = False
|
||||
continue
|
||||
|
||||
if line.startswith(';; AUTHORITY SECTION:'):
|
||||
question = False
|
||||
authority = True
|
||||
answer = False
|
||||
axfr = False
|
||||
authority_list = []
|
||||
continue
|
||||
if question:
|
||||
output_entry['question'] = parse_question(line)
|
||||
question = False
|
||||
authority = False
|
||||
answer = False
|
||||
axfr = False
|
||||
continue
|
||||
|
||||
if ';' not in line and authority:
|
||||
authority_list.append(parse_authority(line))
|
||||
output_entry.update({'authority': authority_list})
|
||||
continue
|
||||
if line.startswith(';; AUTHORITY SECTION:'):
|
||||
question = False
|
||||
authority = True
|
||||
answer = False
|
||||
axfr = False
|
||||
authority_list = []
|
||||
continue
|
||||
|
||||
if line.startswith(';; ANSWER SECTION:'):
|
||||
question = False
|
||||
authority = False
|
||||
answer = True
|
||||
axfr = False
|
||||
answer_list = []
|
||||
continue
|
||||
if ';' not in line and authority:
|
||||
authority_list.append(parse_authority(line))
|
||||
output_entry.update({'authority': authority_list})
|
||||
continue
|
||||
|
||||
if ';' not in line and answer:
|
||||
answer_list.append(parse_answer(line))
|
||||
output_entry.update({'answer': answer_list})
|
||||
continue
|
||||
if line.startswith(';; ANSWER SECTION:'):
|
||||
question = False
|
||||
authority = False
|
||||
answer = True
|
||||
axfr = False
|
||||
answer_list = []
|
||||
continue
|
||||
|
||||
# footer consists of 4 lines
|
||||
# footer line 1
|
||||
if line.startswith(';; Query time:'):
|
||||
output_entry.update({'query_time': line.split(':')[1].lstrip()})
|
||||
continue
|
||||
if ';' not in line and answer:
|
||||
answer_list.append(parse_answer(line))
|
||||
output_entry.update({'answer': answer_list})
|
||||
continue
|
||||
|
||||
# footer line 2
|
||||
if line.startswith(';; SERVER:'):
|
||||
output_entry.update({'server': line.split(':')[1].lstrip()})
|
||||
continue
|
||||
# footer consists of 4 lines
|
||||
# footer line 1
|
||||
if line.startswith(';; Query time:'):
|
||||
output_entry.update({'query_time': line.split(':')[1].lstrip()})
|
||||
continue
|
||||
|
||||
# footer line 3
|
||||
if line.startswith(';; WHEN:'):
|
||||
output_entry.update({'when': line.split(':', maxsplit=1)[1].lstrip()})
|
||||
continue
|
||||
# footer line 2
|
||||
if line.startswith(';; SERVER:'):
|
||||
output_entry.update({'server': line.split(':')[1].lstrip()})
|
||||
continue
|
||||
|
||||
# footer line 4 (last line)
|
||||
if line.startswith(';; MSG SIZE rcvd:'):
|
||||
output_entry.update({'rcvd': line.split(':')[1].lstrip()})
|
||||
# footer line 3
|
||||
if line.startswith(';; WHEN:'):
|
||||
output_entry.update({'when': line.split(':', maxsplit=1)[1].lstrip()})
|
||||
continue
|
||||
|
||||
if output_entry:
|
||||
raw_output.append(output_entry)
|
||||
elif line.startswith(';; XFR size:'):
|
||||
output_entry.update({'size': line.split(':')[1].lstrip()})
|
||||
# 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)
|
||||
if output_entry:
|
||||
raw_output.append(output_entry)
|
||||
elif line.startswith(';; XFR size:'):
|
||||
output_entry.update({'size': line.split(':')[1].lstrip()})
|
||||
|
||||
if output_entry:
|
||||
raw_output.append(output_entry)
|
||||
|
||||
raw_output = list(filter(None, raw_output))
|
||||
|
||||
raw_output = list(filter(None, raw_output))
|
||||
if raw:
|
||||
return raw_output
|
||||
else:
|
||||
|
||||
341
jc/parsers/dmidecode.py
Normal file
341
jc/parsers/dmidecode.py
Normal file
@@ -0,0 +1,341 @@
|
||||
"""jc - JSON CLI output utility dmidecode Parser
|
||||
|
||||
Usage:
|
||||
|
||||
specify --dmidecode as the first argument if the piped input is coming from dmidecode
|
||||
|
||||
Compatibility:
|
||||
|
||||
'linux'
|
||||
|
||||
Examples:
|
||||
|
||||
# dmidecode | jc --dmidecode -p
|
||||
[
|
||||
{
|
||||
"handle": "0x0000",
|
||||
"type": 0,
|
||||
"bytes": 24,
|
||||
"description": "BIOS Information",
|
||||
"values": {
|
||||
"vendor": "Phoenix Technologies LTD",
|
||||
"version": "6.00",
|
||||
"release_date": "04/13/2018",
|
||||
"address": "0xEA490",
|
||||
"runtime_size": "88944 bytes",
|
||||
"rom_size": "64 kB",
|
||||
"characteristics": [
|
||||
"ISA is supported",
|
||||
"PCI is supported",
|
||||
"PC Card (PCMCIA) is supported",
|
||||
"PNP is supported",
|
||||
"APM is supported",
|
||||
"BIOS is upgradeable",
|
||||
"BIOS shadowing is allowed",
|
||||
"ESCD support is available",
|
||||
"Boot from CD is supported",
|
||||
"Selectable boot is supported",
|
||||
"EDD is supported",
|
||||
"Print screen service is supported (int 5h)",
|
||||
"8042 keyboard services are supported (int 9h)",
|
||||
"Serial services are supported (int 14h)",
|
||||
"Printer services are supported (int 17h)",
|
||||
"CGA/mono video services are supported (int 10h)",
|
||||
"ACPI is supported",
|
||||
"Smart battery is supported",
|
||||
"BIOS boot specification is supported",
|
||||
"Function key-initiated network boot is supported",
|
||||
"Targeted content distribution is supported"
|
||||
],
|
||||
"bios_revision": "4.6",
|
||||
"firmware_revision": "0.0"
|
||||
}
|
||||
},
|
||||
...
|
||||
]
|
||||
|
||||
# dmidecode | jc --dmidecode -p -r
|
||||
[
|
||||
{
|
||||
"handle": "0x0000",
|
||||
"type": "0",
|
||||
"bytes": "24",
|
||||
"description": "BIOS Information",
|
||||
"values": {
|
||||
"vendor": "Phoenix Technologies LTD",
|
||||
"version": "6.00",
|
||||
"release_date": "04/13/2018",
|
||||
"address": "0xEA490",
|
||||
"runtime_size": "88944 bytes",
|
||||
"rom_size": "64 kB",
|
||||
"characteristics": [
|
||||
"ISA is supported",
|
||||
"PCI is supported",
|
||||
"PC Card (PCMCIA) is supported",
|
||||
"PNP is supported",
|
||||
"APM is supported",
|
||||
"BIOS is upgradeable",
|
||||
"BIOS shadowing is allowed",
|
||||
"ESCD support is available",
|
||||
"Boot from CD is supported",
|
||||
"Selectable boot is supported",
|
||||
"EDD is supported",
|
||||
"Print screen service is supported (int 5h)",
|
||||
"8042 keyboard services are supported (int 9h)",
|
||||
"Serial services are supported (int 14h)",
|
||||
"Printer services are supported (int 17h)",
|
||||
"CGA/mono video services are supported (int 10h)",
|
||||
"ACPI is supported",
|
||||
"Smart battery is supported",
|
||||
"BIOS boot specification is supported",
|
||||
"Function key-initiated network boot is supported",
|
||||
"Targeted content distribution is supported"
|
||||
],
|
||||
"bios_revision": "4.6",
|
||||
"firmware_revision": "0.0"
|
||||
}
|
||||
},
|
||||
...
|
||||
]
|
||||
"""
|
||||
import jc.utils
|
||||
|
||||
|
||||
class info():
|
||||
version = '1.1'
|
||||
description = 'dmidecode command parser'
|
||||
author = 'Kelly Brazil'
|
||||
author_email = 'kellyjonbrazil@gmail.com'
|
||||
# details = 'enter any other details here'
|
||||
|
||||
# compatible options: linux, darwin, cygwin, win32, aix, freebsd
|
||||
compatible = ['linux']
|
||||
magic_commands = ['dmidecode']
|
||||
|
||||
|
||||
__version__ = info.version
|
||||
|
||||
|
||||
def process(proc_data):
|
||||
"""
|
||||
Final processing to conform to the schema.
|
||||
|
||||
Parameters:
|
||||
|
||||
proc_data: (dictionary) raw structured data to process
|
||||
|
||||
Returns:
|
||||
|
||||
List of dictionaries. Structured data with the following schema:
|
||||
|
||||
[
|
||||
{
|
||||
"handle": string,
|
||||
"type": integer,
|
||||
"bytes": integer,
|
||||
"description": string,
|
||||
"values": { (null if empty)
|
||||
"lowercase_no_spaces_keys": string,
|
||||
"multiline_key_values": [
|
||||
string,
|
||||
]
|
||||
}
|
||||
}
|
||||
]
|
||||
"""
|
||||
for entry in proc_data:
|
||||
int_list = ['type', 'bytes']
|
||||
for key in int_list:
|
||||
if key in entry:
|
||||
try:
|
||||
key_int = int(entry[key])
|
||||
entry[key] = key_int
|
||||
except (ValueError):
|
||||
entry[key] = None
|
||||
|
||||
if not entry['values']:
|
||||
entry['values'] = None
|
||||
|
||||
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)
|
||||
|
||||
item_header = False
|
||||
item_values = False
|
||||
value_list = False
|
||||
|
||||
item = None
|
||||
header = None
|
||||
key = None
|
||||
val = None
|
||||
attribute = None
|
||||
values = None
|
||||
key_data = None
|
||||
|
||||
raw_output = []
|
||||
|
||||
if jc.utils.has_data(data):
|
||||
|
||||
data = data.splitlines()
|
||||
|
||||
# remove header rows
|
||||
for row in data.copy():
|
||||
if row:
|
||||
data.pop(0)
|
||||
else:
|
||||
break
|
||||
|
||||
# main parsing loop
|
||||
for line in data:
|
||||
# new item
|
||||
if not line:
|
||||
item_header = True
|
||||
item_values = False
|
||||
value_list = False
|
||||
|
||||
if item:
|
||||
if values:
|
||||
item['values'][attribute] = values
|
||||
if key_data:
|
||||
item['values'][f'{key}_data'] = key_data
|
||||
raw_output.append(item)
|
||||
|
||||
item = {}
|
||||
header = None
|
||||
key = None
|
||||
val = None
|
||||
attribute = None
|
||||
values = []
|
||||
key_data = []
|
||||
continue
|
||||
|
||||
# header
|
||||
if line.startswith('Handle ') and line.endswith('bytes'):
|
||||
|
||||
# Handle 0x0000, DMI type 0, 24 bytes
|
||||
header = line.replace(',', ' ').split()
|
||||
item = {
|
||||
'handle': header[1],
|
||||
'type': header[4],
|
||||
'bytes': header[5]
|
||||
}
|
||||
continue
|
||||
|
||||
# description
|
||||
if item_header:
|
||||
item_header = False
|
||||
item_values = True
|
||||
value_list = False
|
||||
|
||||
item['description'] = line
|
||||
item['values'] = {}
|
||||
continue
|
||||
|
||||
# new item if multiple descriptions in handle
|
||||
if not item_header and not line.startswith('\t'):
|
||||
item_header = False
|
||||
item_values = True
|
||||
value_list = False
|
||||
|
||||
if item:
|
||||
if values:
|
||||
item['values'][attribute] = values
|
||||
if key_data:
|
||||
item['values'][f'{key}_data'] = key_data
|
||||
raw_output.append(item)
|
||||
|
||||
item = {
|
||||
'handle': header[1],
|
||||
'type': header[4],
|
||||
'bytes': header[5],
|
||||
'description': line,
|
||||
'values': {}
|
||||
}
|
||||
|
||||
key = None
|
||||
val = None
|
||||
attribute = None
|
||||
values = []
|
||||
key_data = []
|
||||
continue
|
||||
|
||||
# keys and values
|
||||
if item_values \
|
||||
and len(line.split(':', maxsplit=1)) == 2 \
|
||||
and line.startswith('\t') \
|
||||
and not line.startswith('\t\t') \
|
||||
and not line.strip().endswith(':'):
|
||||
item_header = False
|
||||
item_values = True
|
||||
value_list = False
|
||||
|
||||
if values:
|
||||
item['values'][attribute] = values
|
||||
values = []
|
||||
if key_data:
|
||||
item['values'][f'{key}_data'] = key_data
|
||||
key_data = []
|
||||
|
||||
key = line.split(':', maxsplit=1)[0].strip().lower().replace(' ', '_')
|
||||
val = line.split(':', maxsplit=1)[1].strip()
|
||||
item['values'].update({key: val})
|
||||
continue
|
||||
|
||||
# multi-line key
|
||||
if item_values \
|
||||
and line.startswith('\t') \
|
||||
and not line.startswith('\t\t') \
|
||||
and line.strip().endswith(':'):
|
||||
item_header = False
|
||||
item_values = True
|
||||
value_list = True
|
||||
|
||||
if values:
|
||||
item['values'][attribute] = values
|
||||
values = []
|
||||
if key_data:
|
||||
item['values'][f'{key}_data'] = key_data
|
||||
key_data = []
|
||||
|
||||
attribute = line[:-1].strip().lower().replace(' ', '_')
|
||||
values = []
|
||||
continue
|
||||
|
||||
# multi-line values
|
||||
if value_list \
|
||||
and line.startswith('\t\t'):
|
||||
values.append(line.strip())
|
||||
continue
|
||||
|
||||
# data for hybrid multi-line objects
|
||||
if item_values \
|
||||
and not value_list \
|
||||
and line.startswith('\t\t'):
|
||||
if f'{key}_data' not in item['values']:
|
||||
item['values'][f'{key}_data'] = []
|
||||
key_data.append(line.strip())
|
||||
continue
|
||||
|
||||
if item:
|
||||
raw_output.append(item)
|
||||
|
||||
if raw:
|
||||
return raw_output
|
||||
else:
|
||||
return process(raw_output)
|
||||
@@ -73,7 +73,7 @@ import jc.parsers.universal
|
||||
|
||||
|
||||
class info():
|
||||
version = '1.1'
|
||||
version = '1.2'
|
||||
description = 'du command parser'
|
||||
author = 'Kelly Brazil'
|
||||
author_email = 'kellyjonbrazil@gmail.com'
|
||||
@@ -137,12 +137,12 @@ def parse(data, raw=False, quiet=False):
|
||||
jc.utils.compatibility(__name__, info.compatible)
|
||||
|
||||
raw_output = []
|
||||
cleandata = data.splitlines()
|
||||
|
||||
# Clear any blank lines
|
||||
cleandata = list(filter(None, cleandata))
|
||||
cleandata = list(filter(None, data.splitlines()))
|
||||
|
||||
if jc.utils.has_data(data):
|
||||
|
||||
if cleandata:
|
||||
cleandata.insert(0, 'size name')
|
||||
raw_output = jc.parsers.universal.simple_table_parse(cleandata)
|
||||
|
||||
|
||||
@@ -52,7 +52,7 @@ import jc.utils
|
||||
|
||||
|
||||
class info():
|
||||
version = '1.1'
|
||||
version = '1.2'
|
||||
description = 'env command parser'
|
||||
author = 'Kelly Brazil'
|
||||
author_email = 'kellyjonbrazil@gmail.com'
|
||||
@@ -116,12 +116,10 @@ def parse(data, raw=False, quiet=False):
|
||||
|
||||
raw_output = {}
|
||||
|
||||
linedata = data.splitlines()
|
||||
|
||||
# Clear any blank lines
|
||||
cleandata = list(filter(None, linedata))
|
||||
cleandata = list(filter(None, data.splitlines()))
|
||||
|
||||
if cleandata:
|
||||
if jc.utils.has_data(data):
|
||||
|
||||
for entry in cleandata:
|
||||
parsed_line = entry.split('=', maxsplit=1)
|
||||
|
||||
@@ -48,7 +48,7 @@ import jc.parsers.universal
|
||||
|
||||
|
||||
class info():
|
||||
version = '1.1'
|
||||
version = '1.2'
|
||||
description = 'file command parser'
|
||||
author = 'Kelly Brazil'
|
||||
author_email = 'kellyjonbrazil@gmail.com'
|
||||
@@ -104,23 +104,26 @@ def parse(data, raw=False, quiet=False):
|
||||
raw_output = []
|
||||
|
||||
warned = False
|
||||
for line in filter(None, data.splitlines()):
|
||||
linedata = line.rsplit(': ', maxsplit=1)
|
||||
|
||||
try:
|
||||
filename = linedata[0].strip()
|
||||
filetype = linedata[1].strip()
|
||||
if jc.utils.has_data(data):
|
||||
|
||||
raw_output.append(
|
||||
{
|
||||
'filename': filename,
|
||||
'type': filetype
|
||||
}
|
||||
)
|
||||
except IndexError:
|
||||
if not warned:
|
||||
jc.utils.warning_message('Filenames with newline characters detected. Some filenames may be truncated.')
|
||||
warned = True
|
||||
for line in filter(None, data.splitlines()):
|
||||
linedata = line.rsplit(': ', maxsplit=1)
|
||||
|
||||
try:
|
||||
filename = linedata[0].strip()
|
||||
filetype = linedata[1].strip()
|
||||
|
||||
raw_output.append(
|
||||
{
|
||||
'filename': filename,
|
||||
'type': filetype
|
||||
}
|
||||
)
|
||||
except IndexError:
|
||||
if not warned:
|
||||
jc.utils.warning_message('Filenames with newline characters detected. Some filenames may be truncated.')
|
||||
warned = True
|
||||
|
||||
if raw:
|
||||
return raw_output
|
||||
|
||||
@@ -78,9 +78,11 @@ def parse(data, raw=False, quiet=False):
|
||||
|
||||
raw_output = []
|
||||
|
||||
for line in filter(None, data.splitlines()):
|
||||
# parse the content
|
||||
pass
|
||||
if jc.utils.has_data(data):
|
||||
|
||||
for line in filter(None, data.splitlines()):
|
||||
# parse the content
|
||||
pass
|
||||
|
||||
if raw:
|
||||
return raw_output
|
||||
|
||||
@@ -53,7 +53,7 @@ import jc.parsers.universal
|
||||
|
||||
|
||||
class info():
|
||||
version = '1.0'
|
||||
version = '1.2'
|
||||
description = 'free command parser'
|
||||
author = 'Kelly Brazil'
|
||||
author_email = 'kellyjonbrazil@gmail.com'
|
||||
@@ -122,14 +122,18 @@ def parse(data, raw=False, quiet=False):
|
||||
jc.utils.compatibility(__name__, info.compatible)
|
||||
|
||||
cleandata = data.splitlines()
|
||||
cleandata[0] = cleandata[0].lower()
|
||||
cleandata[0] = cleandata[0].replace('buff/cache', 'buff_cache')
|
||||
cleandata[0] = 'type ' + cleandata[0]
|
||||
raw_output = []
|
||||
|
||||
raw_output = jc.parsers.universal.simple_table_parse(cleandata)
|
||||
if jc.utils.has_data(data):
|
||||
|
||||
for entry in raw_output:
|
||||
entry['type'] = entry['type'].rstrip(':')
|
||||
cleandata[0] = cleandata[0].lower()
|
||||
cleandata[0] = cleandata[0].replace('buff/cache', 'buff_cache')
|
||||
cleandata[0] = 'type ' + cleandata[0]
|
||||
|
||||
raw_output = jc.parsers.universal.simple_table_parse(cleandata)
|
||||
|
||||
for entry in raw_output:
|
||||
entry['type'] = entry['type'].rstrip(':')
|
||||
|
||||
if raw:
|
||||
return raw_output
|
||||
|
||||
@@ -6,7 +6,7 @@ Usage:
|
||||
|
||||
Compatibility:
|
||||
|
||||
'linux'
|
||||
'linux', 'freebsd'
|
||||
|
||||
Examples:
|
||||
|
||||
@@ -70,13 +70,13 @@ import jc.utils
|
||||
|
||||
|
||||
class info():
|
||||
version = '1.1'
|
||||
version = '1.3'
|
||||
description = 'fstab file parser'
|
||||
author = 'Kelly Brazil'
|
||||
author_email = 'kellyjonbrazil@gmail.com'
|
||||
|
||||
# compatible options: linux, darwin, cygwin, win32, aix, freebsd
|
||||
compatible = ['linux']
|
||||
compatible = ['linux', 'freebsd']
|
||||
|
||||
|
||||
__version__ = info.version
|
||||
@@ -141,7 +141,8 @@ def parse(data, raw=False, quiet=False):
|
||||
# Clear any blank lines
|
||||
cleandata = list(filter(None, cleandata))
|
||||
|
||||
if cleandata:
|
||||
if jc.utils.has_data(data):
|
||||
|
||||
for line in cleandata:
|
||||
output_line = {}
|
||||
# ignore commented lines
|
||||
|
||||
@@ -94,7 +94,7 @@ import jc.utils
|
||||
|
||||
|
||||
class info():
|
||||
version = '1.0'
|
||||
version = '1.1'
|
||||
description = '/etc/group file parser'
|
||||
author = 'Kelly Brazil'
|
||||
author_email = 'kellyjonbrazil@gmail.com'
|
||||
@@ -169,7 +169,8 @@ def parse(data, raw=False, quiet=False):
|
||||
# Clear any blank lines
|
||||
cleandata = list(filter(None, cleandata))
|
||||
|
||||
if cleandata:
|
||||
if jc.utils.has_data(data):
|
||||
|
||||
for entry in cleandata:
|
||||
if entry.startswith('#'):
|
||||
continue
|
||||
|
||||
@@ -60,7 +60,7 @@ import jc.utils
|
||||
|
||||
|
||||
class info():
|
||||
version = '1.0'
|
||||
version = '1.1'
|
||||
description = '/etc/gshadow file parser'
|
||||
author = 'Kelly Brazil'
|
||||
author_email = 'kellyjonbrazil@gmail.com'
|
||||
@@ -131,7 +131,8 @@ def parse(data, raw=False, quiet=False):
|
||||
# Clear any blank lines
|
||||
cleandata = list(filter(None, cleandata))
|
||||
|
||||
if cleandata:
|
||||
if jc.utils.has_data(data):
|
||||
|
||||
for entry in cleandata:
|
||||
if entry.startswith('#'):
|
||||
continue
|
||||
|
||||
@@ -44,7 +44,7 @@ import jc.utils
|
||||
|
||||
|
||||
class info():
|
||||
version = '1.2'
|
||||
version = '1.3'
|
||||
description = 'history command parser'
|
||||
author = 'Kelly Brazil'
|
||||
author_email = 'kellyjonbrazil@gmail.com'
|
||||
@@ -108,17 +108,19 @@ def parse(data, raw=False, quiet=False):
|
||||
|
||||
raw_output = {}
|
||||
|
||||
# split lines and clear out any non-ascii chars
|
||||
linedata = data.encode('ascii', errors='ignore').decode().splitlines()
|
||||
if jc.utils.has_data(data):
|
||||
|
||||
# Skip any blank lines
|
||||
for entry in filter(None, linedata):
|
||||
try:
|
||||
parsed_line = entry.split(maxsplit=1)
|
||||
raw_output[parsed_line[0]] = parsed_line[1]
|
||||
except IndexError:
|
||||
# need to catch indexerror in case there is weird input from prior commands
|
||||
pass
|
||||
# split lines and clear out any non-ascii chars
|
||||
linedata = data.encode('ascii', errors='ignore').decode().splitlines()
|
||||
|
||||
# Skip any blank lines
|
||||
for entry in filter(None, linedata):
|
||||
try:
|
||||
parsed_line = entry.split(maxsplit=1)
|
||||
raw_output[parsed_line[0]] = parsed_line[1]
|
||||
except IndexError:
|
||||
# need to catch indexerror in case there is weird input from prior commands
|
||||
pass
|
||||
|
||||
if raw:
|
||||
return raw_output
|
||||
|
||||
@@ -61,7 +61,7 @@ import jc.utils
|
||||
|
||||
|
||||
class info():
|
||||
version = '1.1'
|
||||
version = '1.2'
|
||||
description = '/etc/hosts file parser'
|
||||
author = 'Kelly Brazil'
|
||||
author_email = 'kellyjonbrazil@gmail.com'
|
||||
@@ -117,12 +117,12 @@ def parse(data, raw=False, quiet=False):
|
||||
jc.utils.compatibility(__name__, info.compatible)
|
||||
|
||||
raw_output = []
|
||||
cleandata = data.splitlines()
|
||||
|
||||
# Clear any blank lines
|
||||
cleandata = list(filter(None, cleandata))
|
||||
cleandata = list(filter(None, data.splitlines()))
|
||||
|
||||
if jc.utils.has_data(data):
|
||||
|
||||
if cleandata:
|
||||
for line in cleandata:
|
||||
output_line = {}
|
||||
# ignore commented lines
|
||||
|
||||
@@ -70,7 +70,7 @@ import jc.utils
|
||||
|
||||
|
||||
class info():
|
||||
version = '1.0'
|
||||
version = '1.1'
|
||||
description = 'id command parser'
|
||||
author = 'Kelly Brazil'
|
||||
author_email = 'kellyjonbrazil@gmail.com'
|
||||
@@ -166,12 +166,12 @@ def parse(data, raw=False, quiet=False):
|
||||
jc.utils.compatibility(__name__, info.compatible)
|
||||
|
||||
raw_output = {}
|
||||
cleandata = data.split()
|
||||
|
||||
# Clear any blank lines
|
||||
cleandata = list(filter(None, cleandata))
|
||||
cleandata = list(filter(None, data.split()))
|
||||
|
||||
if jc.utils.has_data(data):
|
||||
|
||||
if cleandata:
|
||||
for section in cleandata:
|
||||
if section.startswith('uid'):
|
||||
uid_parsed = section.replace('(', '=').replace(')', '=')
|
||||
|
||||
@@ -147,7 +147,7 @@ import jc.utils
|
||||
|
||||
|
||||
class info():
|
||||
version = '1.7'
|
||||
version = '1.8'
|
||||
description = 'ifconfig command parser'
|
||||
author = 'Kelly Brazil'
|
||||
author_email = 'kellyjonbrazil@gmail.com'
|
||||
@@ -372,8 +372,6 @@ class IfconfigParser(object):
|
||||
|
||||
|
||||
class InterfaceNotFound(Exception):
|
||||
"""
|
||||
"""
|
||||
pass
|
||||
|
||||
|
||||
@@ -475,14 +473,16 @@ def parse(data, raw=False, quiet=False):
|
||||
|
||||
raw_output = []
|
||||
|
||||
parsed = IfconfigParser(console_output=data)
|
||||
interfaces = parsed.get_interfaces()
|
||||
if jc.utils.has_data(data):
|
||||
|
||||
# convert ifconfigparser output to a dictionary
|
||||
for iface in interfaces:
|
||||
d = interfaces[iface]._asdict()
|
||||
dct = dict(d)
|
||||
raw_output.append(dct)
|
||||
parsed = IfconfigParser(console_output=data)
|
||||
interfaces = parsed.get_interfaces()
|
||||
|
||||
# convert ifconfigparser output to a dictionary
|
||||
for iface in interfaces:
|
||||
d = interfaces[iface]._asdict()
|
||||
dct = dict(d)
|
||||
raw_output.append(dct)
|
||||
|
||||
if raw:
|
||||
return raw_output
|
||||
|
||||
@@ -2,7 +2,9 @@
|
||||
|
||||
Usage:
|
||||
|
||||
specify --ini as the first argument if the piped input is coming from an INI file
|
||||
Specify --ini as the first argument if the piped input is coming from an INI file or any
|
||||
simple key/value pair file. Delimiter can be '=' or ':'. Missing values are supported.
|
||||
Comment prefix can be '#' or ';'. Comments must be on their own line.
|
||||
|
||||
Compatibility:
|
||||
|
||||
@@ -47,7 +49,7 @@ import configparser
|
||||
|
||||
|
||||
class info():
|
||||
version = '1.0'
|
||||
version = '1.3'
|
||||
description = 'INI file parser'
|
||||
author = 'Kelly Brazil'
|
||||
author_email = 'kellyjonbrazil@gmail.com'
|
||||
@@ -70,15 +72,33 @@ def process(proc_data):
|
||||
|
||||
Returns:
|
||||
|
||||
Dictionary representing an ini document:
|
||||
Dictionary representing an ini or simple key/value pair document:
|
||||
|
||||
{
|
||||
ini document converted to a dictionary
|
||||
see configparser standard library documentation for more details
|
||||
ini or key/value document converted to a dictionary - see configparser standard
|
||||
library documentation for more details.
|
||||
|
||||
Note: Values starting and ending with quotation marks will have the marks removed.
|
||||
If you would like to keep the quotation marks, use the -r or raw=True argument.
|
||||
}
|
||||
"""
|
||||
# remove quotation marks from beginning and end of values
|
||||
for heading in proc_data:
|
||||
# standard ini files with headers
|
||||
if isinstance(proc_data[heading], dict):
|
||||
for key, value in proc_data[heading].items():
|
||||
if value is not None and value.startswith('"') and value.endswith('"'):
|
||||
proc_data[heading][key] = value.lstrip('"').rstrip('"')
|
||||
elif value is None:
|
||||
proc_data[heading][key] = ''
|
||||
|
||||
# simple key/value files with no headers
|
||||
else:
|
||||
if proc_data[heading] is not None and proc_data[heading].startswith('"') and proc_data[heading].endswith('"'):
|
||||
proc_data[heading] = proc_data[heading].lstrip('"').rstrip('"')
|
||||
elif proc_data[heading] is None:
|
||||
proc_data[heading] = ''
|
||||
|
||||
# No further processing
|
||||
return proc_data
|
||||
|
||||
|
||||
@@ -101,10 +121,19 @@ def parse(data, raw=False, quiet=False):
|
||||
|
||||
raw_output = {}
|
||||
|
||||
if data:
|
||||
ini = configparser.ConfigParser()
|
||||
ini.read_string(data)
|
||||
raw_output = {s: dict(ini.items(s)) for s in ini.sections()}
|
||||
if jc.utils.has_data(data):
|
||||
|
||||
ini = configparser.ConfigParser(allow_no_value=True, interpolation=None)
|
||||
try:
|
||||
ini.read_string(data)
|
||||
raw_output = {s: dict(ini.items(s)) for s in ini.sections()}
|
||||
|
||||
except configparser.MissingSectionHeaderError:
|
||||
data = '[data]\n' + data
|
||||
ini.read_string(data)
|
||||
output_dict = {s: dict(ini.items(s)) for s in ini.sections()}
|
||||
for key, value in output_dict['data'].items():
|
||||
raw_output[key] = value
|
||||
|
||||
if raw:
|
||||
return raw_output
|
||||
|
||||
@@ -134,7 +134,7 @@ import jc.utils
|
||||
|
||||
|
||||
class info():
|
||||
version = '1.2'
|
||||
version = '1.4'
|
||||
description = 'iptables command parser'
|
||||
author = 'Kelly Brazil'
|
||||
author_email = 'kellyjonbrazil@gmail.com'
|
||||
@@ -194,19 +194,19 @@ def process(proc_data):
|
||||
if 'bytes' in rule:
|
||||
multiplier = 1
|
||||
if rule['bytes'][-1] == 'K':
|
||||
multiplier = 1000
|
||||
multiplier = 10 ** 3
|
||||
rule['bytes'] = rule['bytes'].rstrip('K')
|
||||
elif rule['bytes'][-1] == 'M':
|
||||
multiplier = 1000000
|
||||
multiplier = 10 ** 6
|
||||
rule['bytes'] = rule['bytes'].rstrip('M')
|
||||
elif rule['bytes'][-1] == 'G':
|
||||
multiplier = 1000000000
|
||||
multiplier = 10 ** 9
|
||||
rule['bytes'] = rule['bytes'].rstrip('G')
|
||||
elif rule['bytes'][-1] == 'T':
|
||||
multiplier = 1000000000000
|
||||
multiplier = 10 ** 12
|
||||
rule['bytes'] = rule['bytes'].rstrip('T')
|
||||
elif rule['bytes'][-1] == 'P':
|
||||
multiplier = 1000000000000000
|
||||
multiplier = 10 ** 15
|
||||
rule['bytes'] = rule['bytes'].rstrip('P')
|
||||
|
||||
try:
|
||||
@@ -243,36 +243,39 @@ def parse(data, raw=False, quiet=False):
|
||||
chain = {}
|
||||
headers = []
|
||||
|
||||
cleandata = data.splitlines()
|
||||
if jc.utils.has_data(data):
|
||||
|
||||
for line in cleandata:
|
||||
for line in list(filter(None, data.splitlines())):
|
||||
|
||||
if line.startswith('Chain'):
|
||||
if line.startswith('Chain'):
|
||||
if chain:
|
||||
raw_output.append(chain)
|
||||
|
||||
chain = {}
|
||||
headers = []
|
||||
|
||||
parsed_line = line.split()
|
||||
|
||||
chain['chain'] = parsed_line[1]
|
||||
chain['rules'] = []
|
||||
|
||||
continue
|
||||
|
||||
elif line.startswith('target') or line.find('pkts') == 1 or line.startswith('num'):
|
||||
headers = []
|
||||
headers = [h for h in ' '.join(line.lower().strip().split()).split() if h]
|
||||
headers.append("options")
|
||||
|
||||
continue
|
||||
|
||||
else:
|
||||
rule = line.split(maxsplit=len(headers) - 1)
|
||||
temp_rule = dict(zip(headers, rule))
|
||||
if temp_rule:
|
||||
chain['rules'].append(temp_rule)
|
||||
|
||||
if chain:
|
||||
raw_output.append(chain)
|
||||
chain = {}
|
||||
headers = []
|
||||
|
||||
parsed_line = line.split()
|
||||
|
||||
chain['chain'] = parsed_line[1]
|
||||
chain['rules'] = []
|
||||
|
||||
continue
|
||||
|
||||
elif line.startswith('target') or line.find('pkts') == 1 or line.startswith('num'):
|
||||
headers = []
|
||||
headers = [h for h in ' '.join(line.lower().strip().split()).split() if h]
|
||||
headers.append("options")
|
||||
|
||||
continue
|
||||
|
||||
else:
|
||||
rule = line.split(maxsplit=len(headers) - 1)
|
||||
temp_rule = dict(zip(headers, rule))
|
||||
if temp_rule:
|
||||
chain['rules'].append(temp_rule)
|
||||
|
||||
raw_output = list(filter(None, raw_output))
|
||||
|
||||
if raw:
|
||||
return raw_output
|
||||
|
||||
@@ -77,7 +77,7 @@ import jc.utils
|
||||
|
||||
|
||||
class info():
|
||||
version = '1.1'
|
||||
version = '1.2'
|
||||
description = 'jobs command parser'
|
||||
author = 'Kelly Brazil'
|
||||
author_email = 'kellyjonbrazil@gmail.com'
|
||||
@@ -144,12 +144,10 @@ def parse(data, raw=False, quiet=False):
|
||||
|
||||
raw_output = []
|
||||
|
||||
linedata = data.splitlines()
|
||||
|
||||
# Clear any blank lines
|
||||
cleandata = list(filter(None, linedata))
|
||||
cleandata = list(filter(None, data.splitlines()))
|
||||
|
||||
if cleandata:
|
||||
if jc.utils.has_data(data):
|
||||
|
||||
for entry in cleandata:
|
||||
output_line = {}
|
||||
|
||||
67
jc/parsers/kv.py
Normal file
67
jc/parsers/kv.py
Normal file
@@ -0,0 +1,67 @@
|
||||
"""jc - JSON CLI output utility Key/Value File Parser
|
||||
|
||||
Usage:
|
||||
|
||||
Specify --kv as the first argument if the piped input is coming from a simple
|
||||
key/value pair file. Delimiter can be '=' or ':'. Missing values are supported.
|
||||
Comment prefix can be '#' or ';'. Comments must be on their own line.
|
||||
|
||||
Compatibility:
|
||||
|
||||
'linux', 'darwin', 'cygwin', 'win32', 'aix', 'freebsd'
|
||||
|
||||
Examples:
|
||||
|
||||
$ cat keyvalue.txt
|
||||
# this file contains key/value pairs
|
||||
name = John Doe
|
||||
address=555 California Drive
|
||||
age: 34
|
||||
; comments can include # or ;
|
||||
# delimiter can be = or :
|
||||
# quoted values have quotation marks stripped by default
|
||||
# but can be preserved with the -r argument
|
||||
occupation:"Engineer"
|
||||
|
||||
$ cat keyvalue.txt | jc --ini -p
|
||||
{
|
||||
"name": "John Doe",
|
||||
"address": "555 California Drive",
|
||||
"age": "34",
|
||||
"occupation": "Engineer"
|
||||
}
|
||||
"""
|
||||
|
||||
|
||||
class info():
|
||||
version = '1.0'
|
||||
description = 'Key/Value file parser'
|
||||
author = 'Kelly Brazil'
|
||||
author_email = 'kellyjonbrazil@gmail.com'
|
||||
details = 'This is a wrapper for the INI parser'
|
||||
|
||||
# compatible options: linux, darwin, cygwin, win32, aix, freebsd
|
||||
compatible = ['linux', 'darwin', 'cygwin', 'win32', 'aix', 'freebsd']
|
||||
|
||||
|
||||
__version__ = info.version
|
||||
|
||||
|
||||
def parse(data, raw=False, quiet=False):
|
||||
"""
|
||||
Main text parsing function
|
||||
|
||||
Note: this is just a wrapper for jc.parsers.ini
|
||||
|
||||
Parameters:
|
||||
|
||||
data: (string) text data to parse
|
||||
raw: (boolean) output preprocessed JSON if True
|
||||
quiet: (boolean) suppress warning messages if True
|
||||
|
||||
Returns:
|
||||
|
||||
Dictionary representing the key/value file
|
||||
"""
|
||||
import jc.parsers.ini
|
||||
return jc.parsers.ini.parse(data, raw=raw, quiet=quiet)
|
||||
@@ -72,7 +72,7 @@ import jc.utils
|
||||
|
||||
|
||||
class info():
|
||||
version = '1.1'
|
||||
version = '1.3'
|
||||
description = 'last and lastb command parser'
|
||||
author = 'Kelly Brazil'
|
||||
author_email = 'kellyjonbrazil@gmail.com'
|
||||
@@ -110,6 +110,9 @@ def process(proc_data):
|
||||
]
|
||||
"""
|
||||
for entry in proc_data:
|
||||
if 'user' in entry and entry['user'] == 'boot_time':
|
||||
entry['user'] = 'boot time'
|
||||
|
||||
if 'tty' in entry and entry['tty'] == '~':
|
||||
entry['tty'] = None
|
||||
|
||||
@@ -146,19 +149,20 @@ def parse(data, raw=False, quiet=False):
|
||||
jc.utils.compatibility(__name__, info.compatible)
|
||||
|
||||
raw_output = []
|
||||
cleandata = data.splitlines()
|
||||
|
||||
# Clear any blank lines
|
||||
cleandata = list(filter(None, cleandata))
|
||||
cleandata = list(filter(None, data.splitlines()))
|
||||
|
||||
if jc.utils.has_data(data):
|
||||
|
||||
if cleandata:
|
||||
for entry in cleandata:
|
||||
output_line = {}
|
||||
|
||||
if entry.startswith('wtmp begins ') or entry.startswith('btmp begins '):
|
||||
if entry.startswith('wtmp begins ') or entry.startswith('btmp begins ') or entry.startswith('utx.log begins '):
|
||||
continue
|
||||
|
||||
entry = entry.replace('system boot', 'system_boot')
|
||||
entry = entry.replace('boot time', 'boot_time')
|
||||
entry = entry.replace(' still logged in', '- still_logged_in')
|
||||
entry = entry.replace(' gone - no logout', '- gone_-_no_logout')
|
||||
|
||||
@@ -166,6 +170,11 @@ def parse(data, raw=False, quiet=False):
|
||||
if re.match(r'[MTWFS][ouerha][nedritnu] [JFMASOND][aepuco][nbrynlgptvc]', ' '.join(linedata[2:4])):
|
||||
linedata.insert(2, '-')
|
||||
|
||||
# freebsd fix
|
||||
if linedata[0] == 'boot_time':
|
||||
linedata.insert(1, '-')
|
||||
linedata.insert(1, '~')
|
||||
|
||||
output_line['user'] = linedata[0]
|
||||
output_line['tty'] = linedata[1]
|
||||
output_line['hostname'] = linedata[2]
|
||||
|
||||
@@ -149,7 +149,7 @@ import jc.utils
|
||||
|
||||
|
||||
class info():
|
||||
version = '1.4'
|
||||
version = '1.6'
|
||||
description = 'ls command parser'
|
||||
author = 'Kelly Brazil'
|
||||
author_email = 'kellyjonbrazil@gmail.com'
|
||||
@@ -226,20 +226,20 @@ def parse(data, raw=False, quiet=False):
|
||||
|
||||
linedata = data.splitlines()
|
||||
|
||||
# Delete first line if it starts with 'total 1234'
|
||||
if linedata:
|
||||
if jc.utils.has_data(data):
|
||||
|
||||
# Delete first line if it starts with 'total 1234'
|
||||
if re.match(r'total [0-9]+', linedata[0]):
|
||||
linedata.pop(0)
|
||||
|
||||
# Look for parent line if glob or -R is used
|
||||
if not re.match(r'[-dclpsbDCMnP?]([-r][-w][-xsS]){2}([-r][-w][-xtT])[+]?', linedata[0]) \
|
||||
and linedata[0].endswith(':'):
|
||||
parent = linedata.pop(0)[:-1]
|
||||
# Pop following total line if it exists
|
||||
if re.match(r'total [0-9]+', linedata[0]):
|
||||
linedata.pop(0)
|
||||
# Look for parent line if glob or -R is used
|
||||
if not re.match(r'[-dclpsbDCMnP?]([-r][-w][-xsS]){2}([-r][-w][-xtT])[+]?', linedata[0]) \
|
||||
and linedata[0].endswith(':'):
|
||||
parent = linedata.pop(0)[:-1]
|
||||
# Pop following total line if it exists
|
||||
if re.match(r'total [0-9]+', linedata[0]):
|
||||
linedata.pop(0)
|
||||
|
||||
if linedata:
|
||||
# Check if -l was used to parse extra data
|
||||
if re.match(r'[-dclpsbDCMnP?]([-r][-w][-xsS]){2}([-r][-w][-xtT])[+]?', linedata[0]):
|
||||
for entry in linedata:
|
||||
|
||||
@@ -216,7 +216,7 @@ import jc.parsers.universal
|
||||
|
||||
|
||||
class info():
|
||||
version = '1.3'
|
||||
version = '1.5'
|
||||
description = 'lsblk command parser'
|
||||
author = 'Kelly Brazil'
|
||||
author_email = 'kellyjonbrazil@gmail.com'
|
||||
@@ -327,20 +327,23 @@ def parse(data, raw=False, quiet=False):
|
||||
if not quiet:
|
||||
jc.utils.compatibility(__name__, info.compatible)
|
||||
|
||||
linedata = data.splitlines()
|
||||
# Clear any blank lines
|
||||
cleandata = list(filter(None, linedata))
|
||||
cleandata = data.splitlines()
|
||||
cleandata = list(filter(None, data.splitlines()))
|
||||
raw_output = []
|
||||
|
||||
cleandata[0] = cleandata[0].lower()
|
||||
cleandata[0] = cleandata[0].replace(':', '_')
|
||||
cleandata[0] = cleandata[0].replace('-', '_')
|
||||
if jc.utils.has_data(data):
|
||||
|
||||
raw_output = jc.parsers.universal.sparse_table_parse(cleandata)
|
||||
cleandata = data.splitlines()
|
||||
|
||||
# clean up non-ascii characters, if any
|
||||
for entry in raw_output:
|
||||
entry['name'] = entry['name'].encode('ascii', errors='ignore').decode()
|
||||
cleandata[0] = cleandata[0].lower()
|
||||
cleandata[0] = cleandata[0].replace(':', '_')
|
||||
cleandata[0] = cleandata[0].replace('-', '_')
|
||||
|
||||
raw_output = jc.parsers.universal.sparse_table_parse(cleandata)
|
||||
|
||||
# clean up non-ascii characters, if any
|
||||
for entry in raw_output:
|
||||
entry['name'] = entry['name'].encode('ascii', errors='ignore').decode()
|
||||
|
||||
if raw:
|
||||
return raw_output
|
||||
|
||||
@@ -107,7 +107,7 @@ import jc.parsers.universal
|
||||
|
||||
|
||||
class info():
|
||||
version = '1.1'
|
||||
version = '1.3'
|
||||
description = 'lsmod command parser'
|
||||
author = 'Kelly Brazil'
|
||||
author_email = 'kellyjonbrazil@gmail.com'
|
||||
@@ -175,13 +175,17 @@ def parse(data, raw=False, quiet=False):
|
||||
jc.utils.compatibility(__name__, info.compatible)
|
||||
|
||||
cleandata = data.splitlines()
|
||||
cleandata[0] = cleandata[0].lower()
|
||||
raw_output = []
|
||||
|
||||
raw_output = jc.parsers.universal.simple_table_parse(cleandata)
|
||||
if jc.utils.has_data(data):
|
||||
|
||||
for mod in raw_output:
|
||||
if 'by' in mod:
|
||||
mod['by'] = mod['by'].split(',')
|
||||
cleandata[0] = cleandata[0].lower()
|
||||
|
||||
raw_output = jc.parsers.universal.simple_table_parse(cleandata)
|
||||
|
||||
for mod in raw_output:
|
||||
if 'by' in mod:
|
||||
mod['by'] = mod['by'].split(',')
|
||||
|
||||
if raw:
|
||||
return raw_output
|
||||
|
||||
@@ -97,7 +97,7 @@ import jc.parsers.universal
|
||||
|
||||
|
||||
class info():
|
||||
version = '1.1'
|
||||
version = '1.2'
|
||||
description = 'lsof command parser'
|
||||
author = 'Kelly Brazil'
|
||||
author_email = 'kellyjonbrazil@gmail.com'
|
||||
@@ -169,12 +169,11 @@ def parse(data, raw=False, quiet=False):
|
||||
|
||||
raw_output = []
|
||||
|
||||
linedata = data.splitlines()
|
||||
|
||||
# Clear any blank lines
|
||||
cleandata = list(filter(None, linedata))
|
||||
cleandata = list(filter(None, data.splitlines()))
|
||||
|
||||
if jc.utils.has_data(data):
|
||||
|
||||
if cleandata:
|
||||
cleandata[0] = cleandata[0].lower()
|
||||
cleandata[0] = cleandata[0].replace('/', '_')
|
||||
|
||||
|
||||
@@ -6,7 +6,7 @@ Usage:
|
||||
|
||||
Compatibility:
|
||||
|
||||
'linux', 'darwin'
|
||||
'linux', 'darwin', 'freebsd'
|
||||
|
||||
Example:
|
||||
|
||||
@@ -56,13 +56,13 @@ import jc.utils
|
||||
|
||||
|
||||
class info():
|
||||
version = '1.2'
|
||||
version = '1.5'
|
||||
description = 'mount command parser'
|
||||
author = 'Kelly Brazil'
|
||||
author_email = 'kellyjonbrazil@gmail.com'
|
||||
|
||||
# compatible options: linux, darwin, cygwin, win32, aix, freebsd
|
||||
compatible = ['linux', 'darwin']
|
||||
compatible = ['linux', 'darwin', 'freebsd']
|
||||
magic_commands = ['mount']
|
||||
|
||||
|
||||
@@ -158,12 +158,12 @@ def parse(data, raw=False, quiet=False):
|
||||
if not quiet:
|
||||
jc.utils.compatibility(__name__, info.compatible)
|
||||
|
||||
linedata = data.splitlines()
|
||||
|
||||
# Clear any blank lines
|
||||
cleandata = list(filter(None, linedata))
|
||||
cleandata = list(filter(None, data.splitlines()))
|
||||
raw_output = []
|
||||
|
||||
if jc.utils.has_data(data):
|
||||
|
||||
if cleandata:
|
||||
# check for OSX output
|
||||
if ' type ' not in cleandata[0]:
|
||||
raw_output = osx_parse(cleandata)
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user