1
0
mirror of https://github.com/kellyjonbrazil/jc.git synced 2026-04-03 17:44:07 +02:00

Compare commits

..

519 Commits

Author SHA1 Message Date
Kelly Brazil
ddabfaa05c Merge pull request #25 from kellyjonbrazil/dev
Dev v1.7.4
2020-02-19 07:05:29 -08:00
Kelly Brazil
f857523ca7 bump to version 1.7.4 2020-02-19 07:02:50 -08:00
Kelly Brazil
00d53858e8 add note about aliases not being supported 2020-02-17 22:57:15 -08:00
Kelly Brazil
c008167e66 add time-style=full-iso option to doc 2020-02-17 22:48:44 -08:00
Kelly Brazil
102344a041 formatting 2020-02-17 22:32:07 -08:00
Kelly Brazil
c865298ef3 remove unnecessary enumerate in for loop 2020-02-17 22:29:39 -08:00
Kelly Brazil
6ac03faf93 Revert "add ubuntu and centos default ls aliases to magic_commands"
This reverts commit 49c2701743.
2020-02-17 18:58:07 -08:00
Kelly Brazil
49c2701743 add ubuntu and centos default ls aliases to magic_commands 2020-02-17 18:55:03 -08:00
Kelly Brazil
d1a271b08e add new ls tests for recursive and multiple directories with glob 2020-02-17 18:33:55 -08:00
Kelly Brazil
7388ad19b9 bump to v1.8.0 2020-02-17 17:31:15 -08:00
Kelly Brazil
2e63cb5fad version bump ls to 1.1 2020-02-17 17:16:34 -08:00
Kelly Brazil
e7f14d02b1 update ls to allow multi directory (glob and -R). Adds 'parent' key if found 2020-02-17 17:14:27 -08:00
Kelly Brazil
873771d05a formatting 2020-02-17 09:16:32 -08:00
Kelly Brazil
d7de122e36 prettify link 2020-02-14 09:44:24 -08:00
Kelly Brazil
4ef0434f53 formatting update 2020-02-14 09:43:02 -08:00
Kelly Brazil
1aa2c99259 removed history from magic syntax 2020-02-13 22:10:22 -08:00
Kelly Brazil
c2450b27b0 Merge pull request #22 from kellyjonbrazil/dev
Dev 1.7.3
2020-02-13 21:26:18 -05:00
Kelly Brazil
14d6d8b84f version bump to 1.7.3 2020-02-13 18:24:53 -08:00
Kelly Brazil
f0e3846c03 formatting 2020-02-13 18:20:22 -08:00
Kelly Brazil
6ba64f1128 usage update 2020-02-13 18:19:19 -08:00
Kelly Brazil
13bcdbc6c9 doc update 2020-02-13 17:50:51 -08:00
Kelly Brazil
cfba62db20 correct parser search in magic() 2020-02-13 17:48:21 -08:00
Kelly Brazil
18fb69e36e docs/parsers link 2020-02-13 17:29:45 -08:00
Kelly Brazil
474eb0f3fd doc updates 2020-02-13 17:24:10 -08:00
Kelly Brazil
7f47b53370 add alternate magic syntax 2020-02-13 17:20:00 -08:00
Kelly Brazil
dc2907d3ce doc update 2020-02-13 16:58:25 -08:00
Kelly Brazil
1af85811e0 remove magic_command info 2020-02-13 16:57:57 -08:00
Kelly Brazil
1c1b19a478 doc update 2020-02-13 16:57:30 -08:00
Kelly Brazil
66942d64ba changelog update 2020-02-13 16:56:48 -08:00
Kelly Brazil
2fb6ae08d7 fix shlex usage 2020-02-13 12:17:41 -08:00
Kelly Brazil
bf8811e03e add comments 2020-02-13 10:25:41 -05:00
Kelly Brazil
c8b502c571 remove unnecessary join and add comments 2020-02-13 10:14:32 -05:00
Kelly Brazil
81c11a975c added docstrings 2020-02-13 10:08:43 -05:00
Kelly Brazil
0d370eb403 doc update 2020-02-13 10:03:11 -05:00
Kelly Brazil
7492c3f1e3 changelog update 2020-02-13 09:48:42 -05:00
Kelly Brazil
515a8a84b7 add "command" to description 2020-02-13 09:47:40 -05:00
Kelly Brazil
dd6680efb2 allow condensed options (-prdq is equivalent to -p -r -d -q) 2020-02-13 09:47:16 -05:00
Kelly Brazil
a7158373cd comment update 2020-02-12 00:16:17 -05:00
Kelly Brazil
6d50ec7199 add try/except to fix bare jc command condition 2020-02-12 00:11:48 -05:00
Kelly Brazil
95dbf98e8e allow options in magic syntax 2020-02-11 19:14:51 -08:00
Kelly Brazil
d49323e4eb add magic_commands list to info 2020-02-11 18:09:21 -08:00
Kelly Brazil
08c1e2aec9 add magic syntax 2020-02-11 18:08:59 -08:00
Kelly Brazil
a2c137df2e better magic command syntax logic using introspection information from parser modules 2020-02-11 18:08:37 -08:00
Kelly Brazil
fe27dcdb8f proof of concept for magic syntax (e.g. jc ls -al) 2020-02-11 12:16:23 -08:00
Kelly Brazil
028e136161 bump to 1.7.2: add test fixtures to package 2020-02-08 12:46:42 -08:00
Kelly Brazil
9a85a0a4d5 fix doc 2020-02-08 12:46:14 -08:00
Kelly Brazil
3a1cbc4d50 move info class to top 2020-02-05 22:26:47 -08:00
Kelly Brazil
77d334f7f3 Merge pull request #19 from kellyjonbrazil/dev-1.7.1
Dev v1.7.1
2020-02-05 16:59:52 -08:00
Kelly Brazil
53cdf863ac changelog update 2020-02-05 16:53:17 -08:00
Kelly Brazil
7b7e7fe0fe changelog update 2020-02-05 16:50:55 -08:00
Kelly Brazil
0c03132847 fix error codes using sys.exit() 2020-02-05 16:18:58 -08:00
Kelly Brazil
3b81f7e2a1 exit code on ctrl-c exit 2020-02-05 16:12:09 -08:00
Kelly Brazil
3d76437b43 doc fix 2020-02-05 16:00:23 -08:00
Kelly Brazil
4bc54c78ce fix compatibility list 2020-02-05 16:00:10 -08:00
Kelly Brazil
3d303a96b9 crontab bug fix and tests 2020-02-05 15:52:39 -08:00
Kelly Brazil
33c99d031d fix line clobbering bug 2020-02-05 15:12:59 -08:00
Kelly Brazil
caf7e9f69a fix line clobbering bug and add user field to shortcuts 2020-02-05 15:11:51 -08:00
Kelly Brazil
9449f1f5d5 crontab bugfix: inserting header row was clobbering the first data row 2020-02-05 14:44:49 -08:00
Kelly Brazil
6bad164b5e simplify by removing unnecessary getattr calls 2020-02-05 14:10:22 -08:00
Kelly Brazil
bb5ba7ddb1 add indent variable to helptext 2020-02-05 13:57:34 -08:00
Kelly Brazil
8b2e01d540 doc update 2020-02-05 13:50:12 -08:00
Kelly Brazil
ff1159b1de exit codes on error 2020-02-05 11:45:17 -08:00
Kelly Brazil
a2fd3202a0 description formatting change 2020-02-05 11:34:33 -08:00
Kelly Brazil
7b53715b91 change description 2020-02-05 11:08:58 -08:00
Kelly Brazil
e05fc0a510 change padding of helptext 2020-02-05 11:08:47 -08:00
Kelly Brazil
43604c33f6 doc update 2020-02-05 10:59:51 -08:00
Kelly Brazil
eb67c484ff add crontab-u to parsers list 2020-02-05 10:58:26 -08:00
Kelly Brazil
a7b7bdd467 load parser modules 'just in time' so we don't need to load all modules at startup 2020-02-05 10:55:08 -08:00
Kelly Brazil
ab06989a18 description updates 2020-02-04 21:46:52 -08:00
Kelly Brazil
657b722f94 ini to INI 2020-02-04 21:44:10 -08:00
Kelly Brazil
dd2aecad27 description update 2020-02-04 21:37:07 -08:00
Kelly Brazil
c82c5c5c64 changelog update 2020-02-04 21:34:57 -08:00
Kelly Brazil
a1761cd68f id tests 2020-02-04 21:25:33 -08:00
Kelly Brazil
d618a7f583 doc update 2020-02-04 21:17:03 -08:00
Kelly Brazil
831a42f660 id formatting 2020-02-04 21:12:32 -08:00
Kelly Brazil
3b36022e5a add id parser 2020-02-04 21:09:42 -08:00
Kelly Brazil
d01dfa25f1 changelog updates 2020-02-04 15:22:36 -08:00
Kelly Brazil
395a99037b crontab-u and history doc updates 2020-02-04 14:36:03 -08:00
Kelly Brazil
025986c51d change history 'line' to integer 2020-02-04 14:31:28 -08:00
Kelly Brazil
c56b83093f doc update 2020-02-04 14:19:33 -08:00
Kelly Brazil
7c712a4133 doc update 2020-02-04 14:18:14 -08:00
Kelly Brazil
9a0cfe6dfa minor formatting 2020-02-04 14:18:01 -08:00
Kelly Brazil
a116cdbcec tests for crontab-u 2020-02-04 14:11:34 -08:00
Kelly Brazil
f2d616c98e add crontab with user parser 2020-02-04 14:02:27 -08:00
Kelly Brazil
42cbd1777d add xml and yaml tests 2020-02-04 13:53:45 -08:00
Kelly Brazil
ebf375aac0 add ini tests 2020-02-04 12:18:31 -08:00
Kelly Brazil
1f9050267e add ini, xml, and yaml test files 2020-02-04 12:02:18 -08:00
Kelly Brazil
d7f9707a15 minor formatting 2020-02-04 11:18:32 -08:00
Kelly Brazil
ab589ee3ed add __version__ variable 2020-02-04 11:18:15 -08:00
Kelly Brazil
c84ec0361f xml example update 2020-02-03 22:25:30 -08:00
Kelly Brazil
47d2f8968a doc update 2020-02-03 22:21:40 -08:00
Kelly Brazil
019c480bcc update acknowledgments 2020-02-03 22:17:13 -08:00
Kelly Brazil
547c6d3d59 add xml parser 2020-02-03 22:13:06 -08:00
Kelly Brazil
b5ebf8b76a add ruamel.yaml ack 2020-02-03 21:41:53 -08:00
Kelly Brazil
c690e328f2 add examples 2020-02-03 21:38:21 -08:00
Kelly Brazil
cbb92c1a95 add ini and yaml 2020-02-03 21:38:08 -08:00
Kelly Brazil
beb41997c9 doc update 2020-02-03 21:28:11 -08:00
Kelly Brazil
755a6faf11 clean up multi-document support 2020-02-03 21:22:30 -08:00
Kelly Brazil
021f8350a3 update doc 2020-02-03 19:11:36 -08:00
Kelly Brazil
76583dcd2f add ini file parser 2020-02-03 19:07:31 -08:00
Kelly Brazil
bf033239a7 doc update 2020-02-03 16:20:38 -08:00
Kelly Brazil
eb37fccd37 doc update 2020-02-03 16:17:29 -08:00
Kelly Brazil
d04ad45331 setup for 1.7.1 2020-02-03 16:12:45 -08:00
Kelly Brazil
db157b8ca7 add yaml file parser 2020-02-03 16:12:32 -08:00
Kelly Brazil
68f277bb20 add __version__ 2020-02-03 16:11:58 -08:00
Kelly Brazil
4de8f42664 Merge pull request #17 from kellyjonbrazil/dev
Dev v1.6.1
2019-12-17 12:11:13 -08:00
Kelly Brazil
4f11855935 update version info 2019-12-17 12:09:24 -08:00
Kelly Brazil
2b9a5fcc32 update version 2019-12-17 12:05:40 -08:00
Kelly Brazil
224948d1f2 pip list and pip show tests 2019-12-17 11:44:43 -08:00
Kelly Brazil
36f2812d5a add support for legacy output 2019-12-17 10:58:00 -08:00
Kelly Brazil
be06aa2b31 update parse() Return info 2019-12-17 10:09:19 -08:00
Kelly Brazil
41f8e3aba2 update Return info 2019-12-17 09:56:09 -08:00
Kelly Brazil
093c0df897 schema info 2019-12-17 09:38:50 -08:00
Kelly Brazil
37afc7dc8a updte todo and compatibility 2019-12-17 09:35:27 -08:00
Kelly Brazil
efbf354960 doc update for pip show 2019-12-17 09:24:08 -08:00
Kelly Brazil
5e39fe0d80 pip show parser working 2019-12-17 09:20:26 -08:00
Kelly Brazil
47328dc659 add pip-show parser 2019-12-16 19:09:14 -08:00
Kelly Brazil
addeef50ba initial pip show parser add 2019-12-16 19:07:51 -08:00
Kelly Brazil
ad338cc5b5 schema doc update 2019-12-16 18:58:33 -08:00
Kelly Brazil
202bc8201e doc update 2019-12-16 18:54:19 -08:00
Kelly Brazil
5ff99de405 add argument to parser info 2019-12-16 18:40:08 -08:00
Kelly Brazil
86ebe2cf9c initial add of pip list parser 2019-12-16 18:36:13 -08:00
Kelly Brazil
facf0b399c add osx to campatible 2019-12-16 18:09:29 -08:00
Kelly Brazil
33db7b0bcb add crontab tests 2019-12-16 18:09:00 -08:00
Kelly Brazil
663d07bca1 add crontab 2019-12-16 17:52:09 -08:00
Kelly Brazil
ba04e4997f update docs 2019-12-16 17:51:11 -08:00
Kelly Brazil
c4fee1b658 add crontab parser 2019-12-16 17:50:52 -08:00
Kelly Brazil
99b92a15bb support shortcut schedules 2019-12-16 17:45:34 -08:00
Kelly Brazil
b076ab5b57 initial crontab parser 2019-12-16 17:01:53 -08:00
Kelly Brazil
687759f75d alphabetize du entry 2019-12-16 14:31:21 -08:00
Kelly Brazil
9eaac7f3af add du 2019-12-16 14:30:06 -08:00
Kelly Brazil
4c24e00cfc add osx-11 and ubuntu tests 2019-12-16 14:27:55 -08:00
Kelly Brazil
beb17011b0 du tests and docs 2019-12-16 13:57:42 -08:00
Kelly Brazil
e882bf55bc initial add du parser 2019-12-16 13:52:42 -08:00
Kelly Brazil
3a3016adb6 add parser_count to about 2019-12-16 11:52:18 -08:00
Kelly Brazil
1e8b68153a add osx uname tests 2019-12-16 11:12:45 -08:00
Kelly Brazil
9335cf65fb add uname osx support 2019-12-16 11:02:02 -08:00
Kelly Brazil
83f35256ae add OSX support 2019-12-16 11:01:43 -08:00
Kelly Brazil
4283333948 version bump 2019-12-16 10:03:47 -08:00
Kelly Brazil
b8f902796b shorten changelog 2019-12-16 10:03:34 -08:00
Kelly Brazil
8f99ab295c info update 2019-12-16 09:08:47 -08:00
Kelly Brazil
882310e268 add name to about parser info 2019-12-16 09:04:52 -08:00
Kelly Brazil
56bce95214 about code cleanup 2019-12-16 09:00:16 -08:00
Kelly Brazil
c13ecbec29 clean up parser info 2019-12-16 08:59:41 -08:00
Kelly Brazil
0ffaaa6e73 clean up about code 2019-12-16 08:18:37 -08:00
Kelly Brazil
75eff3adea remove whitespace 2019-12-14 23:56:40 -08:00
Kelly Brazil
bf5f80476c use real parser name in error message 2019-12-14 23:56:22 -08:00
Kelly Brazil
9aaf0fbb2f doc updates 2019-12-14 23:35:42 -08:00
Kelly Brazil
8f01ef7953 add -a option info 2019-12-14 23:27:56 -08:00
Kelly Brazil
da1d087452 add parser version info 2019-12-14 23:21:47 -08:00
Kelly Brazil
e16bc7e882 add about information to parsers 2019-12-14 23:15:15 -08:00
Kelly Brazil
fe9bdd4811 add info class 2019-12-13 20:01:51 -08:00
Kelly Brazil
17b6f3f6d6 add osx tests 2019-12-13 14:36:21 -08:00
Kelly Brazil
90a6baf0ee add osx tests 2019-12-13 14:30:12 -08:00
Kelly Brazil
f0e73d0e72 add osx tests 2019-12-13 10:50:01 -08:00
Kelly Brazil
a762882f1c fixture updates 2019-12-13 08:58:23 -08:00
Kelly Brazil
4c1bc59236 doc updates 2019-12-12 17:05:40 -08:00
Kelly Brazil
f2962083f8 add osx support for mount parser 2019-12-12 17:04:40 -08:00
Kelly Brazil
a0b22a5bcf help text formatting 2019-12-12 16:14:46 -08:00
Kelly Brazil
dcf393354c doc fix 2019-12-12 16:10:30 -08:00
Kelly Brazil
5f771656e3 use universal parser 2019-12-12 16:07:52 -08:00
Kelly Brazil
f376aab793 doc update 2019-12-12 15:59:36 -08:00
Kelly Brazil
3c96464217 osx fixes and tests 2019-12-12 15:59:24 -08:00
Kelly Brazil
c9892833a1 formatting change 2019-12-12 15:58:40 -08:00
Kelly Brazil
127c98affc changelog update 2019-12-12 15:58:24 -08:00
Kelly Brazil
8687a772f5 use universal parser 2019-12-12 15:33:34 -08:00
Kelly Brazil
b1162b14d4 use universal parser 2019-12-12 15:22:21 -08:00
Kelly Brazil
8a8ee35707 use universal parser 2019-12-12 15:01:42 -08:00
Kelly Brazil
5e109a3665 add du 2019-12-12 14:12:36 -08:00
Kelly Brazil
11db478430 update changelog 2019-12-12 14:12:21 -08:00
Kelly Brazil
a85377014d use universal parser 2019-12-12 14:11:59 -08:00
Kelly Brazil
3aea86234d fix osx-10.11.6 tests 2019-12-12 11:23:49 -08:00
Kelly Brazil
916ec6ed6b fix osx ls tests 2019-12-12 10:11:24 -08:00
Kelly Brazil
9dca6ba539 doc formatting change 2019-12-12 09:47:14 -08:00
Kelly Brazil
0ebb89f561 doc update 2019-12-12 09:41:56 -08:00
Kelly Brazil
e237867e24 doc formatting 2019-12-12 09:41:25 -08:00
Kelly Brazil
78fa44fd9a add compatibility to docs 2019-12-12 09:35:42 -08:00
Kelly Brazil
d615fa3b93 add compatibility to docs 2019-12-12 09:21:20 -08:00
Kelly Brazil
ce134dc332 Add OSX tests for ls 2019-12-12 09:09:57 -08:00
Kelly Brazil
a56e4dc752 use universal simple table parser 2019-12-11 17:27:48 -08:00
Kelly Brazil
d221b4aa29 changelog update 2019-12-11 17:19:38 -08:00
Kelly Brazil
d2cba6ad2f add compatibility info 2019-12-11 17:18:21 -08:00
Kelly Brazil
84b3c30b52 add osx tests 2019-12-11 17:18:04 -08:00
Kelly Brazil
68eeec19a8 doc update 2019-12-11 16:39:30 -08:00
Kelly Brazil
c6d1528a2e use _ instead of - 2019-12-11 16:37:13 -08:00
Kelly Brazil
50a6b256b8 new universal parsers to limit code duplication 2019-12-09 14:01:47 -08:00
Kelly Brazil
bbba1fe477 update df to use universal sparse table parser for osx compatibility 2019-12-09 14:01:29 -08:00
Kelly Brazil
46b827da6b add osx compatibility 2019-12-06 13:22:51 -08:00
Kelly Brazil
5e8c28a30a comment fix 2019-12-06 11:47:42 -08:00
Kelly Brazil
e5d3903164 update ifconfig doc 2019-12-06 11:46:09 -08:00
Kelly Brazil
23975c9c9e fixup osx subnet mask and convert state to an array 2019-12-06 11:44:57 -08:00
Kelly Brazil
1e0dab8355 ifconfig fixture updates 2019-12-06 10:53:49 -08:00
Kelly Brazil
5f4c10ffd5 doc update 2019-12-06 10:39:11 -08:00
Kelly Brazil
6f3d2b4b56 require ifconfig-parser v0.0.5 for mac and bytes support 2019-12-06 10:30:01 -08:00
Kelly Brazil
fea8ace844 add OSX compatibility 2019-12-06 10:27:11 -08:00
Kelly Brazil
6633d9262c Set theme jekyll-theme-cayman 2019-11-30 13:52:24 -08:00
Kelly Brazil
7d54137140 link update 2019-11-28 11:51:54 -08:00
Kelly Brazil
2fcda6f248 add motivation to readme 2019-11-25 18:34:21 -08:00
Kelly Brazil
9c1b8bacf9 Merge pull request #16 from kellyjonbrazil/dev
Dev v1.5.1
2019-11-17 11:55:06 -08:00
Kelly Brazil
4867655eb2 add line-numbers tests 2019-11-17 11:49:36 -08:00
Kelly Brazil
47410d1a95 version bump 2019-11-17 11:05:46 -08:00
Kelly Brazil
5fa49f5e67 changelog update 2019-11-17 11:00:16 -08:00
Kelly Brazil
36c53827fa add systemctl tests 2019-11-17 10:56:55 -08:00
Kelly Brazil
51631aef5b add systemctl tests 2019-11-17 10:31:58 -08:00
Kelly Brazil
a0298ac8a3 add fstab tests 2019-11-17 10:26:48 -08:00
Kelly Brazil
98c0188821 formatting fix 2019-11-15 19:27:51 -08:00
Kelly Brazil
ab1dabe3e4 doc update 2019-11-15 19:26:22 -08:00
Kelly Brazil
94bdb11fdf remove systemctl from TODO 2019-11-15 19:24:32 -08:00
Kelly Brazil
b6727d68ba add systemctl parsers 2019-11-15 19:18:31 -08:00
Kelly Brazil
89bad7fc2b remove systemctl list-machines parser 2019-11-15 19:13:53 -08:00
Kelly Brazil
c0b8b810a2 add systemctl list parsers 2019-11-15 19:07:42 -08:00
Kelly Brazil
31eb65acd1 doc fix 2019-11-15 19:05:49 -08:00
Kelly Brazil
513bbeb464 add break on footer condition 2019-11-15 19:02:57 -08:00
Kelly Brazil
3a52fb725a add systemctl list-jobs parser 2019-11-15 18:58:17 -08:00
Kelly Brazil
5affd44499 add systemctl_lj, lm, ls, and luf 2019-11-15 18:36:12 -08:00
Kelly Brazil
5dbc6e806c add systemctl_luf parser 2019-11-15 12:28:28 -08:00
Kelly Brazil
59ae31f3f3 add systemctl parser 2019-11-15 11:58:17 -08:00
Kelly Brazil
230e921c2e remove fstab from TODO 2019-11-15 10:36:58 -08:00
Kelly Brazil
a7c3d88b08 update example and docs 2019-11-15 10:01:29 -08:00
Kelly Brazil
9b453bcb84 remove commented code block 2019-11-15 09:57:25 -08:00
Kelly Brazil
ce43c782f6 fstab update 2019-11-15 09:32:12 -08:00
Kelly Brazil
cb16faaf4d helptext update 2019-11-15 09:31:28 -08:00
Kelly Brazil
3f1d3ff6d8 add examples 2019-11-15 09:29:54 -08:00
Kelly Brazil
6f67eecd5e add fstab parser 2019-11-15 09:22:07 -08:00
Kelly Brazil
e75c819190 changelog update 2019-11-15 08:51:53 -08:00
Kelly Brazil
601e68d104 doc update 2019-11-15 08:40:13 -08:00
Kelly Brazil
8285ecfd1e enhance test file with comments 2019-11-15 08:40:01 -08:00
Kelly Brazil
8726de902e add hosts parser 2019-11-14 22:04:59 -08:00
Kelly Brazil
4133585274 add hosts tests 2019-11-14 22:04:48 -08:00
Kelly Brazil
ad913b1417 add hosts docs 2019-11-14 21:59:06 -08:00
Kelly Brazil
7113e5a844 filter out comments at the end of the line 2019-11-14 21:55:08 -08:00
Kelly Brazil
a3a8369dc0 add docs 2019-11-14 21:36:02 -08:00
Kelly Brazil
64016b8ef0 add hosts parser 2019-11-14 21:31:25 -08:00
Kelly Brazil
1cb49d60c8 remove sar and sadf 2019-11-14 21:21:15 -08:00
Kelly Brazil
c858adfd12 remove stat from todo 2019-11-14 21:11:05 -08:00
Kelly Brazil
08d68327c7 add stat tests 2019-11-14 21:08:09 -08:00
Kelly Brazil
0d7c6c5664 doc fix and add continue lines 2019-11-14 20:57:49 -08:00
Kelly Brazil
8bfa41dbf4 change values to null if - 2019-11-14 17:36:29 -08:00
Kelly Brazil
7e2fa48ed4 update changelog 2019-11-14 17:24:51 -08:00
Kelly Brazil
340635cad5 fix stats doc 2019-11-14 17:23:44 -08:00
Kelly Brazil
8f77d1de09 add stat docs 2019-11-14 17:21:56 -08:00
Kelly Brazil
7dcf1b25ff add link_to field 2019-11-14 17:20:13 -08:00
Kelly Brazil
9b73538106 set compatibility to linux only 2019-11-14 16:44:12 -08:00
Kelly Brazil
3bf8c8c6db pep8 fixes 2019-11-14 16:40:52 -08:00
Kelly Brazil
04a1ff2ca7 pep8 fixes 2019-11-14 16:36:00 -08:00
Kelly Brazil
64647d230a pep8 cleanup 2019-11-14 16:32:11 -08:00
Kelly Brazil
c2a67e1b70 add stat parser 2019-11-14 16:31:52 -08:00
Kelly Brazil
edb9a7c76e add stat parser 2019-11-14 15:26:36 -08:00
Kelly Brazil
a407f5b678 minor update 2019-11-14 14:01:04 -08:00
Kelly Brazil
e5b4987acb doc update 2019-11-14 14:00:06 -08:00
Kelly Brazil
ba8cc18eeb add ss tests 2019-11-14 13:56:09 -08:00
Kelly Brazil
d2c7316e00 update command options info 2019-11-14 13:43:07 -08:00
Kelly Brazil
609aa14d24 spelling fix 2019-11-14 13:38:52 -08:00
Kelly Brazil
ef1ad4c700 doc update 2019-11-14 13:37:55 -08:00
Kelly Brazil
a0e2732152 add ss example 2019-11-14 09:46:10 -08:00
Kelly Brazil
9b5d3e3be1 update doc 2019-11-14 09:42:44 -08:00
Kelly Brazil
2663ef31fb fix field names per ss documentation 2019-11-14 09:38:19 -08:00
Kelly Brazil
a4cdd3378e add compatibility info 2019-11-13 08:17:41 -08:00
Kelly Brazil
2f805da24d add colon to parameter in docs 2019-11-13 08:04:40 -08:00
Kelly Brazil
79152a946d initialize network_list and socket_list variables 2019-11-13 07:46:14 -08:00
Kelly Brazil
de37bb37d0 add ss docs 2019-11-13 07:45:37 -08:00
Kelly Brazil
f783e44e5c doc fix 2019-11-12 18:58:58 -08:00
Kelly Brazil
af82f2c991 update raw format note 2019-11-12 18:56:42 -08:00
Kelly Brazil
46774daf9d doc update 2019-11-12 18:51:21 -08:00
Kelly Brazil
648306b785 process ss data 2019-11-12 18:04:40 -08:00
Kelly Brazil
b7a4f205b8 parser fixes 2019-11-12 17:10:06 -08:00
Kelly Brazil
fdb168b43a add ss parser 2019-11-12 16:34:42 -08:00
Kelly Brazil
b6f65c93c4 ps doc update 2019-11-12 15:05:21 -08:00
Kelly Brazil
3f4838f17a remove cli.md 2019-11-12 14:22:49 -08:00
Kelly Brazil
eef0dee2aa doc update 2019-11-12 14:20:59 -08:00
Kelly Brazil
e17388d3b2 doc update 2019-11-12 14:19:40 -08:00
Kelly Brazil
7e6a1bc719 doc update 2019-11-12 14:15:22 -08:00
Kelly Brazil
37738a2ea2 update contributions 2019-11-12 14:10:26 -08:00
Kelly Brazil
c5834a57db add todo section 2019-11-12 13:35:32 -08:00
Kelly Brazil
91b9373f38 new examples 2019-11-12 13:05:19 -08:00
Kelly Brazil
ce0bb5b816 formatting fix 2019-11-12 11:52:16 -08:00
Kelly Brazil
f330ff0eff wrap example text 2019-11-12 11:49:14 -08:00
Kelly Brazil
4b02700414 update simple examples 2019-11-12 11:46:52 -08:00
Kelly Brazil
ee30180376 fix note 2019-11-12 11:39:33 -08:00
Kelly Brazil
338e0ff15c add schema note 2019-11-12 11:38:50 -08:00
Kelly Brazil
3ac75305df update process() doc 2019-11-12 11:28:10 -08:00
Kelly Brazil
3bdcf44afb doc update 2019-11-12 11:22:17 -08:00
Kelly Brazil
e3f4ffede5 doc update 2019-11-12 11:18:00 -08:00
Kelly Brazil
f0c8725d43 doc update 2019-11-12 11:17:33 -08:00
Kelly Brazil
5473bc4eb6 doc update 2019-11-12 11:12:41 -08:00
Kelly Brazil
b9bd9422bf doc update 2019-11-12 07:19:01 -08:00
Kelly Brazil
cb5729a070 add options to docs 2019-11-12 07:18:27 -08:00
Kelly Brazil
f0b1ab4233 doc update 2019-11-12 07:08:35 -08:00
Kelly Brazil
b15386e849 doc update 2019-11-12 07:07:43 -08:00
Kelly Brazil
d2a2c8da35 doc updates 2019-11-12 07:03:02 -08:00
Kelly Brazil
7251548cbb documentation updates 2019-11-12 07:01:36 -08:00
Kelly Brazil
146e29f7cb update docs 2019-11-11 18:30:46 -08:00
Kelly Brazil
363fd3eab4 move parser_name to except block 2019-11-11 16:27:28 -08:00
Kelly Brazil
4083dd4260 add -d option 2019-11-11 16:16:41 -08:00
Kelly Brazil
b2b74547ba add netstat-sudo-aeep tests 2019-11-11 15:53:42 -08:00
Kelly Brazil
dddb0baabf use \u2063 instead of \u2026 2019-11-11 15:53:22 -08:00
Kelly Brazil
84b4f67ef9 new json output 2019-11-11 14:34:36 -08:00
Kelly Brazil
3a089138b8 add int and float changes 2019-11-11 14:31:27 -08:00
Kelly Brazil
3ff0305c8e add lsblk tests 2019-11-11 13:00:17 -08:00
Kelly Brazil
761edc3c6c remove unused parse_pairs function 2019-11-11 12:43:27 -08:00
Kelly Brazil
3351c81f64 add documentation 2019-11-11 12:40:16 -08:00
Kelly Brazil
3dfc6f67d7 change empty values to Null 2019-11-11 12:00:23 -08:00
Kelly Brazil
1546ec3bd1 fixes for right justified columns 2019-11-11 11:53:16 -08:00
Kelly Brazil
2a953011f7 rewrite of lsblk parser to use a custom delimiter 2019-11-10 15:18:53 -08:00
Kelly Brazil
d2f755de9d updates tests 2019-11-08 17:08:41 -08:00
Kelly Brazil
f363334639 update tests 2019-11-08 16:21:09 -08:00
Kelly Brazil
750197e485 new tests 2019-11-08 16:04:19 -08:00
Kelly Brazil
36b349e4ed json output files 2019-11-08 16:03:41 -08:00
Kelly Brazil
b5f1e94fe2 fix for space before '-' in program_name 2019-11-08 16:03:14 -08:00
Kelly Brazil
6a504fb0e1 add exception type 2019-11-08 16:02:44 -08:00
Kelly Brazil
e02bad2240 update documentation 2019-11-08 12:22:41 -08:00
Kelly Brazil
1d4043a3b6 add template parser 2019-11-08 12:14:09 -08:00
Kelly Brazil
039e034829 fix parsing issues in program_name when spaces are in the name 2019-11-08 11:47:58 -08:00
Kelly Brazil
d828de4f4f update documentation 2019-11-08 09:07:05 -08:00
Kelly Brazil
098000bb10 fix blank 'from' column issue 2019-11-08 09:04:03 -08:00
Kelly Brazil
b41165eff5 process w data 2019-11-07 19:13:15 -08:00
Kelly Brazil
6ad7891b2b process uptime data 2019-11-07 18:54:52 -08:00
Kelly Brazil
7213831559 add process boilerplate 2019-11-07 18:47:01 -08:00
Kelly Brazil
10eedd82e4 changelog update 2019-11-07 18:34:06 -08:00
Kelly Brazil
a55493da0f process route data 2019-11-07 18:33:51 -08:00
Kelly Brazil
89973f4162 doc updates and tty fix 2019-11-07 15:33:12 -08:00
Kelly Brazil
4802222ad5 process ps data 2019-11-07 15:24:03 -08:00
Kelly Brazil
bcd28f06f8 prep ps for process 2019-11-07 15:09:57 -08:00
Kelly Brazil
e17a47a7fa fix typo 2019-11-07 14:51:05 -08:00
Kelly Brazil
cad2e16c7a document examples 2019-11-07 14:49:21 -08:00
Kelly Brazil
5da5d278da process netstat data 2019-11-07 14:43:42 -08:00
Kelly Brazil
81b6776e57 remove old netstat parser 2019-11-07 13:58:55 -08:00
Kelly Brazil
5ecb6bd58b doc updates 2019-11-07 13:58:37 -08:00
Kelly Brazil
21b56096c5 finalize parse_post 2019-11-07 13:53:23 -08:00
Kelly Brazil
8c78f95973 clean up trailing spaces on entries 2019-11-07 12:13:25 -08:00
Kelly Brazil
94a88bb566 post_parse flags and program_name 2019-11-07 10:52:02 -08:00
Kelly Brazil
579124475b simplify parser_map code 2019-11-07 09:02:27 -08:00
Kelly Brazil
5da83e0200 fix found variable error 2019-11-07 08:23:11 -08:00
Kelly Brazil
a90a76d004 move out old netstat parser 2019-11-07 08:15:19 -08:00
Kelly Brazil
bdfa959123 fix compatibility code 2019-11-07 08:07:43 -08:00
Kelly Brazil
4380594275 remove cli functions from utils 2019-11-07 08:04:32 -08:00
Kelly Brazil
88bf252c0d rename jc.py to cli.py 2019-11-07 08:04:07 -08:00
Kelly Brazil
a5efd8adce rename jc.py to cli.py 2019-11-07 08:03:45 -08:00
Kelly Brazil
2ee392eeff add quiet mode 2019-11-06 21:09:09 -08:00
Kelly Brazil
9c1d893e16 move utils to own module and add quiet mode 2019-11-06 21:07:25 -08:00
Kelly Brazil
88dcb90c83 changelog update 2019-11-06 21:05:25 -08:00
Kelly Brazil
a3bcabc89c mvp of netstat raw_data parser 2019-11-06 20:35:10 -08:00
Kelly Brazil
dafbf9fdcf process lsmod data 2019-11-06 19:17:01 -08:00
Kelly Brazil
680cb2b2ca doc update 2019-11-06 09:56:59 -06:00
Kelly Brazil
54818a06e0 change bool variable names 2019-11-06 09:21:55 -06:00
Kelly Brazil
88f4c5b5a9 remove TypeError from exception check 2019-11-06 08:47:54 -06:00
Kelly Brazil
2bb7409887 process lsblk data 2019-11-05 23:10:49 -06:00
Kelly Brazil
c780aac3ab add compatibility function 2019-11-05 22:42:48 -06:00
Kelly Brazil
5010aaec28 put exit() back 2019-11-05 17:25:20 -06:00
Kelly Brazil
066e93cb07 move exit() to errormessage() 2019-11-05 17:23:46 -06:00
Kelly Brazil
0bd2faa7f7 beautify compatibility list 2019-11-05 17:17:07 -06:00
Kelly Brazil
e2f926453b add install script 2019-11-05 17:08:41 -06:00
Kelly Brazil
b953b79f9c add compatibility 2019-11-05 17:04:18 -06:00
Kelly Brazil
7f99677806 compatibility function call 2019-11-05 17:00:36 -06:00
Kelly Brazil
721b546659 finish schema 2019-11-05 15:14:52 -06:00
Kelly Brazil
2de5e41269 fix for more columns and build schema 2019-11-05 15:07:40 -06:00
Kelly Brazil
dfe0f6e99b process ls data 2019-11-05 08:30:32 -08:00
Kelly Brazil
8873b1bc69 clean up process code 2019-11-05 08:07:39 -08:00
Kelly Brazil
9ff9470700 refactor helptext() function 2019-11-05 07:21:58 -08:00
Kelly Brazil
2c58fca530 process jobs data 2019-11-04 17:07:11 -08:00
Kelly Brazil
9e5cd90da7 process iptables data 2019-11-04 16:59:14 -08:00
Kelly Brazil
7ee0d49424 process ifconfig data 2019-11-04 15:54:34 -08:00
Kelly Brazil
a9058ee21e doc formatting 2019-11-04 15:19:50 -08:00
Kelly Brazil
fcf0aac87d add history processing 2019-11-04 15:19:35 -08:00
Kelly Brazil
daec5f0681 process free data 2019-11-04 15:11:18 -08:00
Kelly Brazil
5b2491d5ae process env data 2019-11-04 15:03:16 -08:00
Kelly Brazil
d9b41ac73b doc formatting 2019-11-04 13:52:45 -08:00
Kelly Brazil
7168ffddf8 process dig output 2019-11-04 13:47:27 -08:00
Kelly Brazil
a855344bec document schema 2019-11-04 13:05:56 -08:00
Kelly Brazil
d8b3b59fae add schema and rename 'avail' to 'available' 2019-11-04 13:02:54 -08:00
Kelly Brazil
4b7d7840d3 add -r option 2019-11-04 12:50:37 -08:00
Kelly Brazil
58a094a9b4 changelog update 2019-11-04 12:40:19 -08:00
Kelly Brazil
65adbb4189 doc update 2019-11-04 12:40:05 -08:00
Kelly Brazil
f7350959c9 df fix for changing header names when -h used 2019-11-04 12:39:43 -08:00
Kelly Brazil
8934a7d832 fix dictionary iteration 2019-11-04 11:10:58 -08:00
Kelly Brazil
669a424fd6 fix process function 2019-11-04 11:02:02 -08:00
Kelly Brazil
591a65c2bd process df data 2019-11-04 10:56:33 -08:00
Kelly Brazil
a78fb89078 add raw and processed output 2019-11-04 09:32:29 -08:00
Kelly Brazil
8979dab2a5 add raw mode 2019-11-04 09:32:09 -08:00
Kelly Brazil
0a891f0add bump python required version 2019-11-04 08:09:19 -08:00
Kelly Brazil
c220e35b14 cleanup helptext 2019-11-04 08:06:50 -08:00
Kelly Brazil
f26c5818bd refactor helptext 2019-11-04 07:57:47 -08:00
Kelly Brazil
e712cd3fc4 netstat2 skeleton 2019-11-01 22:29:08 -07:00
Kelly Brazil
0309c9ac67 setup cleanup 2019-11-01 08:55:52 -07:00
Kelly Brazil
9a9eb4120a setup updates 2019-11-01 08:53:53 -07:00
Kelly Brazil
d1927456b0 Merge pull request #6 from kellyjonbrazil/dev
Dev v1.1.1
2019-10-31 08:06:01 -07:00
Kelly Brazil
a3d9213a1e add date 2019-10-31 07:59:03 -07:00
Kelly Brazil
3365c03a1e add tests 2019-10-31 07:58:44 -07:00
Kelly Brazil
4f6c87389b add dig test files 2019-10-31 07:27:31 -07:00
Kelly Brazil
41a2a9adac remove unnecessary if statement 2019-10-31 07:27:12 -07:00
Kelly Brazil
74dae2905b dig parser mvp 2019-10-30 17:23:35 -07:00
Kelly Brazil
d1f64214de add authority parsing 2019-10-30 17:18:14 -07:00
Kelly Brazil
d3e1aa20a8 fix when line 2019-10-30 17:03:35 -07:00
Kelly Brazil
72cae95777 dig fixes 2019-10-30 16:59:56 -07:00
Kelly Brazil
219bc8130f dig parser skeleton 2019-10-30 15:36:13 -07:00
Kelly Brazil
e8c1a554c0 testfile updates 2019-10-30 13:52:53 -07:00
Kelly Brazil
087a60bc2a documentation updates 2019-10-30 13:52:31 -07:00
Kelly Brazil
9c9823c3b8 add arp testfiles 2019-10-30 13:29:06 -07:00
Kelly Brazil
cf8d13030b add arp 2019-10-30 13:22:12 -07:00
Kelly Brazil
1eff69c187 add documentation 2019-10-30 13:21:05 -07:00
Kelly Brazil
b10fb77d71 fixup arp parser 2019-10-30 13:12:53 -07:00
Kelly Brazil
87cee8b230 add arp parser 2019-10-30 13:00:05 -07:00
Kelly Brazil
83ab10d628 documentation update 2019-10-30 12:50:05 -07:00
Kelly Brazil
d58a6e1d1d readme update 2019-10-29 14:19:04 -07:00
Kelly Brazil
cb46ca5c27 readme update 2019-10-29 10:27:42 -07:00
Kelly Brazil
5528d979f0 version bump 2019-10-29 09:16:03 -07:00
Kelly Brazil
ee94a038a6 add tests 2019-10-29 08:58:52 -07:00
Kelly Brazil
1d658f7a9f add tests 2019-10-29 08:45:11 -07:00
Kelly Brazil
392cb44f9b initial add of tests and fixtures 2019-10-29 07:55:26 -07:00
Kelly Brazil
579bef079c move global output variable inside function 2019-10-29 07:54:59 -07:00
Kelly Brazil
0691cfcab3 changelog fix 2019-10-26 18:49:43 -07:00
Kelly Brazil
db29c7c186 documentation fixes 2019-10-26 18:49:13 -07:00
Kelly Brazil
fb1e036375 formatting 2019-10-25 20:27:03 -07:00
Kelly Brazil
c3eaf59836 Merge pull request #5 from kellyjonbrazil/dev
Dev v1.0.1
2019-10-25 19:43:24 -07:00
Kelly Brazil
c9849ce0db changelog update 2019-10-25 19:41:35 -07:00
Kelly Brazil
d3c89a3092 check for enough info to parse 2019-10-25 19:27:02 -07:00
Kelly Brazil
a3d43f27f7 fix odd uptime text parsing 2019-10-25 18:25:33 -07:00
Kelly Brazil
f4d9c1b699 fix uptime for minutes and hours long uptime 2019-10-25 17:16:02 -07:00
Kelly Brazil
de647bba4a documentation update 2019-10-25 16:14:32 -07:00
Kelly Brazil
d791307031 documentation update 2019-10-25 16:12:45 -07:00
Kelly Brazil
1a4fc204e2 Documentation update 2019-10-25 16:09:31 -07:00
Kelly Brazil
0328e14c7c handle ctrl-c gracefully 2019-10-25 16:05:34 -07:00
Kelly Brazil
1acc4d6c29 fix uptime parsing for short uptimes 2019-10-25 15:52:53 -07:00
Kelly Brazil
27245590ce remove integers 2019-10-25 15:40:53 -07:00
Kelly Brazil
7ca2a4bdb9 remove integer values 2019-10-25 15:39:48 -07:00
Kelly Brazil
5f1ec67348 lower() headers 2019-10-25 14:58:15 -07:00
Kelly Brazil
7e44c4278a formatting 2019-10-25 10:55:38 -07:00
Kelly Brazil
eda726c4a3 documentation update 2019-10-25 10:55:26 -07:00
Kelly Brazil
5f8e70d730 convert headers to lowercase 2019-10-25 10:55:09 -07:00
Kelly Brazil
25b90546c6 change 'Use%' to 'Use_percent' 2019-10-25 10:39:05 -07:00
Kelly Brazil
75c0841538 changelog update 2019-10-25 10:32:54 -07:00
Kelly Brazil
5b532b9b71 minor cleanup 2019-10-25 10:31:03 -07:00
Kelly Brazil
8c7b3193d1 documentation change 2019-10-25 10:28:19 -07:00
Kelly Brazil
0897c96ef3 formatting 2019-10-25 10:22:23 -07:00
Kelly Brazil
57d0ab2ed7 change LOGIN@ to LOGIN_AT 2019-10-25 10:22:10 -07:00
Kelly Brazil
a07d9a0e4b change SIZE/OFF key to SIZE_OFF 2019-10-25 10:04:29 -07:00
Kelly Brazil
b3996cb4df change MAJ:MIN key to MAJ_MIN 2019-10-25 09:54:42 -07:00
Kelly Brazil
4fa88c1ba3 clear out non-ascii chars from data 2019-10-25 09:53:44 -07:00
Kelly Brazil
c8c5564b29 change buff/cache key to buff_cache 2019-10-25 09:46:03 -07:00
Kelly Brazil
6d047486d9 doc fix 2019-10-24 17:53:56 -07:00
Kelly Brazil
42bdc05814 changelog fix 2019-10-24 17:41:51 -07:00
Kelly Brazil
85bfb68886 history parser fixes 2019-10-24 17:33:42 -07:00
Kelly Brazil
08ec21556b formatting 2019-10-24 17:12:27 -07:00
Kelly Brazil
320929bf25 documentation update 2019-10-24 17:11:17 -07:00
Kelly Brazil
41cd489c34 add history and uptime parsers 2019-10-24 17:09:32 -07:00
Kelly Brazil
f101d881a1 add w parser 2019-10-24 16:06:55 -07:00
Kelly Brazil
fa7466022b fix env parser 2019-10-24 15:54:31 -07:00
Kelly Brazil
ea0cf0acf2 documentation update 2019-10-24 09:48:35 -07:00
Kelly Brazil
e7921b65f5 Merge pull request #4 from kellyjonbrazil/dev
Dev v0.9.1
2019-10-23 18:41:55 -07:00
Kelly Brazil
2cc1b1bd54 version bump 2019-10-23 18:39:24 -07:00
Kelly Brazil
58ae976db0 documentation update 2019-10-23 18:30:55 -07:00
Kelly Brazil
66772392ae add lsmod parser 2019-10-23 18:04:54 -07:00
Kelly Brazil
29c47c03a6 documentation update 2019-10-23 17:37:25 -07:00
Kelly Brazil
91eb9a4d13 use None instead of -- 2019-10-23 17:27:23 -07:00
Kelly Brazil
a1a3de32ec add lsof parser 2019-10-23 17:22:25 -07:00
Kelly Brazil
9c47fd05bf doco fix 2019-10-23 14:11:13 -07:00
Kelly Brazil
649c0aa7c1 add documentation 2019-10-23 14:10:10 -07:00
Kelly Brazil
3db758764e add jobs parser 2019-10-23 14:05:47 -07:00
Kelly Brazil
802f1510eb tighten if statements 2019-10-23 10:27:05 -07:00
Kelly Brazil
56901788de stop blocking when no pipe and enhance help text 2019-10-23 09:51:29 -07:00
Kelly Brazil
679ae6d5dc version bump 2019-10-23 09:20:11 -07:00
Kelly Brazil
b15c8c352a simplify state variables 2019-10-23 08:46:54 -07:00
Kelly Brazil
393e8bc560 Merge pull request #3 from kellyjonbrazil/dev
Dev v0.8.1
2019-10-22 17:26:40 -07:00
Kelly Brazil
976fd7d9bd readme update 2019-10-22 17:24:56 -07:00
Kelly Brazil
d8337870ca update documentation 2019-10-22 17:21:00 -07:00
Kelly Brazil
39a8aec77f v0.8.1 build 2019-10-22 17:15:02 -07:00
Kelly Brazil
306d539b6b readme update 2019-10-22 16:50:01 -07:00
Kelly Brazil
f3087b8a8e update readme and formatting 2019-10-22 16:40:27 -07:00
Kelly Brazil
414c2ecef8 fix iptables parser 2019-10-22 16:32:55 -07:00
Kelly Brazil
776ef2d1be add iptables parser 2019-10-22 15:42:29 -07:00
Kelly Brazil
9ac5746996 add uname parser 2019-10-22 13:28:15 -07:00
Kelly Brazil
a3e55d97c0 add mount parser 2019-10-22 12:54:41 -07:00
Kelly Brazil
b15227e7ba add lsblk parser 2019-10-22 11:55:11 -07:00
Kelly Brazil
ec3d1f84ce fix free parser 2019-10-22 11:26:58 -07:00
Kelly Brazil
753d5fd9fe readme update 2019-10-22 11:17:21 -07:00
Kelly Brazil
73a0d70c92 readme update 2019-10-22 11:15:44 -07:00
Kelly Brazil
c2c189f3e6 readme update 2019-10-22 11:14:19 -07:00
Kelly Brazil
36bc55a310 fix df 2019-10-22 11:11:41 -07:00
Kelly Brazil
a023001cd3 add df, env, and free parsers 2019-10-22 11:10:11 -07:00
Kelly Brazil
e3750b4962 documentation enhancements 2019-10-22 07:40:42 -07:00
Kelly Brazil
b5ea08e55b fix transport protocol 2019-10-21 18:22:51 -07:00
Kelly Brazil
8e71b8e352 fix jq example 2019-10-21 18:11:51 -07:00
Kelly Brazil
4c8610c54f fixed build 2019-10-21 17:59:32 -07:00
Kelly Brazil
c8f886dc8f fix example 2019-10-21 17:56:53 -07:00
Kelly Brazil
4cfc2d22b3 update changelog 2019-10-21 17:38:40 -07:00
Kelly Brazil
59238c8540 Merge pull request #2 from kellyjonbrazil/dev
Dev v0.6.2
2019-10-21 17:36:33 -07:00
Kelly Brazil
30080c0165 reorder parsers 2019-10-21 17:26:00 -07:00
Kelly Brazil
fab80bb3b4 readme update 2019-10-21 17:20:12 -07:00
Kelly Brazil
a9f2df8054 move parsed_line var lower 2019-10-21 14:27:26 -07:00
Kelly Brazil
1d110be6cb update doco 2019-10-21 14:13:31 -07:00
Kelly Brazil
be81b5e1ed readme update 2019-10-21 13:47:22 -07:00
Kelly Brazil
5f88f7d8a0 netstat cleanup 2019-10-21 13:41:53 -07:00
Kelly Brazil
e57c7cc8ef change output from dict to list 2019-10-21 13:23:29 -07:00
Kelly Brazil
b216627c10 flatten netstat output 2019-10-21 13:19:00 -07:00
Kelly Brazil
6e925eab13 clean up arg parsing 2019-10-21 13:07:30 -07:00
Kelly Brazil
d54d906c57 update readme 2019-10-18 19:03:11 -07:00
Kelly Brazil
0040febbf0 Merge pull request #1 from kellyjonbrazil/dev
Dev v0.5.5
2019-10-18 18:57:32 -07:00
Kelly Brazil
e416c77bed version bump 2019-10-18 18:56:26 -07:00
Kelly Brazil
9181d242aa bump version 2019-10-18 18:47:20 -07:00
Kelly Brazil
d6f94c53a4 fix blank output case in ls 2019-10-18 18:46:25 -07:00
Kelly Brazil
a9294f32a0 ls fixes 2019-10-18 18:40:56 -07:00
Kelly Brazil
4d93b38fe4 add route documentation 2019-10-18 14:18:34 -07:00
Kelly Brazil
77b74c5507 add route parser 2019-10-18 13:59:30 -07:00
Kelly Brazil
51a1d3e6f4 version bump 2019-10-18 13:51:36 -07:00
Kelly Brazil
2eba30422b skip first line 2019-10-18 13:43:49 -07:00
Kelly Brazil
43ed09ce5b add route parser 2019-10-18 13:38:11 -07:00
Kelly Brazil
367ab54f94 formatting 2019-10-18 13:34:28 -07:00
Kelly Brazil
4f552e370e acknowledgment 2019-10-18 13:26:24 -07:00
Kelly Brazil
7571139f79 bump version 2019-10-18 13:20:38 -07:00
Kelly Brazil
8ec1bec317 add ps parser 2019-10-18 13:19:39 -07:00
Kelly Brazil
c04895407f ubuntu fixes 2019-10-18 12:57:02 -07:00
Kelly Brazil
cec73d6131 linting 2019-10-18 09:57:22 -07:00
Kelly Brazil
756c2bc9ac add acknowledgments 2019-10-18 09:57:10 -07:00
Kelly Brazil
084048987c changelog update 2019-10-17 17:59:46 -07:00
Kelly Brazil
02d97394dd changelog update 2019-10-17 17:28:14 -07:00
Kelly Brazil
177f948f97 version update 2019-10-17 16:11:55 -07:00
Kelly Brazil
c2b013150e add changelog 2019-10-17 15:51:39 -07:00
Kelly Brazil
0bec67c29c double quotes to single quotes 2019-10-17 15:39:12 -07:00
Kelly Brazil
8073d15fe1 readme update 2019-10-17 15:03:32 -07:00
457 changed files with 109192 additions and 702 deletions

1
MANIFEST.in Normal file
View File

@@ -0,0 +1 @@
graft tests/fixtures

2056
README.md

File diff suppressed because it is too large Load Diff

1
_config.yml Normal file
View File

@@ -0,0 +1 @@
theme: jekyll-theme-cayman

100
changelog.txt Normal file
View File

@@ -0,0 +1,100 @@
jc changelog
20200219 v1.7.4
- Updated ls parser to support multiple directories, globbing, and -R (recursive)
20200211 v1.7.3
- Add alternative 'magic' syntax: e.g. `jc ls -al`
- Options can now be condensed (e.g. -prq is equivalant to -p -r -q)
20200208 v1.7.2
- Include test fixtures in wheel and sdist
20200205 v1.7.1
- Add YAML file parser
- Add INI file parser
- Add XML file parser
- Add id parser (tested on linux and OSX)
- Add crontab file parser with user support (tested on linux)
- Add __version__ variable to parser modules
- Add exit code on error
- Updated history parser to output "line" as an integer
- Updated compatibility list for some parsers
- Bugfix in crontab file parser: header insertion was clobbering first row
- Just-in-time loading of parser modules instead of loading all at start
20191217 v1.6.1
- Add du parser (tested on linux and OSX)
- Add crontab parser (tested on linux and OSX)
- Add pip list parser (tested on linux and OSX)
- Add pip show parser (tested on linux and OSX)
- Add OSX support for the ifconfig, arp, df, mount, and uname parsers
- Add tests for ls, dig, ps, w, uptime on OSX
- Add about option
- Add universal parsers to refactor repetitive code
- Updated ifconfig parser to output 'state' as an array
20191117 v1.5.1
- Add ss parser
- Add stat parser
- Add /etc/hosts parser
- Add /etc/fstab parser
- Add systemctl parser (includes list-jobs, list-sockets, and list-unit-files)
- Add -r and raw=True options. By default, jc will now convert numbers and boolean, if possible, and add other semantic information, while the raw output will keep all values as text and provide a more literal JSON output
- Add -q and quiet=True options to suppress warnings to stderr
- Add -d option to debug parsing issues
- Add compatibility warnings to stderr
- Add documentation
- Updated iptables parser to allow --line-numbers option
- Updated lsblk parser to allow parsing of added columns
- Updated mount parser: changed 'access' field name to 'options'
- Updated netstat parser to allow parsing of unix sockets and raw network connections
- Updated w parser to fix unaligned data where blanks are possible
- Clean up code and reorganize package
20191031 v1.1.1
- Add arp parser
- Add dig parser
- Add unit tests
- fix netstat parser (remove side effects due to global variable)
20191025 v1.0.1
- Add w parser
- Add uptime parser
- Add history parser
- Flatten env parser output
- Remove problematic characters from key names in: df, free, history, lsblk, lsof, and w
- Where possible, lowercase all keys (except cases like env where the key is the variable name)
- Remove integer values
- Handle CTRL-C gracefully
20191023 v0.9.1
- Add jobs parser
- Add lsof parser
- Add lsmod parser
- No blocking if no piped data
- Better help text
- Clean up iptables parser code
20191022 v0.8.1
- Add env parser
- Add df parser
- Add free parser
- Add lsblk parser
- Add mount parser
- Add uname parser
- Add iptables parser
20191021 v0.6.4
- Flatten netstat parser output
- Clean up argument parsing
- Fix command help
20191018 v0.5.5
- Fix netstat -p parsing for Ubuntu
- Add ps parser
- Add route parser
- ls parser fixes
20191017 v0.2.0
- ifconfig, ls, and netstat support

43
docgen.sh Executable file
View File

@@ -0,0 +1,43 @@
#!/bin/bash
# Generate docs.md
cd jc
pydocmd simple jc+ > ../docs/readme.md
pydocmd simple utils+ > ../docs/utils.md
pydocmd simple jc.parsers.arp+ > ../docs/parsers/arp.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.df+ > ../docs/parsers/df.md
pydocmd simple jc.parsers.dig+ > ../docs/parsers/dig.md
pydocmd simple jc.parsers.du+ > ../docs/parsers/du.md
pydocmd simple jc.parsers.env+ > ../docs/parsers/env.md
pydocmd simple jc.parsers.free+ > ../docs/parsers/free.md
pydocmd simple jc.parsers.fstab+ > ../docs/parsers/fstab.md
pydocmd simple jc.parsers.history+ > ../docs/parsers/history.md
pydocmd simple jc.parsers.hosts+ > ../docs/parsers/hosts.md
pydocmd simple jc.parsers.id+ > ../docs/parsers/id.md
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.ls+ > ../docs/parsers/ls.md
pydocmd simple jc.parsers.lsblk+ > ../docs/parsers/lsblk.md
pydocmd simple jc.parsers.lsmod+ > ../docs/parsers/lsmod.md
pydocmd simple jc.parsers.lsof+ > ../docs/parsers/lsof.md
pydocmd simple jc.parsers.mount+ > ../docs/parsers/mount.md
pydocmd simple jc.parsers.netstat+ > ../docs/parsers/netstat.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
pydocmd simple jc.parsers.route+ > ../docs/parsers/route.md
pydocmd simple jc.parsers.ss+ > ../docs/parsers/ss.md
pydocmd simple jc.parsers.stat+ > ../docs/parsers/stat.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.uname+ > ../docs/parsers/uname.md
pydocmd simple jc.parsers.uptime+ > ../docs/parsers/uptime.md
pydocmd simple jc.parsers.w+ > ../docs/parsers/w.md
pydocmd simple jc.parsers.xml+ > ../docs/parsers/xml.md
pydocmd simple jc.parsers.yaml+ > ../docs/parsers/yaml.md

137
docs/parsers/arp.md Normal file
View File

@@ -0,0 +1,137 @@
# jc.parsers.arp
jc - JSON CLI output utility arp Parser
Usage:
specify --arp as the first argument if the piped input is coming from:
arp
or
arp -a
Compatibility:
'linux', 'aix', 'freebsd', 'darwin'
Examples:
$ arp | jc --arp -p
[
{
"address": "192.168.71.254",
"hwtype": "ether",
"hwaddress": "00:50:56:f0:98:26",
"flags_mask": "C",
"iface": "ens33"
},
{
"address": "gateway",
"hwtype": "ether",
"hwaddress": "00:50:56:f7:4a:fc",
"flags_mask": "C",
"iface": "ens33"
}
]
$ arp | jc --arp -p -r
[
{
"address": "gateway",
"hwtype": "ether",
"hwaddress": "00:50:56:f7:4a:fc",
"flags_mask": "C",
"iface": "ens33"
},
{
"address": "192.168.71.254",
"hwtype": "ether",
"hwaddress": "00:50:56:fe:7a:b4",
"flags_mask": "C",
"iface": "ens33"
}
]
$ arp -a | jc --arp -p
[
{
"name": null,
"address": "192.168.71.254",
"hwtype": "ether",
"hwaddress": "00:50:56:f0:98:26",
"iface": "ens33"
},
{
"name": "gateway",
"address": "192.168.71.2",
"hwtype": "ether",
"hwaddress": "00:50:56:f7:4a:fc",
"iface": "ens33"
}
]
$ arp -a | jc --arp -p -r
[
{
"name": "?",
"address": "192.168.71.254",
"hwtype": "ether",
"hwaddress": "00:50:56:fe:7a:b4",
"iface": "ens33"
},
{
"name": "_gateway",
"address": "192.168.71.2",
"hwtype": "ether",
"hwaddress": "00:50:56:f7:4a:fc",
"iface": "ens33"
}
]
## info
```python
info(self, /, *args, **kwargs)
```
## 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:
[
{
"name": string,
"address": string,
"hwtype": string,
"hwaddress": string,
"flags_mask": string,
"iface": 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.

197
docs/parsers/crontab.md Normal file
View File

@@ -0,0 +1,197 @@
# jc.parsers.crontab
jc - JSON CLI output utility crontab command and file Parser
Usage:
specify --crontab as the first argument if the piped input is coming from crontab -l or a crontab file
Compatibility:
'linux', 'darwin', 'aix', 'freebsd'
Examples:
$ crontab -l | jc --crontab -p
{
"variables": [
{
"name": "MAILTO",
"value": "root"
},
{
"name": "PATH",
"value": "/sbin:/bin:/usr/sbin:/usr/bin"
},
{
"name": "SHELL",
"value": "/bin/bash"
}
],
"schedule": [
{
"minute": [
"5"
],
"hour": [
"10-11",
"22"
],
"day_of_month": [
"*"
],
"month": [
"*"
],
"day_of_week": [
"*"
],
"command": "/var/www/devdaily.com/bin/mk-new-links.php"
},
{
"minute": [
"30"
],
"hour": [
"4/2"
],
"day_of_month": [
"*"
],
"month": [
"*"
],
"day_of_week": [
"*"
],
"command": "/var/www/devdaily.com/bin/create-all-backups.sh"
},
{
"occurrence": "yearly",
"command": "/home/maverick/bin/annual-maintenance"
},
{
"occurrence": "reboot",
"command": "/home/cleanup"
},
{
"occurrence": "monthly",
"command": "/home/maverick/bin/tape-backup"
}
]
}
$ cat /etc/crontab | jc --crontab -p -r
{
"variables": [
{
"name": "MAILTO",
"value": "root"
},
{
"name": "PATH",
"value": "/sbin:/bin:/usr/sbin:/usr/bin"
},
{
"name": "SHELL",
"value": "/bin/bash"
}
],
"schedule": [
{
"minute": "5",
"hour": "10-11,22",
"day_of_month": "*",
"month": "*",
"day_of_week": "*",
"command": "/var/www/devdaily.com/bin/mk-new-links.php"
},
{
"minute": "30",
"hour": "4/2",
"day_of_month": "*",
"month": "*",
"day_of_week": "*",
"command": "/var/www/devdaily.com/bin/create-all-backups.sh"
},
{
"occurrence": "yearly",
"command": "/home/maverick/bin/annual-maintenance"
},
{
"occurrence": "reboot",
"command": "/home/cleanup"
},
{
"occurrence": "monthly",
"command": "/home/maverick/bin/tape-backup"
}
]
}
## info
```python
info(self, /, *args, **kwargs)
```
## 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:
{
"variables": [
"name": string,
"value": string
],
"schedule": [
{
"occurrence" string,
"minute": [
string
],
"hour": [
string
],
"day_of_month": [
string
],
"month": [
string
],
"day_of_week": [
string
],
"occurrence": string,
"command": 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.

199
docs/parsers/crontab_u.md Normal file
View File

@@ -0,0 +1,199 @@
# jc.parsers.crontab_u
jc - JSON CLI output utility crontab file Parser
Usage:
specify --crontab-u as the first argument if the piped input is coming from a crontab file with User specified
Compatibility:
'linux', 'darwin', 'aix', 'freebsd'
Examples:
$ cat /etc/crontab | jc --crontab-u -p
{
"variables": [
{
"name": "PATH",
"value": "/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin"
},
{
"name": "SHELL",
"value": "/bin/sh"
}
],
"schedule": [
{
"minute": [
"25"
],
"hour": [
"6"
],
"day_of_month": [
"*"
],
"month": [
"*"
],
"day_of_week": [
"*"
],
"user": "root",
"command": "test -x /usr/sbin/anacron || ( cd / && run-parts --report /etc/cron.daily )"
},
{
"minute": [
"47"
],
"hour": [
"6"
],
"day_of_month": [
"*"
],
"month": [
"*"
],
"day_of_week": [
"7"
],
"user": "root",
"command": "test -x /usr/sbin/anacron || ( cd / && run-parts --report /etc/cron.weekly )"
},
{
"minute": [
"52"
],
"hour": [
"6"
],
"day_of_month": [
"1"
],
"month": [
"*"
],
"day_of_week": [
"*"
],
"user": "root",
"command": "test -x /usr/sbin/anacron || ( cd / && run-parts --report /etc/cron.monthly )"
}
]
}
$ cat /etc/crontab | jc --crontab-u -p -r
{
"variables": [
{
"name": "PATH",
"value": "/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin"
},
{
"name": "SHELL",
"value": "/bin/sh"
}
],
"schedule": [
{
"minute": "25",
"hour": "6",
"day_of_month": "*",
"month": "*",
"day_of_week": "*",
"user": "root",
"command": "test -x /usr/sbin/anacron || ( cd / && run-parts --report /etc/cron.daily )"
},
{
"minute": "47",
"hour": "6",
"day_of_month": "*",
"month": "*",
"day_of_week": "7",
"user": "root",
"command": "test -x /usr/sbin/anacron || ( cd / && run-parts --report /etc/cron.weekly )"
},
{
"minute": "52",
"hour": "6",
"day_of_month": "1",
"month": "*",
"day_of_week": "*",
"user": "root",
"command": "test -x /usr/sbin/anacron || ( cd / && run-parts --report /etc/cron.monthly )"
}
]
}
## info
```python
info(self, /, *args, **kwargs)
```
## 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:
{
"variables": [
"name": string,
"value": string
],
"schedule": [
{
"occurrence" string,
"minute": [
string
],
"hour": [
string
],
"day_of_month": [
string
],
"month": [
string
],
"day_of_week": [
string
],
"occurrence": string,
"user": string,
"command": 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.

125
docs/parsers/df.md Normal file
View File

@@ -0,0 +1,125 @@
# jc.parsers.df
jc - JSON CLI output utility df Parser
Usage:
specify --df as the first argument if the piped input is coming from df
Compatibility:
'linux', 'darwin'
Examples:
$ df | jc --df -p
[
{
"filesystem": "devtmpfs",
"1k_blocks": 1918820,
"used": 0,
"available": 1918820,
"use_percent": 0,
"mounted_on": "/dev"
},
{
"filesystem": "tmpfs",
"1k_blocks": 1930668,
"used": 0,
"available": 1930668,
"use_percent": 0,
"mounted_on": "/dev/shm"
},
{
"filesystem": "tmpfs",
"1k_blocks": 1930668,
"used": 11800,
"available": 1918868,
"use_percent": 1,
"mounted_on": "/run"
},
...
]
$ df | jc --df -p -r
[
{
"filesystem": "devtmpfs",
"1k_blocks": "1918820",
"used": "0",
"available": "1918820",
"use_percent": "0%",
"mounted_on": "/dev"
},
{
"filesystem": "tmpfs",
"1k_blocks": "1930668",
"used": "0",
"available": "1930668",
"use_percent": "0%",
"mounted_on": "/dev/shm"
},
{
"filesystem": "tmpfs",
"1k_blocks": "1930668",
"used": "11800",
"available": "1918868",
"use_percent": "1%",
"mounted_on": "/run"
},
...
]
## info
```python
info(self, /, *args, **kwargs)
```
## 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:
[
{
"filesystem": string,
"size": string,
"1k_blocks": integer,
"512_blocks": integer,
"used": integer,
"available": integer,
"capacity_percent": integer,
"ifree": integer,
"iused": integer,
"use_percent": integer,
"iused_percent": integer,
"mounted_on": 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.

402
docs/parsers/dig.md Normal file
View File

@@ -0,0 +1,402 @@
# jc.parsers.dig
jc - JSON CLI output utility dig Parser
Usage:
Specify --dig as the first argument if the piped input is coming from dig
Compatibility:
'linux', 'darwin', 'cygwin', 'win32', 'aix', 'freebsd'
Examples:
$ dig cnn.com www.cnn.com @205.251.194.64 | jc --dig -p
[
{
"id": 34128,
"opcode": "QUERY",
"status": "NOERROR",
"flags": [
"qr",
"rd",
"ra"
],
"query_num": 1,
"answer_num": 4,
"authority_num": 0,
"additional_num": 1,
"question": {
"name": "cnn.com.",
"class": "IN",
"type": "A"
},
"answer": [
{
"name": "cnn.com.",
"class": "IN",
"type": "A",
"ttl": 60,
"data": "151.101.65.67"
},
{
"name": "cnn.com.",
"class": "IN",
"type": "A",
"ttl": 60,
"data": "151.101.193.67"
},
{
"name": "cnn.com.",
"class": "IN",
"type": "A",
"ttl": 60,
"data": "151.101.1.67"
},
{
"name": "cnn.com.",
"class": "IN",
"type": "A",
"ttl": 60,
"data": "151.101.129.67"
}
],
"query_time": 37,
"server": "2600",
"when": "Tue Nov 12 07:14:42 PST 2019",
"rcvd": 100
},
{
"id": 15273,
"opcode": "QUERY",
"status": "NOERROR",
"flags": [
"qr",
"aa",
"rd"
],
"query_num": 1,
"answer_num": 1,
"authority_num": 4,
"additional_num": 1,
"question": {
"name": "www.cnn.com.",
"class": "IN",
"type": "A"
},
"answer": [
{
"name": "www.cnn.com.",
"class": "IN",
"type": "CNAME",
"ttl": 300,
"data": "turner-tls.map.fastly.net."
}
],
"authority": [
{
"name": "cnn.com.",
"class": "IN",
"type": "NS",
"ttl": 3600,
"data": "ns-1086.awsdns-07.org."
},
{
"name": "cnn.com.",
"class": "IN",
"type": "NS",
"ttl": 3600,
"data": "ns-1630.awsdns-11.co.uk."
},
{
"name": "cnn.com.",
"class": "IN",
"type": "NS",
"ttl": 3600,
"data": "ns-47.awsdns-05.com."
},
{
"name": "cnn.com.",
"class": "IN",
"type": "NS",
"ttl": 3600,
"data": "ns-576.awsdns-08.net."
}
],
"query_time": 23,
"server": "205.251.194.64#53(205.251.194.64)",
"when": "Tue Nov 12 07:14:42 PST 2019",
"rcvd": 212
}
]
$ dig cnn.com www.cnn.com @205.251.194.64 | jc --dig -p -r
[
{
"id": "23843",
"opcode": "QUERY",
"status": "NOERROR",
"flags": [
"qr",
"rd",
"ra"
],
"query_num": "1",
"answer_num": "4",
"authority_num": "0",
"additional_num": "1",
"question": {
"name": "cnn.com.",
"class": "IN",
"type": "A"
},
"answer": [
{
"name": "cnn.com.",
"class": "IN",
"type": "A",
"ttl": "30",
"data": "151.101.193.67"
},
{
"name": "cnn.com.",
"class": "IN",
"type": "A",
"ttl": "30",
"data": "151.101.1.67"
},
{
"name": "cnn.com.",
"class": "IN",
"type": "A",
"ttl": "30",
"data": "151.101.65.67"
},
{
"name": "cnn.com.",
"class": "IN",
"type": "A",
"ttl": "30",
"data": "151.101.129.67"
}
],
"query_time": "24 msec",
"server": "192.168.1.254#53(192.168.1.254)",
"when": "Tue Nov 12 07:16:19 PST 2019",
"rcvd": "100"
},
{
"id": "8266",
"opcode": "QUERY",
"status": "NOERROR",
"flags": [
"qr",
"aa",
"rd"
],
"query_num": "1",
"answer_num": "1",
"authority_num": "4",
"additional_num": "1",
"question": {
"name": "www.cnn.com.",
"class": "IN",
"type": "A"
},
"answer": [
{
"name": "www.cnn.com.",
"class": "IN",
"type": "CNAME",
"ttl": "300",
"data": "turner-tls.map.fastly.net."
}
],
"authority": [
{
"name": "cnn.com.",
"class": "IN",
"type": "NS",
"ttl": "3600",
"data": "ns-1086.awsdns-07.org."
},
{
"name": "cnn.com.",
"class": "IN",
"type": "NS",
"ttl": "3600",
"data": "ns-1630.awsdns-11.co.uk."
},
{
"name": "cnn.com.",
"class": "IN",
"type": "NS",
"ttl": "3600",
"data": "ns-47.awsdns-05.com."
},
{
"name": "cnn.com.",
"class": "IN",
"type": "NS",
"ttl": "3600",
"data": "ns-576.awsdns-08.net."
}
],
"query_time": "26 msec",
"server": "205.251.194.64#53(205.251.194.64)",
"when": "Tue Nov 12 07:16:19 PST 2019",
"rcvd": "212"
}
]
$ dig -x 1.1.1.1 | jc --dig -p
[
{
"id": 34898,
"opcode": "QUERY",
"status": "NOERROR",
"flags": [
"qr",
"rd",
"ra"
],
"query_num": 1,
"answer_num": 1,
"authority_num": 0,
"additional_num": 1,
"question": {
"name": "1.1.1.1.in-addr.arpa.",
"class": "IN",
"type": "PTR"
},
"answer": [
{
"name": "1.1.1.1.in-addr.arpa.",
"class": "IN",
"type": "PTR",
"ttl": 952,
"data": "one.one.one.one."
}
],
"query_time": 103,
"server": "2600",
"when": "Tue Nov 12 07:15:33 PST 2019",
"rcvd": 78
}
]
$ dig -x 1.1.1.1 | jc --dig -p -r
[
{
"id": "50986",
"opcode": "QUERY",
"status": "NOERROR",
"flags": [
"qr",
"rd",
"ra"
],
"query_num": "1",
"answer_num": "1",
"authority_num": "0",
"additional_num": "1",
"question": {
"name": "1.1.1.1.in-addr.arpa.",
"class": "IN",
"type": "PTR"
},
"answer": [
{
"name": "1.1.1.1.in-addr.arpa.",
"class": "IN",
"type": "PTR",
"ttl": "1800",
"data": "one.one.one.one."
}
],
"query_time": "38 msec",
"server": "2600",
"when": "Tue Nov 12 07:17:19 PST 2019",
"rcvd": "78"
}
]
## info
```python
info(self, /, *args, **kwargs)
```
## 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:
[
{
"id": integer,
"opcode": string,
"status": string,
"flags": [
string
],
"query_num": integer,
"answer_num": integer,
"authority_num": integer,
"additional_num": integer,
"question": {
"name": string,
"class": string,
"type": string
},
"answer": [
{
"name": string,
"class": string,
"type": string,
"ttl": integer,
"data": string
}
],
"authority": [
{
"name": string,
"class": string,
"type": string,
"ttl": integer,
"data": string
}
],
"query_time": integer, # in msec
"server": string,
"when": string,
"rcvd": integer
}
]
## 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.

115
docs/parsers/du.md Normal file
View File

@@ -0,0 +1,115 @@
# jc.parsers.du
jc - JSON CLI output utility du Parser
Usage:
specify --du as the first argument if the piped input is coming from du
Compatibility:
'linux', 'darwin', 'aix', 'freebsd'
Examples:
$ du /usr | jc --du -p
[
{
"size": 104608,
"name": "/usr/bin"
},
{
"size": 56,
"name": "/usr/standalone/firmware/iBridge1_1Customer.bundle/Contents/_CodeSignature"
},
{
"size": 0,
"name": "/usr/standalone/firmware/iBridge1_1Customer.bundle/Contents/Resources/Firmware/usr/local/standalone"
},
{
"size": 0,
"name": "/usr/standalone/firmware/iBridge1_1Customer.bundle/Contents/Resources/Firmware/usr/local"
},
{
"size": 0,
"name": "/usr/standalone/firmware/iBridge1_1Customer.bundle/Contents/Resources/Firmware/usr"
},
{
"size": 1008,
"name": "/usr/standalone/firmware/iBridge1_1Customer.bundle/Contents/Resources/Firmware/dfu"
},
...
]
$ du /usr | jc --du -p -r
[
{
"size": "104608",
"name": "/usr/bin"
},
{
"size": "56",
"name": "/usr/standalone/firmware/iBridge1_1Customer.bundle/Contents/_CodeSignature"
},
{
"size": "0",
"name": "/usr/standalone/firmware/iBridge1_1Customer.bundle/Contents/Resources/Firmware/usr/local/standalone"
},
{
"size": "0",
"name": "/usr/standalone/firmware/iBridge1_1Customer.bundle/Contents/Resources/Firmware/usr/local"
},
{
"size": "0",
"name": "/usr/standalone/firmware/iBridge1_1Customer.bundle/Contents/Resources/Firmware/usr"
},
{
"size": "1008",
"name": "/usr/standalone/firmware/iBridge1_1Customer.bundle/Contents/Resources/Firmware/dfu"
},
...
]
## info
```python
info(self, /, *args, **kwargs)
```
## 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:
[
{
"size": integer,
"name": 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.

96
docs/parsers/env.md Normal file
View File

@@ -0,0 +1,96 @@
# jc.parsers.env
jc - JSON CLI output utility env Parser
Usage:
specify --env as the first argument if the piped input is coming from env
Compatibility:
'linux', 'darwin', 'cygwin', 'win32', 'aix', 'freebsd'
Examples:
$ env | jc --env -p
[
{
"name": "XDG_SESSION_ID",
"value": "1"
},
{
"name": "HOSTNAME",
"value": "localhost.localdomain"
},
{
"name": "TERM",
"value": "vt220"
},
{
"name": "SHELL",
"value": "/bin/bash"
},
{
"name": "HISTSIZE",
"value": "1000"
},
...
]
$ env | jc --env -p -r
{
"TERM": "xterm-256color",
"SHELL": "/bin/bash",
"USER": "root",
"PATH": "/usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin",
"PWD": "/root",
"LANG": "en_US.UTF-8",
"HOME": "/root",
"LOGNAME": "root",
"_": "/usr/bin/env"
}
## info
```python
info(self, /, *args, **kwargs)
```
## 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:
[
{
"name": string,
"value": 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 of raw structured data or
list of dictionaries of processed structured data

100
docs/parsers/free.md Normal file
View File

@@ -0,0 +1,100 @@
# jc.parsers.free
jc - JSON CLI output utility free Parser
Usage:
specify --free as the first argument if the piped input is coming from free
Compatibility:
'linux'
Examples:
$ free | jc --free -p
[
{
"type": "Mem",
"total": 3861340,
"used": 220508,
"free": 3381972,
"shared": 11800,
"buff_cache": 258860,
"available": 3397784
},
{
"type": "Swap",
"total": 2097148,
"used": 0,
"free": 2097148
}
]
$ free | jc --free -p -r
[
{
"type": "Mem",
"total": "2017300",
"used": "213104",
"free": "1148452",
"shared": "1176",
"buff_cache": "655744",
"available": "1622204"
},
{
"type": "Swap",
"total": "2097148",
"used": "0",
"free": "2097148"
}
]
## info
```python
info(self, /, *args, **kwargs)
```
## 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:
[
{
"type": string,
"total": integer,
"used": integer,
"free": integer,
"shared": integer,
"buff_cache": integer,
"available": integer
}
]
## 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.

117
docs/parsers/fstab.md Normal file
View File

@@ -0,0 +1,117 @@
# jc.parsers.fstab
jc - JSON CLI output utility fstab Parser
Usage:
specify --fstab as the first argument if the piped input is coming from a fstab file
Compatibility:
'linux'
Examples:
$ cat /etc/fstab | jc --fstab -p
[
{
"fs_spec": "/dev/mapper/centos-root",
"fs_file": "/",
"fs_vfstype": "xfs",
"fs_mntops": "defaults",
"fs_freq": 0,
"fs_passno": 0
},
{
"fs_spec": "UUID=05d927bb-5875-49e3-ada1-7f46cb31c932",
"fs_file": "/boot",
"fs_vfstype": "xfs",
"fs_mntops": "defaults",
"fs_freq": 0,
"fs_passno": 0
},
{
"fs_spec": "/dev/mapper/centos-swap",
"fs_file": "swap",
"fs_vfstype": "swap",
"fs_mntops": "defaults",
"fs_freq": 0,
"fs_passno": 0
}
]
$ cat /etc/fstab | jc --fstab -p -r
[
{
"fs_spec": "/dev/mapper/centos-root",
"fs_file": "/",
"fs_vfstype": "xfs",
"fs_mntops": "defaults",
"fs_freq": "0",
"fs_passno": "0"
},
{
"fs_spec": "UUID=05d927bb-5875-49e3-ada1-7f46cb31c932",
"fs_file": "/boot",
"fs_vfstype": "xfs",
"fs_mntops": "defaults",
"fs_freq": "0",
"fs_passno": "0"
},
{
"fs_spec": "/dev/mapper/centos-swap",
"fs_file": "swap",
"fs_vfstype": "swap",
"fs_mntops": "defaults",
"fs_freq": "0",
"fs_passno": "0"
}
]
## info
```python
info(self, /, *args, **kwargs)
```
## 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:
[
{
"fs_spec": string,
"fs_file": string,
"fs_vfstype": string,
"fs_mntops": string,
"fs_freq": integer,
"fs_passno": integer
}
]
## 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.

88
docs/parsers/history.md Normal file
View File

@@ -0,0 +1,88 @@
# jc.parsers.history
jc - JSON CLI output utility history Parser
Usage:
specify --history as the first argument if the piped input is coming from history
Compatibility:
'linux', 'darwin', 'cygwin', 'aix', 'freebsd'
Examples:
$ history | jc --history -p
[
{
"line": 118,
"command": "sleep 100"
},
{
"line": 119,
"command": "ls /bin"
},
{
"line": 120,
"command": "echo "hello""
},
{
"line": 121,
"command": "docker images"
},
...
]
$ history | jc --history -p -r
{
"118": "sleep 100",
"119": "ls /bin",
"120": "echo "hello"",
"121": "docker images",
...
}
## info
```python
info(self, /, *args, **kwargs)
```
## 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:
[
{
"line": integer,
"command": 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 of raw structured data or
list of dictionaries of processed structured data

106
docs/parsers/hosts.md Normal file
View File

@@ -0,0 +1,106 @@
# jc.parsers.hosts
jc - JSON CLI output utility hosts Parser
Usage:
specify --hosts as the first argument if the piped input is coming from a hosts file
Compatibility:
'linux', 'darwin', 'cygwin', 'win32', 'aix', 'freebsd'
Examples:
$ cat /etc/hosts | jc --hosts -p
[
{
"ip": "127.0.0.1",
"hostname": [
"localhost"
]
},
{
"ip": "127.0.1.1",
"hostname": [
"root-ubuntu"
]
},
{
"ip": "::1",
"hostname": [
"ip6-localhost",
"ip6-loopback"
]
},
{
"ip": "fe00::0",
"hostname": [
"ip6-localnet"
]
},
{
"ip": "ff00::0",
"hostname": [
"ip6-mcastprefix"
]
},
{
"ip": "ff02::1",
"hostname": [
"ip6-allnodes"
]
},
{
"ip": "ff02::2",
"hostname": [
"ip6-allrouters"
]
}
]
## info
```python
info(self, /, *args, **kwargs)
```
## 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:
[
{
"ip": string,
"hostname": [
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.

133
docs/parsers/id.md Normal file
View File

@@ -0,0 +1,133 @@
# jc.parsers.id
jc - JSON CLI output utility id Parser
Usage:
specify --id as the first argument if the piped input is coming from id
Compatibility:
'linux', 'darwin', 'aix', 'freebsd'
Examples:
$ id | jc --id -p
{
"uid": {
"id": 1000,
"name": "joeuser"
},
"gid": {
"id": 1000,
"name": "joeuser"
},
"groups": [
{
"id": 1000,
"name": "joeuser"
},
{
"id": 10,
"name": "wheel"
}
],
"context": {
"user": "unconfined_u",
"role": "unconfined_r",
"type": "unconfined_t",
"level": "s0-s0:c0.c1023"
}
}
$ id | jc --id -p -r
{
"uid": {
"id": "1000",
"name": "joeuser"
},
"gid": {
"id": "1000",
"name": "joeuser"
},
"groups": [
{
"id": "1000",
"name": "joeuser"
},
{
"id": "10",
"name": "wheel"
}
],
"context": {
"user": "unconfined_u",
"role": "unconfined_r",
"type": "unconfined_t",
"level": "s0-s0:c0.c1023"
}
}
## info
```python
info(self, /, *args, **kwargs)
```
## 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:
{
"uid": {
"id": integer,
"name": string
},
"gid": {
"id": integer,
"name": string
},
"groups": [
{
"id": integer,
"name": string
},
{
"id": integer,
"name": string
}
],
"context": {
"user": string,
"role": string,
"type": string,
"level": 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.

214
docs/parsers/ifconfig.md Normal file
View File

@@ -0,0 +1,214 @@
# jc.parsers.ifconfig
jc - JSON CLI output utility ifconfig Parser
Usage:
specify --ifconfig as the first argument if the piped input is coming from ifconfig
no ifconfig options are supported.
Compatibility:
'linux', 'aix', 'freebsd', 'darwin'
Examples:
$ ifconfig | jc --ifconfig -p
[
{
"name": "ens33",
"flags": 4163,
"state": [
"UP",
"BROADCAST",
"RUNNING",
"MULTICAST"
],
"mtu": 1500,
"ipv4_addr": "192.168.71.137",
"ipv4_mask": "255.255.255.0",
"ipv4_bcast": "192.168.71.255",
"ipv6_addr": "fe80::c1cb:715d:bc3e:b8a0",
"ipv6_mask": 64,
"ipv6_scope": "0x20",
"mac_addr": "00:0c:29:3b:58:0e",
"type": "Ethernet",
"rx_packets": 8061,
"rx_bytes": 1514413,
"rx_errors": 0,
"rx_dropped": 0,
"rx_overruns": 0,
"rx_frame": 0,
"tx_packets": 4502,
"tx_bytes": 866622,
"tx_errors": 0,
"tx_dropped": 0,
"tx_overruns": 0,
"tx_carrier": 0,
"tx_collisions": 0,
"metric": null
},
{
"name": "lo",
"flags": 73,
"state": [
"UP",
"LOOPBACK",
"RUNNING"
],
"mtu": 65536,
"ipv4_addr": "127.0.0.1",
"ipv4_mask": "255.0.0.0",
"ipv4_bcast": null,
"ipv6_addr": "::1",
"ipv6_mask": 128,
"ipv6_scope": "0x10",
"mac_addr": null,
"type": "Local Loopback",
"rx_packets": 73,
"rx_bytes": 6009,
"rx_errors": 0,
"rx_dropped": 0,
"rx_overruns": 0,
"rx_frame": 0,
"tx_packets": 73,
"tx_bytes": 6009,
"tx_errors": 0,
"tx_dropped": 0,
"tx_overruns": 0,
"tx_carrier": 0,
"tx_collisions": 0,
"metric": null
}
]
$ ifconfig | jc --ifconfig -p -r
[
{
"name": "ens33",
"flags": "4163",
"state": "UP,BROADCAST,RUNNING,MULTICAST",
"mtu": "1500",
"ipv4_addr": "192.168.71.137",
"ipv4_mask": "255.255.255.0",
"ipv4_bcast": "192.168.71.255",
"ipv6_addr": "fe80::c1cb:715d:bc3e:b8a0",
"ipv6_mask": "64",
"ipv6_scope": "0x20",
"mac_addr": "00:0c:29:3b:58:0e",
"type": "Ethernet",
"rx_packets": "8061",
"rx_bytes": "1514413",
"rx_errors": "0",
"rx_dropped": "0",
"rx_overruns": "0",
"rx_frame": "0",
"tx_packets": "4502",
"tx_bytes": "866622",
"tx_errors": "0",
"tx_dropped": "0",
"tx_overruns": "0",
"tx_carrier": "0",
"tx_collisions": "0",
"metric": null
},
{
"name": "lo",
"flags": "73",
"state": "UP,LOOPBACK,RUNNING",
"mtu": "65536",
"ipv4_addr": "127.0.0.1",
"ipv4_mask": "255.0.0.0",
"ipv4_bcast": null,
"ipv6_addr": "::1",
"ipv6_mask": "128",
"ipv6_scope": "0x10",
"mac_addr": null,
"type": "Local Loopback",
"rx_packets": "73",
"rx_bytes": "6009",
"rx_errors": "0",
"rx_dropped": "0",
"rx_overruns": "0",
"rx_frame": "0",
"tx_packets": "73",
"tx_bytes": "6009",
"tx_errors": "0",
"tx_dropped": "0",
"tx_overruns": "0",
"tx_carrier": "0",
"tx_collisions": "0",
"metric": null
}
]
## info
```python
info(self, /, *args, **kwargs)
```
## 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:
[
{
"name": string,
"flags": integer,
"state": [
string
],
"mtu": integer,
"ipv4_addr": string,
"ipv4_mask": string,
"ipv4_bcast": string,
"ipv6_addr": string,
"ipv6_mask": integer,
"ipv6_scope": string,
"mac_addr": string,
"type": string,
"rx_packets": integer,
"rx_bytes": integer,
"rx_errors": integer,
"rx_dropped": integer,
"rx_overruns": integer,
"rx_frame": integer,
"tx_packets": integer,
"tx_bytes": integer,
"tx_errors": integer,
"tx_dropped": integer,
"tx_overruns": integer,
"tx_carrier": integer,
"tx_collisions": integer,
"metric": integer
}
]
## 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.

87
docs/parsers/ini.md Normal file
View File

@@ -0,0 +1,87 @@
# 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
Compatibility:
'linux', 'darwin', 'cygwin', 'win32', 'aix', 'freebsd'
Examples:
$ cat example.ini
[DEFAULT]
ServerAliveInterval = 45
Compression = yes
CompressionLevel = 9
ForwardX11 = yes
[bitbucket.org]
User = hg
[topsecret.server.com]
Port = 50022
ForwardX11 = no
$ cat example.ini | jc --ini -p
{
"bitbucket.org": {
"serveraliveinterval": "45",
"compression": "yes",
"compressionlevel": "9",
"forwardx11": "yes",
"user": "hg"
},
"topsecret.server.com": {
"serveraliveinterval": "45",
"compression": "yes",
"compressionlevel": "9",
"forwardx11": "no",
"port": "50022"
}
}
## info
```python
info(self, /, *args, **kwargs)
```
## process
```python
process(proc_data)
```
Final processing to conform to the schema.
Parameters:
proc_data: (dictionary) raw structured data to process
Returns:
Dictionary representing an ini document:
{
ini document converted to a dictionary
see configparser standard library documentation for more details
}
## 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 representing the ini file

191
docs/parsers/iptables.md Normal file
View File

@@ -0,0 +1,191 @@
# jc.parsers.iptables
jc - JSON CLI output utility ipables Parser
Usage:
Specify --iptables as the first argument if the piped input is coming from iptables
Supports -vLn and --line-numbers for all tables
Compatibility:
'linux'
Examples:
$ sudo iptables --line-numbers -v -L -t nat | jc --iptables -p
[
{
"chain": "PREROUTING",
"rules": [
{
"num": 1,
"pkts": 2183,
"bytes": 186000,
"target": "PREROUTING_direct",
"prot": "all",
"opt": null,
"in": "any",
"out": "any",
"source": "anywhere",
"destination": "anywhere"
},
{
"num": 2,
"pkts": 2183,
"bytes": 186000,
"target": "PREROUTING_ZONES_SOURCE",
"prot": "all",
"opt": null,
"in": "any",
"out": "any",
"source": "anywhere",
"destination": "anywhere"
},
{
"num": 3,
"pkts": 2183,
"bytes": 186000,
"target": "PREROUTING_ZONES",
"prot": "all",
"opt": null,
"in": "any",
"out": "any",
"source": "anywhere",
"destination": "anywhere"
},
{
"num": 4,
"pkts": 0,
"bytes": 0,
"target": "DOCKER",
"prot": "all",
"opt": null,
"in": "any",
"out": "any",
"source": "anywhere",
"destination": "anywhere",
"options": "ADDRTYPE match dst-type LOCAL"
}
]
},
...
]
$ sudo iptables --line-numbers -v -L -t nat | jc --iptables -p -r
[
{
"chain": "PREROUTING",
"rules": [
{
"num": "1",
"pkts": "2183",
"bytes": "186K",
"target": "PREROUTING_direct",
"prot": "all",
"opt": "--",
"in": "any",
"out": "any",
"source": "anywhere",
"destination": "anywhere"
},
{
"num": "2",
"pkts": "2183",
"bytes": "186K",
"target": "PREROUTING_ZONES_SOURCE",
"prot": "all",
"opt": "--",
"in": "any",
"out": "any",
"source": "anywhere",
"destination": "anywhere"
},
{
"num": "3",
"pkts": "2183",
"bytes": "186K",
"target": "PREROUTING_ZONES",
"prot": "all",
"opt": "--",
"in": "any",
"out": "any",
"source": "anywhere",
"destination": "anywhere"
},
{
"num": "4",
"pkts": "0",
"bytes": "0",
"target": "DOCKER",
"prot": "all",
"opt": "--",
"in": "any",
"out": "any",
"source": "anywhere",
"destination": "anywhere",
"options": "ADDRTYPE match dst-type LOCAL"
}
]
},
...
]
## info
```python
info(self, /, *args, **kwargs)
```
## 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:
[
{
"chain": string,
"rules": [
{
"num" integer,
"pkts": integer,
"bytes": integer, # converted based on suffix
"target": string,
"prot": string,
"opt": string, # "--" = Null
"in": string,
"out": string,
"source": string,
"destination": string,
"options": 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.

122
docs/parsers/jobs.md Normal file
View File

@@ -0,0 +1,122 @@
# jc.parsers.jobs
jc - JSON CLI output utility jobs Parser
Usage:
specify --jobs as the first argument if the piped input is coming from jobs
Also supports the -l option
Compatibility:
'linux', 'darwin', 'cygwin', 'aix', 'freebsd'
Example:
$ jobs -l | jc --jobs -p
[
{
"job_number": 1,
"pid": 5283,
"status": "Running",
"command": "sleep 10000 &"
},
{
"job_number": 2,
"pid": 5284,
"status": "Running",
"command": "sleep 10100 &"
},
{
"job_number": 3,
"pid": 5285,
"history": "previous",
"status": "Running",
"command": "sleep 10001 &"
},
{
"job_number": 4,
"pid": 5286,
"history": "current",
"status": "Running",
"command": "sleep 10112 &"
}
]
$ jobs -l | jc --jobs -p -r
[
{
"job_number": "1",
"pid": "19510",
"status": "Running",
"command": "sleep 1000 &"
},
{
"job_number": "2",
"pid": "19511",
"status": "Running",
"command": "sleep 1001 &"
},
{
"job_number": "3",
"pid": "19512",
"history": "previous",
"status": "Running",
"command": "sleep 1002 &"
},
{
"job_number": "4",
"pid": "19513",
"history": "current",
"status": "Running",
"command": "sleep 1003 &"
}
]
## info
```python
info(self, /, *args, **kwargs)
```
## 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:
[
{
"job_number": integer,
"pid": integer,
"history": string,
"status": string,
"command": 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.

193
docs/parsers/ls.md Normal file
View File

@@ -0,0 +1,193 @@
# jc.parsers.ls
jc - JSON CLI output utility ls Parser
Usage:
specify --ls as the first argument if the piped input is coming from ls
ls options supported:
- None
- laR
--time-style=full-iso
- h file sizes will be available in text form with -r but larger file sizes
with human readable suffixes will be converted to Null in default view
since the parser attempts to convert this field to an integer.
Compatibility:
'linux', 'darwin', 'cygwin', 'aix', 'freebsd'
Examples:
$ ls /usr/bin | jc --ls -p
[
{
"filename": "apropos"
},
{
"filename": "arch"
},
{
"filename": "awk"
},
{
"filename": "base64"
},
...
]
$ ls -l /usr/bin | jc --ls -p
[
{
"filename": "apropos",
"link_to": "whatis",
"flags": "lrwxrwxrwx.",
"links": 1,
"owner": "root",
"group": "root",
"size": 6,
"date": "Aug 15 10:53"
},
{
"filename": "ar",
"flags": "-rwxr-xr-x.",
"links": 1,
"owner": "root",
"group": "root",
"size": 62744,
"date": "Aug 8 16:14"
},
{
"filename": "arch",
"flags": "-rwxr-xr-x.",
"links": 1,
"owner": "root",
"group": "root",
"size": 33080,
"date": "Aug 19 23:25"
},
...
]
$ ls -l /usr/bin | jc --ls -p -r
[
{
"filename": "apropos",
"link_to": "whatis",
"flags": "lrwxrwxrwx.",
"links": "1",
"owner": "root",
"group": "root",
"size": "6",
"date": "Aug 15 10:53"
},
{
"filename": "arch",
"flags": "-rwxr-xr-x.",
"links": "1",
"owner": "root",
"group": "root",
"size": "33080",
"date": "Aug 19 23:25"
},
{
"filename": "awk",
"link_to": "gawk",
"flags": "lrwxrwxrwx.",
"links": "1",
"owner": "root",
"group": "root",
"size": "4",
"date": "Aug 15 10:53"
},
{
"filename": "base64",
"flags": "-rwxr-xr-x.",
"links": "1",
"owner": "root",
"group": "root",
"size": "37360",
"date": "Aug 19 23:25"
},
{
"filename": "basename",
"flags": "-rwxr-xr-x.",
"links": "1",
"owner": "root",
"group": "root",
"size": "29032",
"date": "Aug 19 23:25"
},
{
"filename": "bash",
"flags": "-rwxr-xr-x.",
"links": "1",
"owner": "root",
"group": "root",
"size": "964600",
"date": "Aug 8 05:06"
},
...
]
$ ls -l /usr/bin | jc --ls | jq '.[] | select(.size > 50000000)'
{
"filename": "emacs",
"flags": "-r-xr-xr-x",
"links": 1,
"owner": "root",
"group": "wheel",
"size": 117164432,
"date": "May 3 2019"
}
## info
```python
info(self, /, *args, **kwargs)
```
## 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:
[
{
"filename": string,
"flags": string,
"links": integer,
"parent": string,
"owner": string,
"group": string,
"size": integer,
"date": 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.

296
docs/parsers/lsblk.md Normal file
View File

@@ -0,0 +1,296 @@
# jc.parsers.lsblk
jc - JSON CLI output utility lsblk Parser
Usage:
specify --lsblk as the first argument if the piped input is coming from lsblk
Compatibility:
'linux'
Examples:
$ lsblk | jc --lsblk -p
[
{
"name": "sda",
"maj_min": "8:0",
"rm": false,
"size": "20G",
"ro": false,
"type": "disk",
"mountpoint": null
},
{
"name": "sda1",
"maj_min": "8:1",
"rm": false,
"size": "1G",
"ro": false,
"type": "part",
"mountpoint": "/boot"
},
...
]
$ lsblk -o +KNAME,FSTYPE,LABEL,UUID,PARTLABEL,PARTUUID,RA,MODEL,SERIAL,STATE,OWNER,GROUP,MODE,ALIGNMENT,MIN-IO,OPT-IO,PHY-SEC,LOG-SEC,ROTA,SCHED,RQ-SIZE,DISC-ALN,DISC-GRAN,DISC-MAX,DISC-ZERO,WSAME,WWN,RAND,PKNAME,HCTL,TRAN,REV,VENDOR | jc --lsblk -p
[
{
"name": "sda",
"maj_min": "8:0",
"rm": false,
"size": "20G",
"ro": false,
"type": "disk",
"mountpoint": null,
"kname": "sda",
"fstype": null,
"label": null,
"uuid": null,
"partlabel": null,
"partuuid": null,
"ra": 4096,
"model": "VMware Virtual S",
"serial": null,
"state": "running",
"owner": "root",
"group": "disk",
"mode": "brw-rw----",
"alignment": 0,
"min_io": 512,
"opt_io": 0,
"phy_sec": 512,
"log_sec": 512,
"rota": true,
"sched": "deadline",
"rq_size": 128,
"disc_aln": 0,
"disc_gran": "0B",
"disc_max": "0B",
"disc_zero": false,
"wsame": "32M",
"wwn": null,
"rand": true,
"pkname": null,
"hctl": "0:0:0:0",
"tran": "spi",
"rev": "1.0",
"vendor": "VMware,"
},
{
"name": "sda1",
"maj_min": "8:1",
"rm": false,
"size": "1G",
"ro": false,
"type": "part",
"mountpoint": "/boot",
"kname": "sda1",
"fstype": "xfs",
"label": null,
"uuid": "05d927bb-5875-49e3-ada1-7f46cb31c932",
"partlabel": null,
"partuuid": null,
"ra": 4096,
"model": null,
"serial": null,
"state": null,
"owner": "root",
"group": "disk",
"mode": "brw-rw----",
"alignment": 0,
"min_io": 512,
"opt_io": 0,
"phy_sec": 512,
"log_sec": 512,
"rota": true,
"sched": "deadline",
"rq_size": 128,
"disc_aln": 0,
"disc_gran": "0B",
"disc_max": "0B",
"disc_zero": false,
"wsame": "32M",
"wwn": null,
"rand": true,
"pkname": "sda",
"hctl": null,
"tran": null,
"rev": null,
"vendor": null
},
...
]
$ lsblk -o +KNAME,FSTYPE,LABEL,UUID,PARTLABEL,PARTUUID,RA,MODEL,SERIAL,STATE,OWNER,GROUP,MODE,ALIGNMENT,MIN-IO,OPT-IO,PHY-SEC,LOG-SEC,ROTA,SCHED,RQ-SIZE,DISC-ALN,DISC-GRAN,DISC-MAX,DISC-ZERO,WSAME,WWN,RAND,PKNAME,HCTL,TRAN,REV,VENDOR | jc --lsblk -p -r
[
{
"name": "sda",
"maj_min": "8:0",
"rm": "0",
"size": "20G",
"ro": "0",
"type": "disk",
"mountpoint": null,
"kname": "sda",
"fstype": null,
"label": null,
"uuid": null,
"partlabel": null,
"partuuid": null,
"ra": "4096",
"model": "VMware Virtual S",
"serial": null,
"state": "running",
"owner": "root",
"group": "disk",
"mode": "brw-rw----",
"alignment": "0",
"min_io": "512",
"opt_io": "0",
"phy_sec": "512",
"log_sec": "512",
"rota": "1",
"sched": "deadline",
"rq_size": "128",
"disc_aln": "0",
"disc_gran": "0B",
"disc_max": "0B",
"disc_zero": "0",
"wsame": "32M",
"wwn": null,
"rand": "1",
"pkname": null,
"hctl": "0:0:0:0",
"tran": "spi",
"rev": "1.0",
"vendor": "VMware,"
},
{
"name": "sda1",
"maj_min": "8:1",
"rm": "0",
"size": "1G",
"ro": "0",
"type": "part",
"mountpoint": "/boot",
"kname": "sda1",
"fstype": "xfs",
"label": null,
"uuid": "05d927bb-5875-49e3-ada1-7f46cb31c932",
"partlabel": null,
"partuuid": null,
"ra": "4096",
"model": null,
"serial": null,
"state": null,
"owner": "root",
"group": "disk",
"mode": "brw-rw----",
"alignment": "0",
"min_io": "512",
"opt_io": "0",
"phy_sec": "512",
"log_sec": "512",
"rota": "1",
"sched": "deadline",
"rq_size": "128",
"disc_aln": "0",
"disc_gran": "0B",
"disc_max": "0B",
"disc_zero": "0",
"wsame": "32M",
"wwn": null,
"rand": "1",
"pkname": "sda",
"hctl": null,
"tran": null,
"rev": null,
"vendor": null
},
...
]
## info
```python
info(self, /, *args, **kwargs)
```
## 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:
[
{
"name": string,
"maj_min": string,
"rm": boolean,
"size": string,
"ro": boolean,
"type": string,
"mountpoint": string,
"kname": string,
"fstype": string,
"label": string,
"uuid": string,
"partlabel": string,
"partuuid": string,
"ra": integer,
"model": string,
"serial": string,
"state": string,
"owner": string,
"group": string,
"mode": string,
"alignment": integer,
"min_io": integer,
"opt_io": integer,
"phy_sec": integer,
"log_sec": integer,
"rota": boolean,
"sched": string,
"rq_size": integer,
"disc_aln": integer,
"disc_gran": string,
"disc_max": string,
"disc_zero": boolean,
"wsame": string,
"wwn": string,
"rand": boolean,
"pkname": string,
"hctl": string,
"tran": string,
"rev": string,
"vendor": 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.

153
docs/parsers/lsmod.md Normal file
View File

@@ -0,0 +1,153 @@
# jc.parsers.lsmod
jc - JSON CLI output utility lsmod Parser
Usage:
specify --lsmod as the first argument if the piped input is coming from lsmod
Compatibility:
'linux'
Examples:
$ lsmod | jc --lsmod -p
[
...
{
"module": "nf_nat",
"size": 26583,
"used": 3,
"by": [
"nf_nat_ipv4",
"nf_nat_ipv6",
"nf_nat_masquerade_ipv4"
]
},
{
"module": "iptable_mangle",
"size": 12695,
"used": 1
},
{
"module": "iptable_security",
"size": 12705,
"used": 1
},
{
"module": "iptable_raw",
"size": 12678,
"used": 1
},
{
"module": "nf_conntrack",
"size": 139224,
"used": 7,
"by": [
"nf_nat",
"nf_nat_ipv4",
"nf_nat_ipv6",
"xt_conntrack",
"nf_nat_masquerade_ipv4",
"nf_conntrack_ipv4",
"nf_conntrack_ipv6"
]
},
...
]
$ lsmod | jc --lsmod -p -r
[
...
{
"module": "nf_conntrack",
"size": "139224",
"used": "7",
"by": [
"nf_nat",
"nf_nat_ipv4",
"nf_nat_ipv6",
"xt_conntrack",
"nf_nat_masquerade_ipv4",
"nf_conntrack_ipv4",
"nf_conntrack_ipv6"
]
},
{
"module": "ip_set",
"size": "45799",
"used": "0"
},
{
"module": "nfnetlink",
"size": "14519",
"used": "1",
"by": [
"ip_set"
]
},
{
"module": "ebtable_filter",
"size": "12827",
"used": "1"
},
{
"module": "ebtables",
"size": "35009",
"used": "2",
"by": [
"ebtable_nat",
"ebtable_filter"
]
},
...
]
## info
```python
info(self, /, *args, **kwargs)
```
## 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:
[
{
"module": string,
"size": integer,
"used": integer,
"by": [
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.

147
docs/parsers/lsof.md Normal file
View File

@@ -0,0 +1,147 @@
# jc.parsers.lsof
jc - JSON CLI output utility lsof Parser
Usage:
specify --lsof as the first argument if the piped input is coming from lsof
Compatibility:
'linux'
Examples:
$ sudo lsof | jc --lsof -p
[
{
"command": "systemd",
"pid": 1,
"tid": null,
"user": "root",
"fd": "cwd",
"type": "DIR",
"device": "253,0",
"size_off": 224,
"node": 64,
"name": "/"
},
{
"command": "systemd",
"pid": 1,
"tid": null,
"user": "root",
"fd": "rtd",
"type": "DIR",
"device": "253,0",
"size_off": 224,
"node": 64,
"name": "/"
},
{
"command": "systemd",
"pid": 1,
"tid": null,
"user": "root",
"fd": "txt",
"type": "REG",
"device": "253,0",
"size_off": 1624520,
"node": 50360451,
"name": "/usr/lib/systemd/systemd"
},
...
]
$ sudo lsof | jc --lsof -p -r
[
{
"command": "systemd",
"pid": "1",
"tid": null,
"user": "root",
"fd": "cwd",
"type": "DIR",
"device": "8,2",
"size_off": "4096",
"node": "2",
"name": "/"
},
{
"command": "systemd",
"pid": "1",
"tid": null,
"user": "root",
"fd": "rtd",
"type": "DIR",
"device": "8,2",
"size_off": "4096",
"node": "2",
"name": "/"
},
{
"command": "systemd",
"pid": "1",
"tid": null,
"user": "root",
"fd": "txt",
"type": "REG",
"device": "8,2",
"size_off": "1595792",
"node": "668802",
"name": "/lib/systemd/systemd"
},
...
]
## info
```python
info(self, /, *args, **kwargs)
```
## 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:
[
{
"command": string,
"pid": integer,
"tid": integer,
"user": string,
"fd": string,
"type": string,
"device": string,
"size_off": integer,
"node": integer,
"name": 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.

103
docs/parsers/mount.md Normal file
View File

@@ -0,0 +1,103 @@
# jc.parsers.mount
jc - JSON CLI output utility mount Parser
Usage:
specify --mount as the first argument if the piped input is coming from mount
Compatibility:
'linux', 'darwin'
Example:
$ mount | jc --mount -p
[
{
"filesystem": "sysfs",
"mount_point": "/sys",
"type": "sysfs",
"access": [
"rw",
"nosuid",
"nodev",
"noexec",
"relatime"
]
},
{
"filesystem": "proc",
"mount_point": "/proc",
"type": "proc",
"access": [
"rw",
"nosuid",
"nodev",
"noexec",
"relatime"
]
},
{
"filesystem": "udev",
"mount_point": "/dev",
"type": "devtmpfs",
"access": [
"rw",
"nosuid",
"relatime",
"size=977500k",
"nr_inodes=244375",
"mode=755"
]
},
...
]
## info
```python
info(self, /, *args, **kwargs)
```
## 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:
[
{
"filesystem": string,
"mount_point": string,
"type": string,
"access": [
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.

375
docs/parsers/netstat.md Normal file
View File

@@ -0,0 +1,375 @@
# jc.parsers.netstat
jc - JSON CLI output utility netstat Parser
Usage:
Specify --netstat as the first argument if the piped input is coming from netstat
Compatibility:
'linux'
Examples:
$ sudo netstat -apee | 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"
},
{
"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"
},
{
"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",
"foreign_port_num": 52186
},
{
"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",
"local_port_num": 52186
},
{
"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
},
...
]
$ sudo netstat -apee | jc --netstat -p -r
[
{
"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"
},
{
"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"
},
{
"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"
},
...
]
## info
```python
info(self, /, *args, **kwargs)
```
## 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:
[
{
"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
}
]
## 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.

75
docs/parsers/pip_list.md Normal file
View File

@@ -0,0 +1,75 @@
# jc.parsers.pip_list
jc - JSON CLI output utility pip-list Parser
Usage:
specify --pip-list as the first argument if the piped input is coming from pip list
Compatibility:
'linux', 'darwin', 'cygwin', 'win32', 'aix', 'freebsd'
Examples:
$ pip list | jc --pip-list -p
[
{
"package": "ansible",
"version": "2.8.5"
},
{
"package": "antlr4-python3-runtime",
"version": "4.7.2"
},
{
"package": "asn1crypto",
"version": "0.24.0"
},
...
]
## info
```python
info(self, /, *args, **kwargs)
```
## 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:
[
{
"package": string,
"version": string,
"location": 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.

94
docs/parsers/pip_show.md Normal file
View File

@@ -0,0 +1,94 @@
# jc.parsers.pip_show
jc - JSON CLI output utility pip-show Parser
Usage:
specify --pip-show as the first argument if the piped input is coming from pip show
Compatibility:
'linux', 'darwin', 'cygwin', 'win32', 'aix', 'freebsd'
Examples:
$ pip show wrapt jc wheel | jc --pip-show -p
[
{
"name": "wrapt",
"version": "1.11.2",
"summary": "Module for decorators, wrappers and monkey patching.",
"home_page": "https://github.com/GrahamDumpleton/wrapt",
"author": "Graham Dumpleton",
"author_email": "Graham.Dumpleton@gmail.com",
"license": "BSD",
"location": "/usr/local/lib/python3.7/site-packages",
"requires": null,
"required_by": "astroid"
},
{
"name": "wheel",
"version": "0.33.4",
"summary": "A built-package format for Python.",
"home_page": "https://github.com/pypa/wheel",
"author": "Daniel Holth",
"author_email": "dholth@fastmail.fm",
"license": "MIT",
"location": "/usr/local/lib/python3.7/site-packages",
"requires": null,
"required_by": null
}
]
## info
```python
info(self, /, *args, **kwargs)
```
## 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:
[
{
"name": string,
"version": string,
"summary": string,
"home_page": string,
"author": string,
"author_email": string,
"license": string,
"location": string,
"requires": string,
"required_by": 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.

234
docs/parsers/ps.md Normal file
View File

@@ -0,0 +1,234 @@
# jc.parsers.ps
jc - JSON CLI output utility ps Parser
Usage:
specify --ps as the first argument if the piped input is coming from ps
ps options supported:
- ef
- axu
Compatibility:
'linux', 'darwin', 'cygwin', 'aix', 'freebsd'
Examples:
$ ps -ef | jc --ps -p
[
{
"uid": "root",
"pid": 1,
"ppid": 0,
"c": 0,
"stime": "Nov01",
"tty": null,
"time": "00:00:11",
"cmd": "/usr/lib/systemd/systemd --switched-root --system --deserialize 22"
},
{
"uid": "root",
"pid": 2,
"ppid": 0,
"c": 0,
"stime": "Nov01",
"tty": null,
"time": "00:00:00",
"cmd": "[kthreadd]"
},
{
"uid": "root",
"pid": 4,
"ppid": 2,
"c": 0,
"stime": "Nov01",
"tty": null,
"time": "00:00:00",
"cmd": "[kworker/0:0H]"
},
...
]
$ ps -ef | jc --ps -p -r
[
{
"uid": "root",
"pid": "1",
"ppid": "0",
"c": "0",
"stime": "Nov01",
"tty": "?",
"time": "00:00:11",
"cmd": "/usr/lib/systemd/systemd --switched-root --system --deserialize 22"
},
{
"uid": "root",
"pid": "2",
"ppid": "0",
"c": "0",
"stime": "Nov01",
"tty": "?",
"time": "00:00:00",
"cmd": "[kthreadd]"
},
{
"uid": "root",
"pid": "4",
"ppid": "2",
"c": "0",
"stime": "Nov01",
"tty": "?",
"time": "00:00:00",
"cmd": "[kworker/0:0H]"
},
...
]
$ ps axu | jc --ps -p
[
{
"user": "root",
"pid": 1,
"cpu_percent": 0.0,
"mem_percent": 0.1,
"vsz": 128072,
"rss": 6784,
"tty": null,
"stat": "Ss",
"start": "Nov09",
"time": "0:08",
"command": "/usr/lib/systemd/systemd --switched-root --system --deserialize 22"
},
{
"user": "root",
"pid": 2,
"cpu_percent": 0.0,
"mem_percent": 0.0,
"vsz": 0,
"rss": 0,
"tty": null,
"stat": "S",
"start": "Nov09",
"time": "0:00",
"command": "[kthreadd]"
},
{
"user": "root",
"pid": 4,
"cpu_percent": 0.0,
"mem_percent": 0.0,
"vsz": 0,
"rss": 0,
"tty": null,
"stat": "S<",
"start": "Nov09",
"time": "0:00",
"command": "[kworker/0:0H]"
},
...
]
$ ps axu | jc --ps -p -r
[
{
"user": "root",
"pid": "1",
"cpu_percent": "0.0",
"mem_percent": "0.1",
"vsz": "128072",
"rss": "6784",
"tty": "?",
"stat": "Ss",
"start": "Nov09",
"time": "0:08",
"command": "/usr/lib/systemd/systemd --switched-root --system --deserialize 22"
},
{
"user": "root",
"pid": "2",
"cpu_percent": "0.0",
"mem_percent": "0.0",
"vsz": "0",
"rss": "0",
"tty": "?",
"stat": "S",
"start": "Nov09",
"time": "0:00",
"command": "[kthreadd]"
},
{
"user": "root",
"pid": "4",
"cpu_percent": "0.0",
"mem_percent": "0.0",
"vsz": "0",
"rss": "0",
"tty": "?",
"stat": "S<",
"start": "Nov09",
"time": "0:00",
"command": "[kworker/0:0H]"
},
...
]
## info
```python
info(self, /, *args, **kwargs)
```
## 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:
[
{
"uid": string,
"pid": integer,
"ppid": integer,
"c": integer,
"stime": string,
"tty": string, # ? or ?? = Null
"tt": string, # ?? = Null
"time": string,
"cmd": string,
"user": string,
"cpu_percent": float,
"mem_percent": float,
"vsz": integer,
"rss": integer,
"stat": string,
"start": string,
"command": 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.

152
docs/parsers/route.md Normal file
View File

@@ -0,0 +1,152 @@
# jc.parsers.route
jc - JSON CLI output utility route Parser
Usage:
specify --route as the first argument if the piped input is coming from route
Compatibility:
'linux'
Examples:
$ route -ee | jc --route -p
[
{
"destination": "default",
"gateway": "gateway",
"genmask": "0.0.0.0",
"flags": "UG",
"metric": 100,
"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
},
{
"destination": "192.168.71.0",
"gateway": "0.0.0.0",
"genmask": "255.255.255.0",
"flags": "U",
"metric": 100,
"ref": 0,
"use": 0,
"iface": "ens33",
"mss": 0,
"window": 0,
"irtt": 0
}
]
$ route -ee | jc --route -p -r
[
{
"destination": "default",
"gateway": "gateway",
"genmask": "0.0.0.0",
"flags": "UG",
"metric": "100",
"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"
},
{
"destination": "192.168.71.0",
"gateway": "0.0.0.0",
"genmask": "255.255.255.0",
"flags": "U",
"metric": "100",
"ref": "0",
"use": "0",
"iface": "ens33",
"mss": "0",
"window": "0",
"irtt": "0"
}
]
## info
```python
info(self, /, *args, **kwargs)
```
## 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:
[
{
"destination": string,
"gateway": string,
"genmask": string,
"flags": string,
"metric": integer,
"ref": integer,
"use": integer,
"mss": integer,
"window": integer,
"irtt": integer,
"iface": 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.

308
docs/parsers/ss.md Normal file
View File

@@ -0,0 +1,308 @@
# jc.parsers.ss
jc - JSON CLI output utility ss Parser
Usage:
specify --ss as the first argument if the piped input is coming from ss
Limitations:
Extended information options like -e and -p are not supported and may cause parsing irregularities
Compatibility:
'linux'
Examples:
$ sudo ss -a | jc --ss -p
[
{
"netid": "nl",
"state": "UNCONN",
"recv_q": 0,
"send_q": 0,
"peer_address": "*",
"channel": "rtnl:kernel"
},
{
"netid": "nl",
"state": "UNCONN",
"recv_q": 0,
"send_q": 0,
"peer_address": "*",
"pid": 893,
"channel": "rtnl:systemd-resolve"
},
...
{
"netid": "p_raw",
"state": "UNCONN",
"recv_q": 0,
"send_q": 0,
"peer_address": "*",
"link_layer": "LLDP",
"interface": "ens33"
},
{
"netid": "u_dgr",
"state": "UNCONN",
"recv_q": 0,
"send_q": 0,
"local_port": "93066",
"peer_address": "*",
"peer_port": "0",
"path": "/run/user/1000/systemd/notify"
},
{
"netid": "u_seq",
"state": "LISTEN",
"recv_q": 0,
"send_q": 128,
"local_port": "20699",
"peer_address": "*",
"peer_port": "0",
"path": "/run/udev/control"
},
...
{
"netid": "icmp6",
"state": "UNCONN",
"recv_q": 0,
"send_q": 0,
"local_address": "*",
"local_port": "ipv6-icmp",
"peer_address": "*",
"peer_port": "*",
"interface": "ens33"
},
{
"netid": "udp",
"state": "UNCONN",
"recv_q": 0,
"send_q": 0,
"local_address": "127.0.0.53",
"local_port": "domain",
"peer_address": "0.0.0.0",
"peer_port": "*",
"interface": "lo"
},
{
"netid": "tcp",
"state": "LISTEN",
"recv_q": 0,
"send_q": 128,
"local_address": "127.0.0.53",
"local_port": "domain",
"peer_address": "0.0.0.0",
"peer_port": "*",
"interface": "lo"
},
{
"netid": "tcp",
"state": "LISTEN",
"recv_q": 0,
"send_q": 128,
"local_address": "0.0.0.0",
"local_port": "ssh",
"peer_address": "0.0.0.0",
"peer_port": "*"
},
{
"netid": "tcp",
"state": "LISTEN",
"recv_q": 0,
"send_q": 128,
"local_address": "[::]",
"local_port": "ssh",
"peer_address": "[::]",
"peer_port": "*"
},
{
"netid": "v_str",
"state": "ESTAB",
"recv_q": 0,
"send_q": 0,
"local_address": "999900439",
"local_port": "1023",
"peer_address": "0",
"peer_port": "976",
"local_port_num": 1023,
"peer_port_num": 976
}
]
$ sudo ss -a | jc --ss -p -r
[
{
"netid": "nl",
"state": "UNCONN",
"recv_q": "0",
"send_q": "0",
"peer_address": "*",
"channel": "rtnl:kernel"
},
{
"netid": "nl",
"state": "UNCONN",
"recv_q": "0",
"send_q": "0",
"peer_address": "*",
"pid": "893",
"channel": "rtnl:systemd-resolve"
},
...
{
"netid": "p_raw",
"state": "UNCONN",
"recv_q": "0",
"send_q": "0",
"peer_address": "*",
"link_layer": "LLDP",
"interface": "ens33"
},
{
"netid": "u_dgr",
"state": "UNCONN",
"recv_q": "0",
"send_q": "0",
"local_port": "93066",
"peer_address": "*",
"peer_port": "0",
"path": "/run/user/1000/systemd/notify"
},
{
"netid": "u_seq",
"state": "LISTEN",
"recv_q": "0",
"send_q": "128",
"local_port": "20699",
"peer_address": "*",
"peer_port": "0",
"path": "/run/udev/control"
},
...
{
"netid": "icmp6",
"state": "UNCONN",
"recv_q": "0",
"send_q": "0",
"local_address": "*",
"local_port": "ipv6-icmp",
"peer_address": "*",
"peer_port": "*",
"interface": "ens33"
},
{
"netid": "udp",
"state": "UNCONN",
"recv_q": "0",
"send_q": "0",
"local_address": "127.0.0.53",
"local_port": "domain",
"peer_address": "0.0.0.0",
"peer_port": "*",
"interface": "lo"
},
{
"netid": "tcp",
"state": "LISTEN",
"recv_q": "0",
"send_q": "128",
"local_address": "127.0.0.53",
"local_port": "domain",
"peer_address": "0.0.0.0",
"peer_port": "*",
"interface": "lo"
},
{
"netid": "tcp",
"state": "LISTEN",
"recv_q": "0",
"send_q": "128",
"local_address": "0.0.0.0",
"local_port": "ssh",
"peer_address": "0.0.0.0",
"peer_port": "*"
},
{
"netid": "tcp",
"state": "LISTEN",
"recv_q": "0",
"send_q": "128",
"local_address": "[::]",
"local_port": "ssh",
"peer_address": "[::]",
"peer_port": "*"
},
{
"netid": "v_str",
"state": "ESTAB",
"recv_q": "0",
"send_q": "0",
"local_address": "999900439",
"local_port": "1023",
"peer_address": "0",
"peer_port": "976"
}
]
## info
```python
info(self, /, *args, **kwargs)
```
## 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:
[
{
"netid": string,
"state": string,
"recv_q": integer,
"send_q": integer,
"local_address": string,
"local_port": string,
"local_port_num": integer,
"peer_address": string,
"peer_port": string,
"peer_port_num": integer,
"interface": string,
"link_layer" string,
"channel": string,
"path": string,
"pid": integer
}
]
Information from https://www.cyberciti.biz/files/ss.html used to define field names
## 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.

164
docs/parsers/stat.md Normal file
View File

@@ -0,0 +1,164 @@
# jc.parsers.stat
jc - JSON CLI output utility stat Parser
Usage:
specify --stat as the first argument if the piped input is coming from stat
Compatibility:
'linux'
Examples:
$ stat /bin/* | jc --stat -p
[
{
"file": "/bin/bash",
"size": 1113504,
"blocks": 2176,
"io_blocks": 4096,
"type": "regular file",
"device": "802h/2050d",
"inode": 131099,
"links": 1,
"access": "0755",
"flags": "-rwxr-xr-x",
"uid": 0,
"user": "root",
"gid": 0,
"group": "root",
"access_time": "2019-11-14 08:18:03.509681766 +0000",
"modify_time": "2019-06-06 22:28:15.000000000 +0000",
"change_time": "2019-08-12 17:21:29.521945390 +0000",
"birth_time": null
},
{
"file": "/bin/btrfs",
"size": 716464,
"blocks": 1400,
"io_blocks": 4096,
"type": "regular file",
"device": "802h/2050d",
"inode": 131100,
"links": 1,
"access": "0755",
"flags": "-rwxr-xr-x",
"uid": 0,
"user": "root",
"gid": 0,
"group": "root",
"access_time": "2019-11-14 08:18:28.990834276 +0000",
"modify_time": "2018-03-12 23:04:27.000000000 +0000",
"change_time": "2019-08-12 17:21:29.545944399 +0000",
"birth_time": null
},
...
]
$ stat /bin/* | jc --stat -p -r
[
{
"file": "/bin/bash",
"size": "1113504",
"blocks": "2176",
"io_blocks": "4096",
"type": "regular file",
"device": "802h/2050d",
"inode": "131099",
"links": "1",
"access": "0755",
"flags": "-rwxr-xr-x",
"uid": "0",
"user": "root",
"gid": "0",
"group": "root",
"access_time": "2019-11-14 08:18:03.509681766 +0000",
"modify_time": "2019-06-06 22:28:15.000000000 +0000",
"change_time": "2019-08-12 17:21:29.521945390 +0000",
"birth_time": null
},
{
"file": "/bin/btrfs",
"size": "716464",
"blocks": "1400",
"io_blocks": "4096",
"type": "regular file",
"device": "802h/2050d",
"inode": "131100",
"links": "1",
"access": "0755",
"flags": "-rwxr-xr-x",
"uid": "0",
"user": "root",
"gid": "0",
"group": "root",
"access_time": "2019-11-14 08:18:28.990834276 +0000",
"modify_time": "2018-03-12 23:04:27.000000000 +0000",
"change_time": "2019-08-12 17:21:29.545944399 +0000",
"birth_time": null
},
..
]
## info
```python
info(self, /, *args, **kwargs)
```
## 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:
[
{
"file": string,
"link_to" string,
"size": integer,
"blocks": integer,
"io_blocks": integer,
"type": string,
"device": string,
"inode": integer,
"links": integer,
"access": string,
"flags": string,
"uid": integer,
"user": string,
"gid": integer,
"group": string,
"access_time": string, # - = null
"modify_time": string, # - = null
"change_time": string, # - = null
"birth_time": string # - = null
}
]
## 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.

86
docs/parsers/systemctl.md Normal file
View File

@@ -0,0 +1,86 @@
# jc.parsers.systemctl
jc - JSON CLI output utility systemctl Parser
Usage:
specify --systemctl as the first argument if the piped input is coming from systemctl
Compatibility:
'linux'
Examples:
$ systemctl -a | jc --systemctl -p
[
{
"unit": "proc-sys-fs-binfmt_misc.automount",
"load": "loaded",
"active": "active",
"sub": "waiting",
"description": "Arbitrary Executable File Formats File System Automount Point"
},
{
"unit": "dev-block-8:2.device",
"load": "loaded",
"active": "active",
"sub": "plugged",
"description": "LVM PV 3klkIj-w1qk-DkJi-0XBJ-y3o7-i2Ac-vHqWBM on /dev/sda2 2"
},
{
"unit": "dev-cdrom.device",
"load": "loaded",
"active": "active",
"sub": "plugged",
"description": "VMware_Virtual_IDE_CDROM_Drive"
},
...
]
## info
```python
info(self, /, *args, **kwargs)
```
## 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:
[
{
"unit": string,
"load": string,
"active": string,
"sub": string,
"description": 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.

View File

@@ -0,0 +1,104 @@
# jc.parsers.systemctl_lj
jc - JSON CLI output utility systemctl-lj Parser
Usage:
specify --systemctl-lj as the first argument if the piped input is coming from systemctl list-jobs
Compatibility:
'linux'
Examples:
$ systemctl list-jobs| jc --systemctl-lj -p
[
{
"job": 3543,
"unit": "nginxAfterGlusterfs.service",
"type": "start",
"state": "waiting"
},
{
"job": 3545,
"unit": "glusterReadyForLocalhostMount.service",
"type": "start",
"state": "running"
},
{
"job": 3506,
"unit": "nginx.service",
"type": "start",
"state": "waiting"
}
]
$ systemctl list-jobs| jc --systemctl-lj -p -r
[
{
"job": "3543",
"unit": "nginxAfterGlusterfs.service",
"type": "start",
"state": "waiting"
},
{
"job": "3545",
"unit": "glusterReadyForLocalhostMount.service",
"type": "start",
"state": "running"
},
{
"job": "3506",
"unit": "nginx.service",
"type": "start",
"state": "waiting"
}
]
## info
```python
info(self, /, *args, **kwargs)
```
## 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:
[
{
"job": integer,
"unit": string,
"type": string,
"state": 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.

View File

@@ -0,0 +1,78 @@
# jc.parsers.systemctl_ls
jc - JSON CLI output utility systemctl-ls Parser
Usage:
specify --systemctl-ls as the first argument if the piped input is coming from systemctl list-sockets
Compatibility:
'linux'
Examples:
$ systemctl list-sockets | jc --systemctl-ls -p
[
{
"listen": "/dev/log",
"unit": "systemd-journald.socket",
"activates": "systemd-journald.service"
},
{
"listen": "/run/dbus/system_bus_socket",
"unit": "dbus.socket",
"activates": "dbus.service"
},
{
"listen": "/run/dmeventd-client",
"unit": "dm-event.socket",
"activates": "dm-event.service"
},
...
]
## info
```python
info(self, /, *args, **kwargs)
```
## 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:
[
{
"listen": string,
"unit": string,
"activates": 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.

View File

@@ -0,0 +1,74 @@
# jc.parsers.systemctl_luf
jc - JSON CLI output utility systemctl-luf Parser
Usage:
specify --systemctl-luf as the first argument if the piped input is coming from systemctl list-unit-files
Compatibility:
'linux'
Examples:
$ systemctl list-unit-files | jc --systemctl-luf -p
[
{
"unit_file": "proc-sys-fs-binfmt_misc.automount",
"state": "static"
},
{
"unit_file": "dev-hugepages.mount",
"state": "static"
},
{
"unit_file": "dev-mqueue.mount",
"state": "static"
},
...
]
## info
```python
info(self, /, *args, **kwargs)
```
## 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:
[
{
"unit_file": string,
"state": 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.

77
docs/parsers/uname.md Normal file
View File

@@ -0,0 +1,77 @@
# jc.parsers.uname
jc - JSON CLI output utility uname Parser
Usage:
specify --uname as the first argument if the piped input is coming from uname
Limitations:
must use 'uname -a'
Compatibility:
'linux', 'darwin'
Example:
$ uname -a | jc --uname -p
{
"kernel_name": "Linux",
"node_name": "user-ubuntu",
"kernel_release": "4.15.0-65-generic",
"operating_system": "GNU/Linux",
"hardware_platform": "x86_64",
"processor": "x86_64",
"machine": "x86_64",
"kernel_version": "#74-Ubuntu SMP Tue Sep 17 17:06:04 UTC 2019"
}
## info
```python
info(self, /, *args, **kwargs)
```
## 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:
{
"kernel_name": string,
"node_name": string,
"kernel_release": string,
"operating_system": string,
"hardware_platform": string,
"processor": string,
"machine": string,
"kernel_version": 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.

79
docs/parsers/uptime.md Normal file
View File

@@ -0,0 +1,79 @@
# jc.parsers.uptime
jc - JSON CLI output utility uptime Parser
Usage:
specify --uptime as the first argument if the piped input is coming from uptime
Compatibility:
'linux', 'darwin', 'cygwin', 'aix', 'freebsd'
Example:
$ uptime | jc --uptime -p
{
"time": "11:30:44",
"uptime": "1 day, 21:17",
"users": 1,
"load_1m": 0.01,
"load_5m": 0.04,
"load_15m": 0.05
}
$ uptime | jc --uptime -p -r
{
"time": "11:31:09",
"uptime": "1 day, 21:17",
"users": "1",
"load_1m": "0.00",
"load_5m": "0.04",
"load_15m": "0.05"
}
## info
```python
info(self, /, *args, **kwargs)
```
## 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:
{
"time": string,
"uptime": string,
"users": integer,
"load_1m": float,
"load_5m": float,
"load_15m": 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

131
docs/parsers/w.md Normal file
View File

@@ -0,0 +1,131 @@
# jc.parsers.w
jc - JSON CLI output utility w Parser
Usage:
specify --w as the first argument if the piped input is coming from w
Compatibility:
'linux', 'darwin', 'cygwin', 'aix', 'freebsd'
Examples:
$ w | jc --w -p
[
{
"user": "root",
"tty": "tty1",
"from": null,
"login_at": "07:49",
"idle": "1:15m",
"jcpu": "0.00s",
"pcpu": "0.00s",
"what": "-bash"
},
{
"user": "root",
"tty": "ttyS0",
"from": null,
"login_at": "06:24",
"idle": "0.00s",
"jcpu": "0.43s",
"pcpu": "0.00s",
"what": "w"
},
{
"user": "root",
"tty": "pts/0",
"from": "192.168.71.1",
"login_at": "06:29",
"idle": "2:35m",
"jcpu": "0.00s",
"pcpu": "0.00s",
"what": "-bash"
}
]
$ w | jc --w -p -r
[
{
"user": "kbrazil",
"tty": "tty1",
"from": "-",
"login_at": "07:49",
"idle": "1:16m",
"jcpu": "0.00s",
"pcpu": "0.00s",
"what": "-bash"
},
{
"user": "kbrazil",
"tty": "ttyS0",
"from": "-",
"login_at": "06:24",
"idle": "2.00s",
"jcpu": "0.46s",
"pcpu": "0.00s",
"what": "w"
},
{
"user": "kbrazil",
"tty": "pts/0",
"from": "192.168.71.1",
"login_at": "06:29",
"idle": "2:36m",
"jcpu": "0.00s",
"pcpu": "0.00s",
"what": "-bash"
}
]
## info
```python
info(self, /, *args, **kwargs)
```
## 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:
[
{
"user": string, # '-'' = null
"tty": string, # '-'' = null
"from": string, # '-'' = null
"login_at": string, # '-'' = null
"idle": string, # '-'' = null
"jcpu": string,
"pcpu": string,
"what": string # '-'' = null
}
]
## 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.

99
docs/parsers/xml.md Normal file
View File

@@ -0,0 +1,99 @@
# jc.parsers.xml
jc - JSON CLI output utility XML Parser
Usage:
specify --xml as the first argument if the piped input is coming from an XML file
Compatibility:
'linux', 'darwin', 'cygwin', 'win32', 'aix', 'freebsd'
Examples:
$ cat cd_catalog.xml
<?xml version="1.0" encoding="UTF-8"?>
<CATALOG>
<CD>
<TITLE>Empire Burlesque</TITLE>
<ARTIST>Bob Dylan</ARTIST>
<COUNTRY>USA</COUNTRY>
<COMPANY>Columbia</COMPANY>
<PRICE>10.90</PRICE>
<YEAR>1985</YEAR>
</CD>
<CD>
<TITLE>Hide your heart</TITLE>
<ARTIST>Bonnie Tyler</ARTIST>
<COUNTRY>UK</COUNTRY>
<COMPANY>CBS Records</COMPANY>
<PRICE>9.90</PRICE>
<YEAR>1988</YEAR>
</CD>
...
$ cat cd_catalog.xml | jc --xml -p
{
"CATALOG": {
"CD": [
{
"TITLE": "Empire Burlesque",
"ARTIST": "Bob Dylan",
"COUNTRY": "USA",
"COMPANY": "Columbia",
"PRICE": "10.90",
"YEAR": "1985"
},
{
"TITLE": "Hide your heart",
"ARTIST": "Bonnie Tyler",
"COUNTRY": "UK",
"COMPANY": "CBS Records",
"PRICE": "9.90",
"YEAR": "1988"
},
...
}
## info
```python
info(self, /, *args, **kwargs)
```
## process
```python
process(proc_data)
```
Final processing to conform to the schema.
Parameters:
proc_data: (dictionary) raw structured data to process
Returns:
Dictionary representing an XML document:
{
XML Document converted to a Dictionary
See https://github.com/martinblech/xmltodict for details
}
## 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.

113
docs/parsers/yaml.md Normal file
View File

@@ -0,0 +1,113 @@
# jc.parsers.yaml
jc - JSON CLI output utility YAML Parser
Usage:
specify --yaml as the first argument if the piped input is coming from a YAML file
Compatibility:
'linux', 'darwin', 'cygwin', 'win32', 'aix', 'freebsd'
Examples:
$ cat istio-mtls-permissive.yaml
apiVersion: "authentication.istio.io/v1alpha1"
kind: "Policy"
metadata:
name: "default"
namespace: "default"
spec:
peers:
- mtls: {}
---
apiVersion: "networking.istio.io/v1alpha3"
kind: "DestinationRule"
metadata:
name: "default"
namespace: "default"
spec:
host: "*.default.svc.cluster.local"
trafficPolicy:
tls:
mode: ISTIO_MUTUAL
$ cat istio-mtls-permissive.yaml | jc --yaml -p
[
{
"apiVersion": "authentication.istio.io/v1alpha1",
"kind": "Policy",
"metadata": {
"name": "default",
"namespace": "default"
},
"spec": {
"peers": [
{
"mtls": {}
}
]
}
},
{
"apiVersion": "networking.istio.io/v1alpha3",
"kind": "DestinationRule",
"metadata": {
"name": "default",
"namespace": "default"
},
"spec": {
"host": "*.default.svc.cluster.local",
"trafficPolicy": {
"tls": {
"mode": "ISTIO_MUTUAL"
}
}
}
}
]
## info
```python
info(self, /, *args, **kwargs)
```
## 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. Each dictionary represents a YAML document:
[
{
YAML Document converted to a Dictionary
See https://pypi.org/project/ruamel.yaml for details
}
]
## 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.

68
docs/readme.md Normal file
View File

@@ -0,0 +1,68 @@
# jc
JC - JSON CLI output utility
* kellyjonbrazil@gmail.com
This package serializes the output of many standard unix command line tools to JSON format.
CLI Example:
$ ls -l /usr/bin | jc --ls -p
[
{
"filename": "apropos",
"link_to": "whatis",
"flags": "lrwxrwxrwx.",
"links": 1,
"owner": "root",
"group": "root",
"size": 6,
"date": "Aug 15 10:53"
},
{
"filename": "ar",
"flags": "-rwxr-xr-x.",
"links": 1,
"owner": "root",
"group": "root",
"size": 62744,
"date": "Aug 8 16:14"
},
{
"filename": "arch",
"flags": "-rwxr-xr-x.",
"links": 1,
"owner": "root",
"group": "root",
"size": 33080,
"date": "Aug 19 23:25"
},
...
]
Module Example:
>>> import jc.parsers.ls
>>>
>>> data='''-rwxr-xr-x 1 root wheel 23648 May 3 22:26 cat
... -rwxr-xr-x 1 root wheel 30016 May 3 22:26 chmod
... -rwxr-xr-x 1 root wheel 29024 May 3 22:26 cp
... -rwxr-xr-x 1 root wheel 375824 May 3 22:26 csh
... -rwxr-xr-x 1 root wheel 28608 May 3 22:26 date
... -rwxr-xr-x 1 root wheel 32000 May 3 22:26 dd
... -rwxr-xr-x 1 root wheel 23392 May 3 22:26 df
... -rwxr-xr-x 1 root wheel 18128 May 3 22:26 echo'''
>>>
>>> jc.parsers.ls.parse(data)
[{'filename': 'cat', 'flags': '-rwxr-xr-x', 'links': 1, 'owner': 'root', 'group': 'wheel', 'size': 23648,
'date': 'May 3 22:26'}, {'filename': 'chmod', 'flags': '-rwxr-xr-x', 'links': 1, 'owner': 'root',
'group': 'wheel', 'size': 30016, 'date': 'May 3 22:26'}, {'filename': 'cp', 'flags': '-rwxr-xr-x',
'links': 1, 'owner': 'root', 'group': 'wheel', 'size': 29024, 'date': 'May 3 22:26'}, {'filename': 'csh',
'flags': '-rwxr-xr-x', 'links': 1, 'owner': 'root', 'group': 'wheel', 'size': 375824, 'date': 'May 3
22:26'}, {'filename': 'date', 'flags': '-rwxr-xr-x', 'links': 1, 'owner': 'root', 'group': 'wheel',
'size': 28608, 'date': 'May 3 22:26'}, {'filename': 'dd', 'flags': '-rwxr-xr-x', 'links': 1, 'owner':
'root', 'group': 'wheel', 'size': 32000, 'date': 'May 3 22:26'}, {'filename': 'df', 'flags':
'-rwxr-xr-x', 'links': 1, 'owner': 'root', 'group': 'wheel', 'size': 23392, 'date': 'May 3 22:26'},
{'filename': 'echo', 'flags': '-rwxr-xr-x', 'links': 1, 'owner': 'root', 'group': 'wheel', 'size': 18128,
'date': 'May 3 22:26'}]

50
docs/utils.md Normal file
View File

@@ -0,0 +1,50 @@
# utils
jc - JSON CLI output utility utils
## warning_message
```python
warning_message(message)
```
Prints a warning message for non-fatal issues
Parameters:
message: (string) text of message
Returns:
no return, just prints output to STDERR
## error_message
```python
error_message(message)
```
Prints an error message for fatal issues
Parameters:
message: (string) text of message
Returns:
no return, just prints output to STDERR
## compatibility
```python
compatibility(mod_name, compatible)
```
Checks for the parser's compatibility with the running OS platform.
Parameters:
mod_name: (string) __name__ of the calling module
compatible: (list) sys.platform name(s) compatible with the parser
compatible options:
linux, darwin, cygwin, win32, aix, freebsd
Returns:
no return, just prints output to STDERR

2
install.sh Executable file
View File

@@ -0,0 +1,2 @@
#!/bin/bash
pip3 install --upgrade --user -e .

View File

@@ -1,61 +1,69 @@
"""JC - JSON CLI output utility
v0.1
* kellyjonbrazil@gmail.com
This module serializes standard unix command line output to structured JSON
output.
This package serializes the output of many standard unix command line tools to JSON format.
Example:
CLI Example:
$ ls -al | jc | jq .
[
{
"filename": ".",
"suffix": Null,
"bytes": 224,
"date_updated": "Oct 1 12:09",
"owner_user": "joeuser",
"owner_group": "staff",
"flags": "drwxr-xr-x+",
"link_to": Null,
"links": 47
},
{
"filename": "..",
"suffix": Null,
"bytes": 224,
"date_updated": "Oct 1 12:09",
"owner_user": "admin",
"owner_group": "root",
"flags": "drwxr-xr-x",
"link_to": Null,
"links": 7
},
{
"filename": "testfile.txt",
"suffix": "txt",
"bytes": 14686,
"date_updated": "Oct 1 12:09",
"owner_user": "joeuser",
"owner_group": "staff",
"flags": "-rwxr-xr-x@",
"link_to": Null,
"links": 1
},
{
"filename": "ncat",
"suffix": Null,
"bytes": 14686,
"date_updated": "Oct 1 12:09",
"owner_user": "joeuser",
"owner_group": "staff",
"flags": "lrwxr-xr-x",
"link_to": "../Cellar/nmap/7.70/bin/ncat",
"links": 1
}
]
$ ls -l /usr/bin | jc --ls -p
[
{
"filename": "apropos",
"link_to": "whatis",
"flags": "lrwxrwxrwx.",
"links": 1,
"owner": "root",
"group": "root",
"size": 6,
"date": "Aug 15 10:53"
},
{
"filename": "ar",
"flags": "-rwxr-xr-x.",
"links": 1,
"owner": "root",
"group": "root",
"size": 62744,
"date": "Aug 8 16:14"
},
{
"filename": "arch",
"flags": "-rwxr-xr-x.",
"links": 1,
"owner": "root",
"group": "root",
"size": 33080,
"date": "Aug 19 23:25"
},
...
]
Module Example:
>>> import jc.parsers.ls
>>>
>>> data='''-rwxr-xr-x 1 root wheel 23648 May 3 22:26 cat
... -rwxr-xr-x 1 root wheel 30016 May 3 22:26 chmod
... -rwxr-xr-x 1 root wheel 29024 May 3 22:26 cp
... -rwxr-xr-x 1 root wheel 375824 May 3 22:26 csh
... -rwxr-xr-x 1 root wheel 28608 May 3 22:26 date
... -rwxr-xr-x 1 root wheel 32000 May 3 22:26 dd
... -rwxr-xr-x 1 root wheel 23392 May 3 22:26 df
... -rwxr-xr-x 1 root wheel 18128 May 3 22:26 echo'''
>>>
>>> jc.parsers.ls.parse(data)
[{'filename': 'cat', 'flags': '-rwxr-xr-x', 'links': 1, 'owner': 'root', 'group': 'wheel', 'size': 23648,
'date': 'May 3 22:26'}, {'filename': 'chmod', 'flags': '-rwxr-xr-x', 'links': 1, 'owner': 'root',
'group': 'wheel', 'size': 30016, 'date': 'May 3 22:26'}, {'filename': 'cp', 'flags': '-rwxr-xr-x',
'links': 1, 'owner': 'root', 'group': 'wheel', 'size': 29024, 'date': 'May 3 22:26'}, {'filename': 'csh',
'flags': '-rwxr-xr-x', 'links': 1, 'owner': 'root', 'group': 'wheel', 'size': 375824, 'date': 'May 3
22:26'}, {'filename': 'date', 'flags': '-rwxr-xr-x', 'links': 1, 'owner': 'root', 'group': 'wheel',
'size': 28608, 'date': 'May 3 22:26'}, {'filename': 'dd', 'flags': '-rwxr-xr-x', 'links': 1, 'owner':
'root', 'group': 'wheel', 'size': 32000, 'date': 'May 3 22:26'}, {'filename': 'df', 'flags':
'-rwxr-xr-x', 'links': 1, 'owner': 'root', 'group': 'wheel', 'size': 23392, 'date': 'May 3 22:26'},
{'filename': 'echo', 'flags': '-rwxr-xr-x', 'links': 1, 'owner': 'root', 'group': 'wheel', 'size': 18128,
'date': 'May 3 22:26'}]
"""
name = 'jc'

322
jc/cli.py Normal file
View File

@@ -0,0 +1,322 @@
#!/usr/bin/env python3
"""jc - JSON CLI output utility
JC cli module
"""
import sys
import os
import shlex
import importlib
import textwrap
import signal
import json
import jc.utils
class info():
version = '1.7.4'
description = 'jc cli output JSON conversion tool'
author = 'Kelly Brazil'
author_email = 'kellyjonbrazil@gmail.com'
__version__ = info.version
parsers = [
'arp',
'crontab',
'crontab-u',
'df',
'dig',
'du',
'env',
'free',
'fstab',
'history',
'hosts',
'id',
'ifconfig',
'ini',
'iptables',
'jobs',
'ls',
'lsblk',
'lsmod',
'lsof',
'mount',
'netstat',
'pip-list',
'pip-show',
'ps',
'route',
'ss',
'stat',
'systemctl',
'systemctl-lj',
'systemctl-ls',
'systemctl-luf',
'uname',
'uptime',
'w',
'xml',
'yaml'
]
def ctrlc(signum, frame):
"""exit with error on SIGINT"""
sys.exit(1)
def parser_shortname(parser_argument):
"""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 f'--{parser}'
def parser_mod_shortname(parser):
"""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))
def parsers_text(indent=0, pad=0):
"""return the argument and description information from each parser"""
ptext = ''
for parser in parsers:
parser_arg = parser_argument(parser)
parser_mod = parser_module(parser)
if hasattr(parser_mod, 'info'):
parser_desc = parser_mod.info.description
padding = pad - len(parser_arg)
padding_char = ' '
indent_text = padding_char * indent
padding_text = padding_char * padding
ptext += indent_text + parser_arg + padding_text + parser_desc + '\n'
return ptext
def about_jc():
"""return jc info and the contents of each parser.info as a dictionary"""
parser_list = []
for parser in parsers:
parser_mod = parser_module(parser)
if hasattr(parser_mod, 'info'):
info_dict = {}
info_dict['name'] = parser_mod.__name__.split('.')[-1]
info_dict['argument'] = parser_argument(parser)
parser_entry = vars(parser_mod.info)
for k, v in parser_entry.items():
if not k.startswith('__'):
info_dict[k] = v
parser_list.append(info_dict)
return {
'name': 'jc',
'version': info.version,
'description': info.description,
'author': info.author,
'author_email': info.author_email,
'parser_count': len(parser_list),
'parsers': parser_list
}
def helptext(message):
"""return the help text with the list of parsers"""
parsers_string = parsers_text(indent=12, pad=17)
helptext_string = f'''
jc: {message}
Usage: COMMAND | jc PARSER [OPTIONS]
or
COMMAND | jc [OPTIONS] PARSER
or magic syntax:
jc [OPTIONS] COMMAND
Parsers:
{parsers_string}
Options:
-a about jc
-d debug - show trace messages
-p pretty print output
-q quiet - suppress warnings
-r raw JSON output
Example:
ls -al | jc --ls -p
or using the magic syntax:
jc -p ls -al
'''
print(textwrap.dedent(helptext_string), file=sys.stderr)
def json_out(data, pretty=False):
if pretty:
print(json.dumps(data, indent=2))
else:
print(json.dumps(data))
def magic():
"""Parse with magic syntax: jc -p ls -al"""
if len(sys.argv) > 1 and not sys.argv[1].startswith('--'):
parser_info = about_jc()['parsers']
# correctly parse escape characters and spaces with shlex
args_given = " ".join(map(shlex.quote, sys.argv[1:])).split()
options = []
found_parser = None
# find the options
if args_given[0].startswith('-'):
p = 0
for i, arg in list(enumerate(args_given)):
# parser found - use standard syntax
if arg.startswith('--'):
return
# option found - populate option list
elif arg.startswith('-'):
options.append(args_given.pop(i - p)[1:])
p = p + 1
# command found if iterator didn't already stop - stop iterating
else:
break
# find the command and parser
for parser in parser_info:
if 'magic_commands' in parser:
# first pass for two word commands: e.g. 'pip list'
for magic_command in parser['magic_commands']:
try:
if ' '.join(args_given[0:2]) == magic_command:
found_parser = parser['argument']
break
# No command found - go to next loop (for cases like 'jc -a')
except Exception:
break
# second pass for one word commands: e.g. 'ls'
if not found_parser:
for magic_command in parser['magic_commands']:
try:
if args_given[0] == magic_command:
found_parser = parser['argument']
break
# No command found - use standard syntax (for cases like 'jc -a')
except Exception:
return
# construct a new command line using the standard syntax: COMMAND | jc --PARSER -OPTIONS
run_command = ' '.join(args_given)
if found_parser:
if options:
cmd_options = '-' + ''.join(options)
else:
cmd_options = ''
whole_command = ' '.join([run_command, '|', 'jc', found_parser, cmd_options])
os.system(whole_command)
exit()
else:
helptext(f'parser not found for "{run_command}"')
sys.exit(1)
def main():
# break on ctrl-c keyboard interrupt
signal.signal(signal.SIGINT, ctrlc)
# try magic syntax first: e.g. jc -p ls -al
magic()
options = []
debug = False
pretty = False
quiet = False
raw = False
# options
for opt in sys.argv:
if opt.startswith('-') and not opt.startswith('--'):
for flag in opt[1:]:
options.append(flag)
if 'd' in options:
debug = True
if 'p' in options:
pretty = True
if 'q' in options:
quiet = True
if 'r' in options:
raw = True
if 'a' in options:
json_out(about_jc(), pretty=pretty)
exit()
if sys.stdin.isatty():
helptext('missing piped data')
sys.exit(1)
data = sys.stdin.read()
found = False
if debug:
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)
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:
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.')
sys.exit(1)
if not found:
helptext('missing or incorrect arguments')
sys.exit(1)
json_out(result, pretty=pretty)
if __name__ == '__main__':
main()

View File

@@ -1,43 +0,0 @@
#!/usr/bin/env python3
"""jc - JSON CLI output utility
Main input module
"""
import sys
import json
import jc.parsers.ifconfig
import jc.parsers.ls
import jc.parsers.netstat
def main():
pretty = False
data = sys.stdin.read()
if len(sys.argv) < 2:
print(f'\nError: jc\n Must specify parser. (e.g. --ls, --netstat, --ifconfig, etc.)')
print(' Use -p to pretty print')
print(f'\nExample: ls -al | jc --ls -p\n')
exit()
arg = sys.argv[1]
if len(sys.argv) > 2:
if sys.argv[2] == '-p':
pretty = True
if arg == '--ifconfig':
result = jc.parsers.ifconfig.parse(data)
elif arg == '--ls':
result = jc.parsers.ls.parse(data)
elif arg == '--netstat':
result = jc.parsers.netstat.parse(data)
# output resulting dictionary as json
if pretty:
print(json.dumps(result, indent=2))
else:
print(json.dumps(result))
if __name__ == '__main__':
main()

210
jc/parsers/arp.py Normal file
View File

@@ -0,0 +1,210 @@
"""jc - JSON CLI output utility arp Parser
Usage:
specify --arp as the first argument if the piped input is coming from:
arp
or
arp -a
Compatibility:
'linux', 'aix', 'freebsd', 'darwin'
Examples:
$ arp | jc --arp -p
[
{
"address": "192.168.71.254",
"hwtype": "ether",
"hwaddress": "00:50:56:f0:98:26",
"flags_mask": "C",
"iface": "ens33"
},
{
"address": "gateway",
"hwtype": "ether",
"hwaddress": "00:50:56:f7:4a:fc",
"flags_mask": "C",
"iface": "ens33"
}
]
$ arp | jc --arp -p -r
[
{
"address": "gateway",
"hwtype": "ether",
"hwaddress": "00:50:56:f7:4a:fc",
"flags_mask": "C",
"iface": "ens33"
},
{
"address": "192.168.71.254",
"hwtype": "ether",
"hwaddress": "00:50:56:fe:7a:b4",
"flags_mask": "C",
"iface": "ens33"
}
]
$ arp -a | jc --arp -p
[
{
"name": null,
"address": "192.168.71.254",
"hwtype": "ether",
"hwaddress": "00:50:56:f0:98:26",
"iface": "ens33"
},
{
"name": "gateway",
"address": "192.168.71.2",
"hwtype": "ether",
"hwaddress": "00:50:56:f7:4a:fc",
"iface": "ens33"
}
]
$ arp -a | jc --arp -p -r
[
{
"name": "?",
"address": "192.168.71.254",
"hwtype": "ether",
"hwaddress": "00:50:56:fe:7a:b4",
"iface": "ens33"
},
{
"name": "_gateway",
"address": "192.168.71.2",
"hwtype": "ether",
"hwaddress": "00:50:56:f7:4a:fc",
"iface": "ens33"
}
]
"""
import jc.utils
import jc.parsers.universal
class info():
version = '1.1'
description = 'arp command parser'
author = 'Kelly Brazil'
author_email = 'kellyjonbrazil@gmail.com'
# compatible options: linux, darwin, cygwin, win32, aix, freebsd
compatible = ['linux', 'aix', 'freebsd', 'darwin']
magic_commands = ['arp']
__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:
[
{
"name": string,
"address": string,
"hwtype": string,
"hwaddress": string,
"flags_mask": string,
"iface": string
}
]
"""
# in BSD style, change name to null if it is a question mark
for entry in proc_data:
if 'name' in entry and entry['name'] == '?':
entry['name'] = 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)
cleandata = data.splitlines()
# remove final Entries row if -v was used
if cleandata[-1].find('Entries:') == 0:
cleandata.pop(-1)
# detect if osx style was used
if cleandata[0].find(' ifscope ') != -1:
raw_output = []
for line in cleandata:
line = line.split()
output_line = {}
output_line['name'] = line[0]
output_line['address'] = line[1].lstrip('(').rstrip(')')
output_line['hwtype'] = line[-1].lstrip('[').rstrip(']')
output_line['hwaddress'] = line[3]
output_line['iface'] = line[5]
raw_output.append(output_line)
if raw:
return raw_output
else:
return process(raw_output)
# detect if linux style was used
elif cleandata[0].find('Address') == 0:
# 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
else:
raw_output = []
for line in cleandata:
line = line.split()
output_line = {}
output_line['name'] = line[0]
output_line['address'] = line[1].lstrip('(').rstrip(')')
output_line['hwtype'] = line[4].lstrip('[').rstrip(']')
output_line['hwaddress'] = line[3]
output_line['iface'] = line[6]
raw_output.append(output_line)
if raw:
return raw_output
else:
return process(raw_output)

270
jc/parsers/crontab.py Normal file
View File

@@ -0,0 +1,270 @@
"""jc - JSON CLI output utility crontab command and file Parser
Usage:
specify --crontab as the first argument if the piped input is coming from crontab -l or a crontab file
Compatibility:
'linux', 'darwin', 'aix', 'freebsd'
Examples:
$ crontab -l | jc --crontab -p
{
"variables": [
{
"name": "MAILTO",
"value": "root"
},
{
"name": "PATH",
"value": "/sbin:/bin:/usr/sbin:/usr/bin"
},
{
"name": "SHELL",
"value": "/bin/bash"
}
],
"schedule": [
{
"minute": [
"5"
],
"hour": [
"10-11",
"22"
],
"day_of_month": [
"*"
],
"month": [
"*"
],
"day_of_week": [
"*"
],
"command": "/var/www/devdaily.com/bin/mk-new-links.php"
},
{
"minute": [
"30"
],
"hour": [
"4/2"
],
"day_of_month": [
"*"
],
"month": [
"*"
],
"day_of_week": [
"*"
],
"command": "/var/www/devdaily.com/bin/create-all-backups.sh"
},
{
"occurrence": "yearly",
"command": "/home/maverick/bin/annual-maintenance"
},
{
"occurrence": "reboot",
"command": "/home/cleanup"
},
{
"occurrence": "monthly",
"command": "/home/maverick/bin/tape-backup"
}
]
}
$ cat /etc/crontab | jc --crontab -p -r
{
"variables": [
{
"name": "MAILTO",
"value": "root"
},
{
"name": "PATH",
"value": "/sbin:/bin:/usr/sbin:/usr/bin"
},
{
"name": "SHELL",
"value": "/bin/bash"
}
],
"schedule": [
{
"minute": "5",
"hour": "10-11,22",
"day_of_month": "*",
"month": "*",
"day_of_week": "*",
"command": "/var/www/devdaily.com/bin/mk-new-links.php"
},
{
"minute": "30",
"hour": "4/2",
"day_of_month": "*",
"month": "*",
"day_of_week": "*",
"command": "/var/www/devdaily.com/bin/create-all-backups.sh"
},
{
"occurrence": "yearly",
"command": "/home/maverick/bin/annual-maintenance"
},
{
"occurrence": "reboot",
"command": "/home/cleanup"
},
{
"occurrence": "monthly",
"command": "/home/maverick/bin/tape-backup"
}
]
}
"""
import jc.utils
import jc.parsers.universal
class info():
version = '1.1'
description = 'crontab command and file 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', 'darwin', 'aix', 'freebsd']
magic_commands = ['crontab']
__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:
{
"variables": [
"name": string,
"value": string
],
"schedule": [
{
"occurrence" string,
"minute": [
string
],
"hour": [
string
],
"day_of_month": [
string
],
"month": [
string
],
"day_of_week": [
string
],
"occurrence": string,
"command": string
}
]
}
"""
# put itmes in lists
try:
for entry in proc_data['schedule']:
entry['minute'] = entry['minute'].split(',')
entry['hour'] = entry['hour'].split(',')
entry['day_of_month'] = entry['day_of_month'].split(',')
entry['month'] = entry['month'].split(',')
entry['day_of_week'] = entry['day_of_week'].split(',')
except (KeyError):
pass
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:
Dictionary. Raw or processed structured data.
"""
if not quiet:
jc.utils.compatibility(__name__, info.compatible)
raw_output = {}
cleandata = data.splitlines()
# Clear any blank lines
cleandata = list(filter(None, cleandata))
# Clear any commented lines
for i, line in reversed(list(enumerate(cleandata))):
if line.strip().find('#') == 0:
cleandata.pop(i)
# Pop any variable assignment lines
cron_var = []
for i, line in reversed(list(enumerate(cleandata))):
if line.find('=') != -1:
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})
raw_output['variables'] = cron_var
# 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})
# Add header row for parsing
cleandata[:0] = ['minute hour day_of_month month day_of_week command']
if len(cleandata) > 1:
cron_list = jc.parsers.universal.simple_table_parse(cleandata)
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
else:
return process(raw_output)

273
jc/parsers/crontab_u.py Normal file
View File

@@ -0,0 +1,273 @@
"""jc - JSON CLI output utility crontab file Parser
Usage:
specify --crontab-u as the first argument if the piped input is coming from a crontab file with User specified
Compatibility:
'linux', 'darwin', 'aix', 'freebsd'
Examples:
$ cat /etc/crontab | jc --crontab-u -p
{
"variables": [
{
"name": "PATH",
"value": "/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin"
},
{
"name": "SHELL",
"value": "/bin/sh"
}
],
"schedule": [
{
"minute": [
"25"
],
"hour": [
"6"
],
"day_of_month": [
"*"
],
"month": [
"*"
],
"day_of_week": [
"*"
],
"user": "root",
"command": "test -x /usr/sbin/anacron || ( cd / && run-parts --report /etc/cron.daily )"
},
{
"minute": [
"47"
],
"hour": [
"6"
],
"day_of_month": [
"*"
],
"month": [
"*"
],
"day_of_week": [
"7"
],
"user": "root",
"command": "test -x /usr/sbin/anacron || ( cd / && run-parts --report /etc/cron.weekly )"
},
{
"minute": [
"52"
],
"hour": [
"6"
],
"day_of_month": [
"1"
],
"month": [
"*"
],
"day_of_week": [
"*"
],
"user": "root",
"command": "test -x /usr/sbin/anacron || ( cd / && run-parts --report /etc/cron.monthly )"
}
]
}
$ cat /etc/crontab | jc --crontab-u -p -r
{
"variables": [
{
"name": "PATH",
"value": "/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin"
},
{
"name": "SHELL",
"value": "/bin/sh"
}
],
"schedule": [
{
"minute": "25",
"hour": "6",
"day_of_month": "*",
"month": "*",
"day_of_week": "*",
"user": "root",
"command": "test -x /usr/sbin/anacron || ( cd / && run-parts --report /etc/cron.daily )"
},
{
"minute": "47",
"hour": "6",
"day_of_month": "*",
"month": "*",
"day_of_week": "7",
"user": "root",
"command": "test -x /usr/sbin/anacron || ( cd / && run-parts --report /etc/cron.weekly )"
},
{
"minute": "52",
"hour": "6",
"day_of_month": "1",
"month": "*",
"day_of_week": "*",
"user": "root",
"command": "test -x /usr/sbin/anacron || ( cd / && run-parts --report /etc/cron.monthly )"
}
]
}
"""
import jc.utils
import jc.parsers.universal
class info():
version = '1.0'
description = 'crontab file parser with user support'
author = 'Kelly Brazil'
author_email = 'kellyjonbrazil@gmail.com'
# details = 'enter any other details here'
# compatible options: linux, darwin, cygwin, win32, aix, freebsd
compatible = ['linux', 'darwin', 'aix', 'freebsd']
__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:
{
"variables": [
"name": string,
"value": string
],
"schedule": [
{
"occurrence" string,
"minute": [
string
],
"hour": [
string
],
"day_of_month": [
string
],
"month": [
string
],
"day_of_week": [
string
],
"occurrence": string,
"user": string,
"command": string
}
]
}
"""
# put itmes in lists
try:
for entry in proc_data['schedule']:
entry['minute'] = entry['minute'].split(',')
entry['hour'] = entry['hour'].split(',')
entry['day_of_month'] = entry['day_of_month'].split(',')
entry['month'] = entry['month'].split(',')
entry['day_of_week'] = entry['day_of_week'].split(',')
except (KeyError):
pass
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:
Dictionary. Raw or processed structured data.
"""
if not quiet:
jc.utils.compatibility(__name__, info.compatible)
raw_output = {}
cleandata = data.splitlines()
# Clear any blank lines
cleandata = list(filter(None, cleandata))
# Clear any commented lines
for i, line in reversed(list(enumerate(cleandata))):
if line.strip().find('#') == 0:
cleandata.pop(i)
# Pop any variable assignment lines
cron_var = []
for i, line in reversed(list(enumerate(cleandata))):
if line.find('=') != -1:
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})
raw_output['variables'] = cron_var
# 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})
# Add header row for parsing
cleandata[:0] = ['minute hour day_of_month month day_of_week user command']
if len(cleandata) > 1:
cron_list = jc.parsers.universal.simple_table_parse(cleandata)
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
else:
return process(raw_output)

199
jc/parsers/df.py Normal file
View File

@@ -0,0 +1,199 @@
"""jc - JSON CLI output utility df Parser
Usage:
specify --df as the first argument if the piped input is coming from df
Compatibility:
'linux', 'darwin'
Examples:
$ df | jc --df -p
[
{
"filesystem": "devtmpfs",
"1k_blocks": 1918820,
"used": 0,
"available": 1918820,
"use_percent": 0,
"mounted_on": "/dev"
},
{
"filesystem": "tmpfs",
"1k_blocks": 1930668,
"used": 0,
"available": 1930668,
"use_percent": 0,
"mounted_on": "/dev/shm"
},
{
"filesystem": "tmpfs",
"1k_blocks": 1930668,
"used": 11800,
"available": 1918868,
"use_percent": 1,
"mounted_on": "/run"
},
...
]
$ df | jc --df -p -r
[
{
"filesystem": "devtmpfs",
"1k_blocks": "1918820",
"used": "0",
"available": "1918820",
"use_percent": "0%",
"mounted_on": "/dev"
},
{
"filesystem": "tmpfs",
"1k_blocks": "1930668",
"used": "0",
"available": "1930668",
"use_percent": "0%",
"mounted_on": "/dev/shm"
},
{
"filesystem": "tmpfs",
"1k_blocks": "1930668",
"used": "11800",
"available": "1918868",
"use_percent": "1%",
"mounted_on": "/run"
},
...
]
"""
import jc.utils
import jc.parsers.universal
class info():
version = '1.1'
description = 'df command parser'
author = 'Kelly Brazil'
author_email = 'kellyjonbrazil@gmail.com'
# compatible options: linux, darwin, cygwin, win32, aix, freebsd
compatible = ['linux', 'darwin']
magic_commands = ['df']
__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:
[
{
"filesystem": string,
"size": string,
"1k_blocks": integer,
"512_blocks": integer,
"used": integer,
"available": integer,
"capacity_percent": integer,
"ifree": integer,
"iused": integer,
"use_percent": integer,
"iused_percent": integer,
"mounted_on": string
}
]
"""
for entry in proc_data:
# change 'avail' to 'available'
if 'avail' in entry:
entry['available'] = entry.pop('avail')
# change 'use%' to 'use_percent'
if 'use%' in entry:
entry['use_percent'] = entry.pop('use%')
# change 'capacity' to 'capacity_percent'
if 'capacity' in entry:
entry['capacity_percent'] = entry.pop('capacity')
# change '%iused' to 'iused_percent'
if '%iused' in entry:
entry['iused_percent'] = entry.pop('%iused')
# change any entry for key with '_blocks' in the name to int
for k in entry:
if str(k).find('_blocks') != -1:
try:
blocks_int = int(entry[k])
entry[k] = blocks_int
except (ValueError):
entry[k] = None
# remove percent sign from 'use_percent', 'capacity_percent', and 'iused_percent'
if 'use_percent' in entry:
entry['use_percent'] = entry['use_percent'].rstrip('%')
if 'capacity_percent' in entry:
entry['capacity_percent'] = entry['capacity_percent'].rstrip('%')
if 'iused_percent' in entry:
entry['iused_percent'] = entry['iused_percent'].rstrip('%')
# change used, available, use_percent, capacity_percent, ifree, iused, iused_percent to int
int_list = ['used', 'available', 'use_percent', 'capacity_percent', 'ifree', 'iused', 'iused_percent']
for key in int_list:
if key in entry:
try:
key_int = int(entry[key])
entry[key] = key_int
except (ValueError):
entry[key] = 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)
cleandata = data.splitlines()
# 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
else:
return process(raw_output)

614
jc/parsers/dig.py Normal file
View File

@@ -0,0 +1,614 @@
"""jc - JSON CLI output utility dig Parser
Usage:
Specify --dig as the first argument if the piped input is coming from dig
Compatibility:
'linux', 'darwin', 'cygwin', 'win32', 'aix', 'freebsd'
Examples:
$ dig cnn.com www.cnn.com @205.251.194.64 | jc --dig -p
[
{
"id": 34128,
"opcode": "QUERY",
"status": "NOERROR",
"flags": [
"qr",
"rd",
"ra"
],
"query_num": 1,
"answer_num": 4,
"authority_num": 0,
"additional_num": 1,
"question": {
"name": "cnn.com.",
"class": "IN",
"type": "A"
},
"answer": [
{
"name": "cnn.com.",
"class": "IN",
"type": "A",
"ttl": 60,
"data": "151.101.65.67"
},
{
"name": "cnn.com.",
"class": "IN",
"type": "A",
"ttl": 60,
"data": "151.101.193.67"
},
{
"name": "cnn.com.",
"class": "IN",
"type": "A",
"ttl": 60,
"data": "151.101.1.67"
},
{
"name": "cnn.com.",
"class": "IN",
"type": "A",
"ttl": 60,
"data": "151.101.129.67"
}
],
"query_time": 37,
"server": "2600",
"when": "Tue Nov 12 07:14:42 PST 2019",
"rcvd": 100
},
{
"id": 15273,
"opcode": "QUERY",
"status": "NOERROR",
"flags": [
"qr",
"aa",
"rd"
],
"query_num": 1,
"answer_num": 1,
"authority_num": 4,
"additional_num": 1,
"question": {
"name": "www.cnn.com.",
"class": "IN",
"type": "A"
},
"answer": [
{
"name": "www.cnn.com.",
"class": "IN",
"type": "CNAME",
"ttl": 300,
"data": "turner-tls.map.fastly.net."
}
],
"authority": [
{
"name": "cnn.com.",
"class": "IN",
"type": "NS",
"ttl": 3600,
"data": "ns-1086.awsdns-07.org."
},
{
"name": "cnn.com.",
"class": "IN",
"type": "NS",
"ttl": 3600,
"data": "ns-1630.awsdns-11.co.uk."
},
{
"name": "cnn.com.",
"class": "IN",
"type": "NS",
"ttl": 3600,
"data": "ns-47.awsdns-05.com."
},
{
"name": "cnn.com.",
"class": "IN",
"type": "NS",
"ttl": 3600,
"data": "ns-576.awsdns-08.net."
}
],
"query_time": 23,
"server": "205.251.194.64#53(205.251.194.64)",
"when": "Tue Nov 12 07:14:42 PST 2019",
"rcvd": 212
}
]
$ dig cnn.com www.cnn.com @205.251.194.64 | jc --dig -p -r
[
{
"id": "23843",
"opcode": "QUERY",
"status": "NOERROR",
"flags": [
"qr",
"rd",
"ra"
],
"query_num": "1",
"answer_num": "4",
"authority_num": "0",
"additional_num": "1",
"question": {
"name": "cnn.com.",
"class": "IN",
"type": "A"
},
"answer": [
{
"name": "cnn.com.",
"class": "IN",
"type": "A",
"ttl": "30",
"data": "151.101.193.67"
},
{
"name": "cnn.com.",
"class": "IN",
"type": "A",
"ttl": "30",
"data": "151.101.1.67"
},
{
"name": "cnn.com.",
"class": "IN",
"type": "A",
"ttl": "30",
"data": "151.101.65.67"
},
{
"name": "cnn.com.",
"class": "IN",
"type": "A",
"ttl": "30",
"data": "151.101.129.67"
}
],
"query_time": "24 msec",
"server": "192.168.1.254#53(192.168.1.254)",
"when": "Tue Nov 12 07:16:19 PST 2019",
"rcvd": "100"
},
{
"id": "8266",
"opcode": "QUERY",
"status": "NOERROR",
"flags": [
"qr",
"aa",
"rd"
],
"query_num": "1",
"answer_num": "1",
"authority_num": "4",
"additional_num": "1",
"question": {
"name": "www.cnn.com.",
"class": "IN",
"type": "A"
},
"answer": [
{
"name": "www.cnn.com.",
"class": "IN",
"type": "CNAME",
"ttl": "300",
"data": "turner-tls.map.fastly.net."
}
],
"authority": [
{
"name": "cnn.com.",
"class": "IN",
"type": "NS",
"ttl": "3600",
"data": "ns-1086.awsdns-07.org."
},
{
"name": "cnn.com.",
"class": "IN",
"type": "NS",
"ttl": "3600",
"data": "ns-1630.awsdns-11.co.uk."
},
{
"name": "cnn.com.",
"class": "IN",
"type": "NS",
"ttl": "3600",
"data": "ns-47.awsdns-05.com."
},
{
"name": "cnn.com.",
"class": "IN",
"type": "NS",
"ttl": "3600",
"data": "ns-576.awsdns-08.net."
}
],
"query_time": "26 msec",
"server": "205.251.194.64#53(205.251.194.64)",
"when": "Tue Nov 12 07:16:19 PST 2019",
"rcvd": "212"
}
]
$ dig -x 1.1.1.1 | jc --dig -p
[
{
"id": 34898,
"opcode": "QUERY",
"status": "NOERROR",
"flags": [
"qr",
"rd",
"ra"
],
"query_num": 1,
"answer_num": 1,
"authority_num": 0,
"additional_num": 1,
"question": {
"name": "1.1.1.1.in-addr.arpa.",
"class": "IN",
"type": "PTR"
},
"answer": [
{
"name": "1.1.1.1.in-addr.arpa.",
"class": "IN",
"type": "PTR",
"ttl": 952,
"data": "one.one.one.one."
}
],
"query_time": 103,
"server": "2600",
"when": "Tue Nov 12 07:15:33 PST 2019",
"rcvd": 78
}
]
$ dig -x 1.1.1.1 | jc --dig -p -r
[
{
"id": "50986",
"opcode": "QUERY",
"status": "NOERROR",
"flags": [
"qr",
"rd",
"ra"
],
"query_num": "1",
"answer_num": "1",
"authority_num": "0",
"additional_num": "1",
"question": {
"name": "1.1.1.1.in-addr.arpa.",
"class": "IN",
"type": "PTR"
},
"answer": [
{
"name": "1.1.1.1.in-addr.arpa.",
"class": "IN",
"type": "PTR",
"ttl": "1800",
"data": "one.one.one.one."
}
],
"query_time": "38 msec",
"server": "2600",
"when": "Tue Nov 12 07:17:19 PST 2019",
"rcvd": "78"
}
]
"""
import jc.utils
class info():
version = '1.0'
description = 'dig command parser'
author = 'Kelly Brazil'
author_email = 'kellyjonbrazil@gmail.com'
# compatible options: linux, darwin, cygwin, win32, aix, freebsd
compatible = ['linux', 'aix', 'freebsd', 'darwin']
magic_commands = ['dig']
__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:
[
{
"id": integer,
"opcode": string,
"status": string,
"flags": [
string
],
"query_num": integer,
"answer_num": integer,
"authority_num": integer,
"additional_num": integer,
"question": {
"name": string,
"class": string,
"type": string
},
"answer": [
{
"name": string,
"class": string,
"type": string,
"ttl": integer,
"data": string
}
],
"authority": [
{
"name": string,
"class": string,
"type": string,
"ttl": integer,
"data": string
}
],
"query_time": integer, # in msec
"server": string,
"when": string,
"rcvd": integer
}
]
"""
for entry in proc_data:
int_list = ['id', 'query_num', 'answer_num', 'authority_num', 'additional_num', 'rcvd']
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 'answer' in entry:
for ans in entry['answer']:
try:
ttl_int = int(ans['ttl'])
ans['ttl'] = ttl_int
except (ValueError):
ans['ttl'] = None
if 'authority' in entry:
for auth in entry['authority']:
try:
ttl_int = int(auth['ttl'])
auth['ttl'] = ttl_int
except (ValueError):
auth['ttl'] = None
if 'query_time' in entry:
try:
qt_int = int(entry['query_time'].split()[0])
entry['query_time'] = qt_int
except (ValueError):
entry['query_time'] = None
return proc_data
def parse_header(header):
# ;; ->>HEADER<<- opcode: QUERY, status: NXDOMAIN, id: 6140
header = header.split()
opcode = header[3].rstrip(',')
status = header[5].rstrip(',')
header_id = header[7]
return {'id': header_id,
'opcode': opcode,
'status': status}
def parse_flags_line(flagsline):
# ;; flags: qr rd ra; QUERY: 1, ANSWER: 0, AUTHORITY: 0, ADDITIONAL: 1
flagsline = flagsline.split(';')
flags = flagsline.pop(0)
flags = flagsline.pop(0)
flags = flagsline.pop(0).split(':')
flags = flags[1].lstrip()
flags = flags.split()
restline = flagsline[0].replace(',', ' ').replace(':', ' ')
restlist = restline.split()
query_num = restlist[1]
answer_num = restlist[3]
authority_num = restlist[5]
additional_num = restlist[7]
return {'flags': flags,
'query_num': query_num,
'answer_num': answer_num,
'authority_num': authority_num,
'additional_num': additional_num}
def parse_question(question):
# ;www.cnn.com. IN A
question = question.split()
dns_name = question[0].lstrip(';')
dns_class = question[1]
dns_type = question[2]
return {'name': dns_name,
'class': dns_class,
'type': dns_type}
def parse_authority(authority):
# cnn.com. 3600 IN NS ns-1086.awsdns-07.org.
authority = authority.split()
authority_name = authority[0]
authority_class = authority[2]
authority_type = authority[3]
authority_ttl = authority[1]
authority_data = authority[4]
return {'name': authority_name,
'class': authority_class,
'type': authority_type,
'ttl': authority_ttl,
'data': authority_data}
def parse_answer(answer):
# www.cnn.com. 5 IN CNAME turner-tls.map.fastly.net.
answer = answer.split()
answer_name = answer[0]
answer_class = answer[2]
answer_type = answer[3]
answer_ttl = answer[1]
answer_data = answer[4]
return {'name': answer_name,
'class': answer_class,
'type': answer_type,
'ttl': answer_ttl,
'data': answer_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)
raw_output = []
cleandata = data.splitlines()
# remove blank lines
cleandata = list(filter(None, cleandata))
question = False
authority = False
answer = False
output_entry = {}
for line in cleandata:
if line.find(';; ->>HEADER<<-') == 0:
output_entry = {}
output_entry.update(parse_header(line))
continue
if line.find(';; flags:') == 0:
output_entry.update(parse_flags_line(line))
continue
if line.find(';; QUESTION SECTION:') == 0:
question = True
authority = False
answer = False
continue
if question:
output_entry['question'] = parse_question(line)
question = False
authority = False
answer = False
continue
if line.find(';; AUTHORITY SECTION:') == 0:
question = False
authority = True
answer = False
authority_list = []
continue
if line.find(';') == -1 and authority:
authority_list.append(parse_authority(line))
output_entry.update({'authority': authority_list})
continue
if line.find(';; ANSWER SECTION:') == 0:
question = False
authority = False
answer = True
answer_list = []
continue
if line.find(';') == -1 and answer:
answer_list.append(parse_answer(line))
output_entry.update({'answer': answer_list})
continue
# footer consists of 4 lines
# footer line 1
if line.find(';; Query time:') == 0:
output_entry.update({'query_time': line.split(':')[1].lstrip()})
continue
# footer line 2
if line.find(';; SERVER:') == 0:
output_entry.update({'server': line.split(':')[1].lstrip()})
continue
# footer line 3
if line.find(';; WHEN:') == 0:
output_entry.update({'when': line.split(':', maxsplit=1)[1].lstrip()})
continue
# footer line 4 (last line)
if line.find(';; MSG SIZE rcvd:') == 0:
output_entry.update({'rcvd': line.split(':')[1].lstrip()})
if output_entry:
raw_output.append(output_entry)
raw_output = list(filter(None, raw_output))
if raw:
return raw_output
else:
return process(raw_output)

152
jc/parsers/du.py Normal file
View File

@@ -0,0 +1,152 @@
"""jc - JSON CLI output utility du Parser
Usage:
specify --du as the first argument if the piped input is coming from du
Compatibility:
'linux', 'darwin', 'aix', 'freebsd'
Examples:
$ du /usr | jc --du -p
[
{
"size": 104608,
"name": "/usr/bin"
},
{
"size": 56,
"name": "/usr/standalone/firmware/iBridge1_1Customer.bundle/Contents/_CodeSignature"
},
{
"size": 0,
"name": "/usr/standalone/firmware/iBridge1_1Customer.bundle/Contents/Resources/Firmware/usr/local/standalone"
},
{
"size": 0,
"name": "/usr/standalone/firmware/iBridge1_1Customer.bundle/Contents/Resources/Firmware/usr/local"
},
{
"size": 0,
"name": "/usr/standalone/firmware/iBridge1_1Customer.bundle/Contents/Resources/Firmware/usr"
},
{
"size": 1008,
"name": "/usr/standalone/firmware/iBridge1_1Customer.bundle/Contents/Resources/Firmware/dfu"
},
...
]
$ du /usr | jc --du -p -r
[
{
"size": "104608",
"name": "/usr/bin"
},
{
"size": "56",
"name": "/usr/standalone/firmware/iBridge1_1Customer.bundle/Contents/_CodeSignature"
},
{
"size": "0",
"name": "/usr/standalone/firmware/iBridge1_1Customer.bundle/Contents/Resources/Firmware/usr/local/standalone"
},
{
"size": "0",
"name": "/usr/standalone/firmware/iBridge1_1Customer.bundle/Contents/Resources/Firmware/usr/local"
},
{
"size": "0",
"name": "/usr/standalone/firmware/iBridge1_1Customer.bundle/Contents/Resources/Firmware/usr"
},
{
"size": "1008",
"name": "/usr/standalone/firmware/iBridge1_1Customer.bundle/Contents/Resources/Firmware/dfu"
},
...
]
"""
import jc.utils
import jc.parsers.universal
class info():
version = '1.1'
description = 'du 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', 'darwin', 'aix', 'freebsd']
magic_commands = ['du']
__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:
[
{
"size": integer,
"name": string
}
]
"""
int_list = ['size']
for entry in proc_data:
for key in int_list:
if key in entry:
try:
key_int = int(entry[key])
entry[key] = key_int
except (ValueError):
entry[key] = 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)
raw_output = []
cleandata = data.splitlines()
# Clear any blank lines
cleandata = list(filter(None, cleandata))
if cleandata:
cleandata.insert(0, 'size name')
raw_output = jc.parsers.universal.simple_table_parse(cleandata)
if raw:
return raw_output
else:
return process(raw_output)

133
jc/parsers/env.py Normal file
View File

@@ -0,0 +1,133 @@
"""jc - JSON CLI output utility env Parser
Usage:
specify --env as the first argument if the piped input is coming from env
Compatibility:
'linux', 'darwin', 'cygwin', 'win32', 'aix', 'freebsd'
Examples:
$ env | jc --env -p
[
{
"name": "XDG_SESSION_ID",
"value": "1"
},
{
"name": "HOSTNAME",
"value": "localhost.localdomain"
},
{
"name": "TERM",
"value": "vt220"
},
{
"name": "SHELL",
"value": "/bin/bash"
},
{
"name": "HISTSIZE",
"value": "1000"
},
...
]
$ env | jc --env -p -r
{
"TERM": "xterm-256color",
"SHELL": "/bin/bash",
"USER": "root",
"PATH": "/usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin",
"PWD": "/root",
"LANG": "en_US.UTF-8",
"HOME": "/root",
"LOGNAME": "root",
"_": "/usr/bin/env"
}
"""
import jc.utils
class info():
version = '1.1'
description = 'env command parser'
author = 'Kelly Brazil'
author_email = 'kellyjonbrazil@gmail.com'
# compatible options: linux, darwin, cygwin, win32, aix, freebsd
compatible = ['linux', 'darwin', 'cygwin', 'win32', 'aix', 'freebsd']
magic_commands = ['env']
__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:
[
{
"name": string,
"value": string
}
]
"""
# rebuild output for added semantic information
processed = []
for k, v in proc_data.items():
proc_line = {}
proc_line['name'] = k
proc_line['value'] = v
processed.append(proc_line)
return processed
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 of raw structured data or
list of dictionaries of processed structured data
"""
if not quiet:
jc.utils.compatibility(__name__, info.compatible)
raw_output = {}
linedata = data.splitlines()
# Clear any blank lines
cleandata = list(filter(None, linedata))
if cleandata:
for entry in cleandata:
parsed_line = entry.split('=', maxsplit=1)
raw_output[parsed_line[0]] = parsed_line[1]
if raw:
return raw_output
else:
return process(raw_output)

92
jc/parsers/foo.py Normal file
View File

@@ -0,0 +1,92 @@
"""jc - JSON CLI output utility foo Parser
Usage:
specify --foo as the first argument if the piped input is coming from foo
Compatibility:
'linux', 'darwin', 'cygwin', 'win32', 'aix', 'freebsd'
Examples:
$ foo | jc --foo -p
[]
$ foo | jc --foo -p -r
[]
"""
import jc.utils
class info():
version = '1.0'
description = 'foo command parser'
author = 'John Doe'
author_email = 'johndoe@gmail.com'
# details = 'enter any other details here'
# compatible options: linux, darwin, cygwin, win32, aix, freebsd
compatible = ['linux', 'darwin', 'cygwin', 'win32', 'aix', 'freebsd']
magic_commands = ['foo']
__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:
[
{
"foo": string,
"bar": boolean,
"baz": integer
}
]
"""
# rebuild output for added semantic information
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)
raw_output = []
cleandata = data.splitlines()
# Clear any blank lines
cleandata = list(filter(None, cleandata))
if cleandata:
# parse the content
pass
if raw:
return raw_output
else:
return process(raw_output)

137
jc/parsers/free.py Normal file
View File

@@ -0,0 +1,137 @@
"""jc - JSON CLI output utility free Parser
Usage:
specify --free as the first argument if the piped input is coming from free
Compatibility:
'linux'
Examples:
$ free | jc --free -p
[
{
"type": "Mem",
"total": 3861340,
"used": 220508,
"free": 3381972,
"shared": 11800,
"buff_cache": 258860,
"available": 3397784
},
{
"type": "Swap",
"total": 2097148,
"used": 0,
"free": 2097148
}
]
$ free | jc --free -p -r
[
{
"type": "Mem",
"total": "2017300",
"used": "213104",
"free": "1148452",
"shared": "1176",
"buff_cache": "655744",
"available": "1622204"
},
{
"type": "Swap",
"total": "2097148",
"used": "0",
"free": "2097148"
}
]
"""
import jc.utils
import jc.parsers.universal
class info():
version = '1.0'
description = 'free command parser'
author = 'Kelly Brazil'
author_email = 'kellyjonbrazil@gmail.com'
# compatible options: linux, darwin, cygwin, win32, aix, freebsd
compatible = ['linux']
magic_commands = ['free']
__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:
[
{
"type": string,
"total": integer,
"used": integer,
"free": integer,
"shared": integer,
"buff_cache": integer,
"available": integer
}
]
"""
for entry in proc_data:
int_list = ['total', 'used', 'free', 'shared', 'buff_cache', 'available']
for key in int_list:
if key in entry:
try:
key_int = int(entry[key])
entry[key] = key_int
except (ValueError):
entry[key] = 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)
cleandata = data.splitlines()
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
else:
return process(raw_output)

171
jc/parsers/fstab.py Normal file
View File

@@ -0,0 +1,171 @@
"""jc - JSON CLI output utility fstab Parser
Usage:
specify --fstab as the first argument if the piped input is coming from a fstab file
Compatibility:
'linux'
Examples:
$ cat /etc/fstab | jc --fstab -p
[
{
"fs_spec": "/dev/mapper/centos-root",
"fs_file": "/",
"fs_vfstype": "xfs",
"fs_mntops": "defaults",
"fs_freq": 0,
"fs_passno": 0
},
{
"fs_spec": "UUID=05d927bb-5875-49e3-ada1-7f46cb31c932",
"fs_file": "/boot",
"fs_vfstype": "xfs",
"fs_mntops": "defaults",
"fs_freq": 0,
"fs_passno": 0
},
{
"fs_spec": "/dev/mapper/centos-swap",
"fs_file": "swap",
"fs_vfstype": "swap",
"fs_mntops": "defaults",
"fs_freq": 0,
"fs_passno": 0
}
]
$ cat /etc/fstab | jc --fstab -p -r
[
{
"fs_spec": "/dev/mapper/centos-root",
"fs_file": "/",
"fs_vfstype": "xfs",
"fs_mntops": "defaults",
"fs_freq": "0",
"fs_passno": "0"
},
{
"fs_spec": "UUID=05d927bb-5875-49e3-ada1-7f46cb31c932",
"fs_file": "/boot",
"fs_vfstype": "xfs",
"fs_mntops": "defaults",
"fs_freq": "0",
"fs_passno": "0"
},
{
"fs_spec": "/dev/mapper/centos-swap",
"fs_file": "swap",
"fs_vfstype": "swap",
"fs_mntops": "defaults",
"fs_freq": "0",
"fs_passno": "0"
}
]
"""
import jc.utils
class info():
version = '1.0'
description = 'fstab file parser'
author = 'Kelly Brazil'
author_email = 'kellyjonbrazil@gmail.com'
# compatible options: linux, darwin, cygwin, win32, aix, freebsd
compatible = ['linux']
__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:
[
{
"fs_spec": string,
"fs_file": string,
"fs_vfstype": string,
"fs_mntops": string,
"fs_freq": integer,
"fs_passno": integer
}
]
"""
for entry in proc_data:
int_list = ['fs_freq', 'fs_passno']
for key in int_list:
if key in entry:
try:
key_int = int(entry[key])
entry[key] = key_int
except (ValueError):
entry[key] = 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)
raw_output = []
cleandata = data.splitlines()
# Clear any blank lines
cleandata = list(filter(None, cleandata))
if cleandata:
for line in cleandata:
output_line = {}
# ignore commented lines
if line.strip().find('#') == 0:
continue
line_list = line.split(maxsplit=6)
fs_spec = line_list[0]
fs_file = line_list[1]
fs_vfstype = line_list[2]
fs_mntops = line_list[3]
fs_freq = line_list[4]
fs_passno = line_list[5]
output_line['fs_spec'] = fs_spec
output_line['fs_file'] = fs_file
output_line['fs_vfstype'] = fs_vfstype
output_line['fs_mntops'] = fs_mntops
output_line['fs_freq'] = fs_freq
output_line['fs_passno'] = fs_passno
raw_output.append(output_line)
if raw:
return raw_output
else:
return process(raw_output)

138
jc/parsers/history.py Normal file
View File

@@ -0,0 +1,138 @@
"""jc - JSON CLI output utility history Parser
Usage:
specify --history as the first argument if the piped input is coming from history
Compatibility:
'linux', 'darwin', 'cygwin', 'aix', 'freebsd'
Examples:
$ history | jc --history -p
[
{
"line": 118,
"command": "sleep 100"
},
{
"line": 119,
"command": "ls /bin"
},
{
"line": 120,
"command": "echo \"hello\""
},
{
"line": 121,
"command": "docker images"
},
...
]
$ history | jc --history -p -r
{
"118": "sleep 100",
"119": "ls /bin",
"120": "echo \"hello\"",
"121": "docker images",
...
}
"""
import jc
class info():
version = '1.1'
description = 'history command parser'
author = 'Kelly Brazil'
author_email = 'kellyjonbrazil@gmail.com'
# compatible options: linux, darwin, cygwin, win32, aix, freebsd
compatible = ['linux', 'darwin', 'cygwin', 'aix', 'freebsd']
__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:
[
{
"line": integer,
"command": string
}
]
"""
# rebuild output for added semantic information
processed = []
for k, v in proc_data.items():
proc_line = {}
proc_line['line'] = k
proc_line['command'] = v
processed.append(proc_line)
for entry in processed:
int_list = ['line']
for key in int_list:
if key in entry:
try:
key_int = int(entry[key])
entry[key] = key_int
except (ValueError):
entry[key] = None
return processed
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 of raw structured data or
list of dictionaries of processed structured data
"""
if not quiet:
jc.utils.compatibility(__name__, info.compatible)
raw_output = {}
# split lines and clear out any non-ascii chars
linedata = data.encode('ascii', errors='ignore').decode().splitlines()
# Clear any blank lines
cleandata = list(filter(None, linedata))
if cleandata:
for entry in cleandata:
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
else:
return process(raw_output)

155
jc/parsers/hosts.py Normal file
View File

@@ -0,0 +1,155 @@
"""jc - JSON CLI output utility hosts Parser
Usage:
specify --hosts as the first argument if the piped input is coming from a hosts file
Compatibility:
'linux', 'darwin', 'cygwin', 'win32', 'aix', 'freebsd'
Examples:
$ cat /etc/hosts | jc --hosts -p
[
{
"ip": "127.0.0.1",
"hostname": [
"localhost"
]
},
{
"ip": "127.0.1.1",
"hostname": [
"root-ubuntu"
]
},
{
"ip": "::1",
"hostname": [
"ip6-localhost",
"ip6-loopback"
]
},
{
"ip": "fe00::0",
"hostname": [
"ip6-localnet"
]
},
{
"ip": "ff00::0",
"hostname": [
"ip6-mcastprefix"
]
},
{
"ip": "ff02::1",
"hostname": [
"ip6-allnodes"
]
},
{
"ip": "ff02::2",
"hostname": [
"ip6-allrouters"
]
}
]
"""
import jc.utils
class info():
version = '1.0'
description = '/etc/hosts file parser'
author = 'Kelly Brazil'
author_email = 'kellyjonbrazil@gmail.com'
# compatible options: linux, darwin, cygwin, win32, aix, freebsd
compatible = ['linux', 'darwin', 'cygwin', 'win32', 'aix', 'freebsd']
__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:
[
{
"ip": string,
"hostname": [
string
]
}
]
"""
# no additional processing needed
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)
raw_output = []
cleandata = data.splitlines()
# Clear any blank lines
cleandata = list(filter(None, cleandata))
if cleandata:
for line in cleandata:
output_line = {}
# ignore commented lines
if line.strip().find('#') == 0:
continue
line_list = line.split(maxsplit=1)
ip = line_list[0]
hosts = line_list[1]
hosts_list = hosts.split()
comment_found = False
for i, item in enumerate(hosts_list):
if item.find('#') != -1:
comment_found = True
comment_item = i
break
if comment_found:
hosts_list = hosts_list[:comment_item]
output_line['ip'] = ip
output_line['hostname'] = hosts_list
raw_output.append(output_line)
if raw:
return raw_output
else:
return process(raw_output)

215
jc/parsers/id.py Normal file
View File

@@ -0,0 +1,215 @@
"""jc - JSON CLI output utility id Parser
Usage:
specify --id as the first argument if the piped input is coming from id
Compatibility:
'linux', 'darwin', 'aix', 'freebsd'
Examples:
$ id | jc --id -p
{
"uid": {
"id": 1000,
"name": "joeuser"
},
"gid": {
"id": 1000,
"name": "joeuser"
},
"groups": [
{
"id": 1000,
"name": "joeuser"
},
{
"id": 10,
"name": "wheel"
}
],
"context": {
"user": "unconfined_u",
"role": "unconfined_r",
"type": "unconfined_t",
"level": "s0-s0:c0.c1023"
}
}
$ id | jc --id -p -r
{
"uid": {
"id": "1000",
"name": "joeuser"
},
"gid": {
"id": "1000",
"name": "joeuser"
},
"groups": [
{
"id": "1000",
"name": "joeuser"
},
{
"id": "10",
"name": "wheel"
}
],
"context": {
"user": "unconfined_u",
"role": "unconfined_r",
"type": "unconfined_t",
"level": "s0-s0:c0.c1023"
}
}
"""
import jc.utils
class info():
version = '1.0'
description = 'id 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', 'darwin', 'aix', 'freebsd']
magic_commands = ['id']
__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:
{
"uid": {
"id": integer,
"name": string
},
"gid": {
"id": integer,
"name": string
},
"groups": [
{
"id": integer,
"name": string
},
{
"id": integer,
"name": string
}
],
"context": {
"user": string,
"role": string,
"type": string,
"level": string
}
}
"""
if 'uid' in proc_data:
if 'id' in proc_data['uid']:
try:
proc_data['uid']['id'] = int(proc_data['uid']['id'])
except (ValueError):
proc_data['uid']['id'] = None
if 'gid' in proc_data:
if 'id' in proc_data['gid']:
try:
proc_data['gid']['id'] = int(proc_data['gid']['id'])
except (ValueError):
proc_data['gid']['id'] = None
if 'groups' in proc_data:
for group in proc_data['groups']:
if 'id' in group:
try:
group['id'] = int(group['id'])
except (ValueError):
group['id'] = 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)
raw_output = {}
cleandata = data.split()
# Clear any blank lines
cleandata = list(filter(None, cleandata))
if cleandata:
for section in cleandata:
if section.startswith('uid'):
uid_parsed = section.replace('(', '=').replace(')', '=')
uid_parsed = uid_parsed.split('=')
raw_output['uid'] = {}
raw_output['uid']['id'] = uid_parsed[1]
raw_output['uid']['name'] = uid_parsed[2]
if section.startswith('gid'):
gid_parsed = section.replace('(', '=').replace(')', '=')
gid_parsed = gid_parsed.split('=')
raw_output['gid'] = {}
raw_output['gid']['id'] = gid_parsed[1]
raw_output['gid']['name'] = gid_parsed[2]
if section.startswith('groups'):
groups_parsed = section.replace('(', '=').replace(')', '=')
groups_parsed = groups_parsed.replace('groups=', '')
groups_parsed = groups_parsed.split(',')
raw_output['groups'] = []
for group in groups_parsed:
group_dict = {}
grp_parsed = group.split('=')
group_dict['id'] = grp_parsed[0]
group_dict['name'] = grp_parsed[1]
raw_output['groups'].append(group_dict)
if section.startswith('context'):
context_parsed = section.replace('context=', '')
context_parsed = context_parsed.split(':', maxsplit=3)
raw_output['context'] = {}
raw_output['context']['user'] = context_parsed[0]
raw_output['context']['role'] = context_parsed[1]
raw_output['context']['type'] = context_parsed[2]
raw_output['context']['level'] = context_parsed[3]
if raw:
return raw_output
else:
return process(raw_output)

View File

@@ -1,21 +1,263 @@
"""jc - JSON CLI output utility ifconfig Parser
Usage:
specify --ifconfig as the first argument if the piped input is coming from ifconfig
no ifconfig options are supported.
Example:
Compatibility:
$ ifconfig | jc --ifconfig -p
'linux', 'aix', 'freebsd', 'darwin'
Examples:
$ ifconfig | jc --ifconfig -p
[
{
"name": "ens33",
"flags": 4163,
"state": [
"UP",
"BROADCAST",
"RUNNING",
"MULTICAST"
],
"mtu": 1500,
"ipv4_addr": "192.168.71.137",
"ipv4_mask": "255.255.255.0",
"ipv4_bcast": "192.168.71.255",
"ipv6_addr": "fe80::c1cb:715d:bc3e:b8a0",
"ipv6_mask": 64,
"ipv6_scope": "0x20",
"mac_addr": "00:0c:29:3b:58:0e",
"type": "Ethernet",
"rx_packets": 8061,
"rx_bytes": 1514413,
"rx_errors": 0,
"rx_dropped": 0,
"rx_overruns": 0,
"rx_frame": 0,
"tx_packets": 4502,
"tx_bytes": 866622,
"tx_errors": 0,
"tx_dropped": 0,
"tx_overruns": 0,
"tx_carrier": 0,
"tx_collisions": 0,
"metric": null
},
{
"name": "lo",
"flags": 73,
"state": [
"UP",
"LOOPBACK",
"RUNNING"
],
"mtu": 65536,
"ipv4_addr": "127.0.0.1",
"ipv4_mask": "255.0.0.0",
"ipv4_bcast": null,
"ipv6_addr": "::1",
"ipv6_mask": 128,
"ipv6_scope": "0x10",
"mac_addr": null,
"type": "Local Loopback",
"rx_packets": 73,
"rx_bytes": 6009,
"rx_errors": 0,
"rx_dropped": 0,
"rx_overruns": 0,
"rx_frame": 0,
"tx_packets": 73,
"tx_bytes": 6009,
"tx_errors": 0,
"tx_dropped": 0,
"tx_overruns": 0,
"tx_carrier": 0,
"tx_collisions": 0,
"metric": null
}
]
$ ifconfig | jc --ifconfig -p -r
[
{
"name": "ens33",
"flags": "4163",
"state": "UP,BROADCAST,RUNNING,MULTICAST",
"mtu": "1500",
"ipv4_addr": "192.168.71.137",
"ipv4_mask": "255.255.255.0",
"ipv4_bcast": "192.168.71.255",
"ipv6_addr": "fe80::c1cb:715d:bc3e:b8a0",
"ipv6_mask": "64",
"ipv6_scope": "0x20",
"mac_addr": "00:0c:29:3b:58:0e",
"type": "Ethernet",
"rx_packets": "8061",
"rx_bytes": "1514413",
"rx_errors": "0",
"rx_dropped": "0",
"rx_overruns": "0",
"rx_frame": "0",
"tx_packets": "4502",
"tx_bytes": "866622",
"tx_errors": "0",
"tx_dropped": "0",
"tx_overruns": "0",
"tx_carrier": "0",
"tx_collisions": "0",
"metric": null
},
{
"name": "lo",
"flags": "73",
"state": "UP,LOOPBACK,RUNNING",
"mtu": "65536",
"ipv4_addr": "127.0.0.1",
"ipv4_mask": "255.0.0.0",
"ipv4_bcast": null,
"ipv6_addr": "::1",
"ipv6_mask": "128",
"ipv6_scope": "0x10",
"mac_addr": null,
"type": "Local Loopback",
"rx_packets": "73",
"rx_bytes": "6009",
"rx_errors": "0",
"rx_dropped": "0",
"rx_overruns": "0",
"rx_frame": "0",
"tx_packets": "73",
"tx_bytes": "6009",
"tx_errors": "0",
"tx_dropped": "0",
"tx_overruns": "0",
"tx_carrier": "0",
"tx_collisions": "0",
"metric": null
}
]
"""
from collections import namedtuple
import jc.utils
from ifconfigparser import IfconfigParser
def parse(data):
output = []
class info():
version = '1.5'
description = 'ifconfig command parser'
author = 'Kelly Brazil'
author_email = 'kellyjonbrazil@gmail.com'
details = 'Using ifconfig-parser package from https://github.com/KnightWhoSayNi/ifconfig-parser'
# compatible options: linux, darwin, cygwin, win32, aix, freebsd
compatible = ['linux', 'aix', 'freebsd', 'darwin']
magic_commands = ['ifconfig']
__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:
[
{
"name": string,
"flags": integer,
"state": [
string
],
"mtu": integer,
"ipv4_addr": string,
"ipv4_mask": string,
"ipv4_bcast": string,
"ipv6_addr": string,
"ipv6_mask": integer,
"ipv6_scope": string,
"mac_addr": string,
"type": string,
"rx_packets": integer,
"rx_bytes": integer,
"rx_errors": integer,
"rx_dropped": integer,
"rx_overruns": integer,
"rx_frame": integer,
"tx_packets": integer,
"tx_bytes": integer,
"tx_errors": integer,
"tx_dropped": integer,
"tx_overruns": integer,
"tx_carrier": integer,
"tx_collisions": integer,
"metric": integer
}
]
"""
for entry in proc_data:
int_list = ['flags', 'mtu', 'ipv6_mask', 'rx_packets', 'rx_bytes', 'rx_errors', 'rx_dropped', 'rx_overruns',
'rx_frame', 'tx_packets', 'tx_bytes', 'tx_errors', 'tx_dropped', 'tx_overruns', 'tx_carrier',
'tx_collisions', 'metric']
for key in int_list:
if key in entry:
try:
key_int = int(entry[key])
entry[key] = key_int
except (ValueError, TypeError):
entry[key] = None
# convert OSX-style subnet mask to dotted quad
if 'ipv4_mask' in entry:
try:
if entry['ipv4_mask'].find('0x') == 0:
new_mask = entry['ipv4_mask']
new_mask = new_mask.lstrip('0x')
new_mask = '.'.join(str(int(i, 16)) for i in [new_mask[i:i + 2] for i in range(0, len(new_mask), 2)])
entry['ipv4_mask'] = new_mask
except (ValueError, TypeError, AttributeError):
pass
# convert state value to an array
if 'state' in entry:
try:
new_state = entry['state'].split(',')
entry['state'] = new_state
except (ValueError, TypeError, AttributeError):
pass
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)
raw_output = []
parsed = IfconfigParser(console_output=data)
interfaces = parsed.get_interfaces()
@@ -23,8 +265,9 @@ def parse(data):
for iface in interfaces:
d = interfaces[iface]._asdict()
dct = dict(d)
output.append(dct)
return output
raw_output.append(dct)
if raw:
return raw_output
else:
return process(raw_output)

112
jc/parsers/ini.py Normal file
View File

@@ -0,0 +1,112 @@
"""jc - JSON CLI output utility INI Parser
Usage:
specify --ini as the first argument if the piped input is coming from an INI file
Compatibility:
'linux', 'darwin', 'cygwin', 'win32', 'aix', 'freebsd'
Examples:
$ cat example.ini
[DEFAULT]
ServerAliveInterval = 45
Compression = yes
CompressionLevel = 9
ForwardX11 = yes
[bitbucket.org]
User = hg
[topsecret.server.com]
Port = 50022
ForwardX11 = no
$ cat example.ini | jc --ini -p
{
"bitbucket.org": {
"serveraliveinterval": "45",
"compression": "yes",
"compressionlevel": "9",
"forwardx11": "yes",
"user": "hg"
},
"topsecret.server.com": {
"serveraliveinterval": "45",
"compression": "yes",
"compressionlevel": "9",
"forwardx11": "no",
"port": "50022"
}
}
"""
import jc.utils
import configparser
class info():
version = '1.0'
description = 'INI file parser'
author = 'Kelly Brazil'
author_email = 'kellyjonbrazil@gmail.com'
details = 'Using configparser from the standard library'
# compatible options: linux, darwin, cygwin, win32, aix, freebsd
compatible = ['linux', 'darwin', 'cygwin', 'win32', 'aix', 'freebsd']
__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 representing an ini document:
{
ini document converted to a dictionary
see configparser standard library documentation for more details
}
"""
# No further processing
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:
Dictionary representing the ini file
"""
if not quiet:
jc.utils.compatibility(__name__, info.compatible)
raw_output = {}
if data:
ini = configparser.ConfigParser()
ini.read_string(data)
raw_output = {s: dict(ini.items(s)) for s in ini.sections()}
if raw:
return raw_output
else:
return process(raw_output)

280
jc/parsers/iptables.py Normal file
View File

@@ -0,0 +1,280 @@
"""jc - JSON CLI output utility ipables Parser
Usage:
Specify --iptables as the first argument if the piped input is coming from iptables
Supports -vLn and --line-numbers for all tables
Compatibility:
'linux'
Examples:
$ sudo iptables --line-numbers -v -L -t nat | jc --iptables -p
[
{
"chain": "PREROUTING",
"rules": [
{
"num": 1,
"pkts": 2183,
"bytes": 186000,
"target": "PREROUTING_direct",
"prot": "all",
"opt": null,
"in": "any",
"out": "any",
"source": "anywhere",
"destination": "anywhere"
},
{
"num": 2,
"pkts": 2183,
"bytes": 186000,
"target": "PREROUTING_ZONES_SOURCE",
"prot": "all",
"opt": null,
"in": "any",
"out": "any",
"source": "anywhere",
"destination": "anywhere"
},
{
"num": 3,
"pkts": 2183,
"bytes": 186000,
"target": "PREROUTING_ZONES",
"prot": "all",
"opt": null,
"in": "any",
"out": "any",
"source": "anywhere",
"destination": "anywhere"
},
{
"num": 4,
"pkts": 0,
"bytes": 0,
"target": "DOCKER",
"prot": "all",
"opt": null,
"in": "any",
"out": "any",
"source": "anywhere",
"destination": "anywhere",
"options": "ADDRTYPE match dst-type LOCAL"
}
]
},
...
]
$ sudo iptables --line-numbers -v -L -t nat | jc --iptables -p -r
[
{
"chain": "PREROUTING",
"rules": [
{
"num": "1",
"pkts": "2183",
"bytes": "186K",
"target": "PREROUTING_direct",
"prot": "all",
"opt": "--",
"in": "any",
"out": "any",
"source": "anywhere",
"destination": "anywhere"
},
{
"num": "2",
"pkts": "2183",
"bytes": "186K",
"target": "PREROUTING_ZONES_SOURCE",
"prot": "all",
"opt": "--",
"in": "any",
"out": "any",
"source": "anywhere",
"destination": "anywhere"
},
{
"num": "3",
"pkts": "2183",
"bytes": "186K",
"target": "PREROUTING_ZONES",
"prot": "all",
"opt": "--",
"in": "any",
"out": "any",
"source": "anywhere",
"destination": "anywhere"
},
{
"num": "4",
"pkts": "0",
"bytes": "0",
"target": "DOCKER",
"prot": "all",
"opt": "--",
"in": "any",
"out": "any",
"source": "anywhere",
"destination": "anywhere",
"options": "ADDRTYPE match dst-type LOCAL"
}
]
},
...
]
"""
import jc.utils
class info():
version = '1.1'
description = 'iptables command parser'
author = 'Kelly Brazil'
author_email = 'kellyjonbrazil@gmail.com'
# compatible options: linux, darwin, cygwin, win32, aix, freebsd
compatible = ['linux']
magic_commands = ['iptables']
__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:
[
{
"chain": string,
"rules": [
{
"num" integer,
"pkts": integer,
"bytes": integer, # converted based on suffix
"target": string,
"prot": string,
"opt": string, # "--" = Null
"in": string,
"out": string,
"source": string,
"destination": string,
"options": string
}
]
}
]
"""
for entry in proc_data:
for rule in entry['rules']:
int_list = ['num', 'pkts']
for key in int_list:
if key in rule:
try:
key_int = int(rule[key])
rule[key] = key_int
except (ValueError):
rule[key] = None
if 'bytes' in rule:
multiplier = 1
if rule['bytes'][-1] == 'K':
multiplier = 1000
rule['bytes'] = rule['bytes'].rstrip('K')
elif rule['bytes'][-1] == 'M':
multiplier = 1000000
rule['bytes'] = rule['bytes'].rstrip('M')
elif rule['bytes'][-1] == 'G':
multiplier = 1000000000
rule['bytes'] = rule['bytes'].rstrip('G')
elif rule['bytes'][-1] == 'T':
multiplier = 1000000000000
rule['bytes'] = rule['bytes'].rstrip('T')
elif rule['bytes'][-1] == 'P':
multiplier = 1000000000000000
rule['bytes'] = rule['bytes'].rstrip('P')
try:
bytes_int = int(rule['bytes'])
rule['bytes'] = bytes_int * multiplier
except (ValueError):
rule['bytes'] = None
if 'opt' in rule:
if rule['opt'] == '--':
rule['opt'] = 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)
raw_output = []
chain = {}
headers = []
cleandata = data.splitlines()
for line in cleandata:
if line.find('Chain') == 0:
raw_output.append(chain)
chain = {}
headers = []
parsed_line = line.split()
chain['chain'] = parsed_line[1]
chain['rules'] = []
continue
elif line.find('target') == 0 or line.find('pkts') == 1 or line.find('num') == 0:
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
else:
return process(raw_output)

204
jc/parsers/jobs.py Normal file
View File

@@ -0,0 +1,204 @@
"""jc - JSON CLI output utility jobs Parser
Usage:
specify --jobs as the first argument if the piped input is coming from jobs
Also supports the -l option
Compatibility:
'linux', 'darwin', 'cygwin', 'aix', 'freebsd'
Example:
$ jobs -l | jc --jobs -p
[
{
"job_number": 1,
"pid": 5283,
"status": "Running",
"command": "sleep 10000 &"
},
{
"job_number": 2,
"pid": 5284,
"status": "Running",
"command": "sleep 10100 &"
},
{
"job_number": 3,
"pid": 5285,
"history": "previous",
"status": "Running",
"command": "sleep 10001 &"
},
{
"job_number": 4,
"pid": 5286,
"history": "current",
"status": "Running",
"command": "sleep 10112 &"
}
]
$ jobs -l | jc --jobs -p -r
[
{
"job_number": "1",
"pid": "19510",
"status": "Running",
"command": "sleep 1000 &"
},
{
"job_number": "2",
"pid": "19511",
"status": "Running",
"command": "sleep 1001 &"
},
{
"job_number": "3",
"pid": "19512",
"history": "previous",
"status": "Running",
"command": "sleep 1002 &"
},
{
"job_number": "4",
"pid": "19513",
"history": "current",
"status": "Running",
"command": "sleep 1003 &"
}
]
"""
import string
import jc.utils
class info():
version = '1.0'
description = 'jobs command parser'
author = 'Kelly Brazil'
author_email = 'kellyjonbrazil@gmail.com'
# compatible options: linux, darwin, cygwin, win32, aix, freebsd
compatible = ['linux', 'darwin', 'cygwin', 'aix', 'freebsd']
magic_commands = ['jobs']
__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:
[
{
"job_number": integer,
"pid": integer,
"history": string,
"status": string,
"command": string
}
]
"""
for entry in proc_data:
int_list = ['job_number', 'pid']
for key in int_list:
if key in entry:
try:
key_int = int(entry[key])
entry[key] = key_int
except (ValueError):
entry[key] = 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)
raw_output = []
linedata = data.splitlines()
# Clear any blank lines
cleandata = list(filter(None, linedata))
if cleandata:
for entry in cleandata:
output_line = {}
remainder = []
job_number = ''
pid = ''
job_history = ''
parsed_line = entry.split(maxsplit=2)
# check if -l was used
if parsed_line[1][0] in string.digits:
pid = parsed_line.pop(1)
remainder = parsed_line.pop(1)
job_number = parsed_line.pop(0)
remainder = remainder.split(maxsplit=1)
# rebuild parsed_line
parsed_line = []
for r in remainder:
parsed_line.append(r)
parsed_line.insert(0, job_number)
# check for + or - in first field
if parsed_line[0].find('+') != -1:
job_history = 'current'
parsed_line[0] = parsed_line[0].rstrip('+')
if parsed_line[0].find('-') != -1:
job_history = 'previous'
parsed_line[0] = parsed_line[0].rstrip('-')
# clean up first field
parsed_line[0] = parsed_line[0].lstrip('[').rstrip(']')
# create list of dictionaries
output_line['job_number'] = parsed_line[0]
if pid:
output_line['pid'] = pid
if job_history:
output_line['history'] = job_history
output_line['status'] = parsed_line[1]
output_line['command'] = parsed_line[2]
raw_output.append(output_line)
if raw:
return raw_output
else:
return process(raw_output)

View File

@@ -1,130 +1,297 @@
"""jc - JSON CLI output utility ls Parser
Usage:
specify --ls as the first argument if the piped input is coming from ls
ls options supported:
- None
- l
- a
- laR
--time-style=full-iso
- h file sizes will be available in text form with -r but larger file sizes
with human readable suffixes will be converted to Null in default view
since the parser attempts to convert this field to an integer.
Compatibility:
'linux', 'darwin', 'cygwin', 'aix', 'freebsd'
Examples:
$ ls -a /usr/bin | jc --ls -p
[
{
"filename": "."
},
{
"filename": ".."
},
{
"filename": "2to3-"
},
{
"filename": "2to3-2.7"
},
{
"filename": "AssetCacheLocatorUtil"
},
...
]
$ ls /usr/bin | jc --ls -p
[
{
"filename": "apropos"
},
{
"filename": "arch"
},
{
"filename": "awk"
},
{
"filename": "base64"
},
...
]
$ ls -al /usr/bin | jc --ls -p
[
{
"filename": ".",
"flags": "drwxr-xr-x",
"links": 970,
"owner": "root",
"group": "wheel",
"bytes": 31040,
"date": "Aug 27 21:20"
},
{
"filename": "..",
"flags": "drwxr-xr-x@",
"links": 9,
"owner": "root",
"group": "wheel",
"bytes": 288,
"date": "May 3 22:14"
},
{
"filename": "2to3-",
"flags": "-rwxr-xr-x",
"links": 4,
"owner": "root",
"group": "wheel",
"bytes": 925,
"date": "Feb 22 2019"
},
{
"filename": "2to3-2.7",
"link_to": "../../System/Library/Frameworks/Python.framework/Versions/2.7/bin/2to3-2.7",
"flags": "lrwxr-xr-x",
"links": 1,
"owner": "root",
"group": "wheel",
"bytes": 74,
"date": "May 4 02:12"
},
...
]
$ ls -l /usr/bin | jc --ls -p
[
{
"filename": "apropos",
"link_to": "whatis",
"flags": "lrwxrwxrwx.",
"links": 1,
"owner": "root",
"group": "root",
"size": 6,
"date": "Aug 15 10:53"
},
{
"filename": "ar",
"flags": "-rwxr-xr-x.",
"links": 1,
"owner": "root",
"group": "root",
"size": 62744,
"date": "Aug 8 16:14"
},
{
"filename": "arch",
"flags": "-rwxr-xr-x.",
"links": 1,
"owner": "root",
"group": "root",
"size": 33080,
"date": "Aug 19 23:25"
},
...
]
$ $ ls -l /usr/bin | jc --ls | jq .[] | jq 'select(.bytes > 50000000)'
{
"filename": "emacs",
"flags": "-r-xr-xr-x",
"links": 1,
"owner": "root",
"group": "wheel",
"bytes": 117164432,
"date": "May 3 22:26"
}
$ ls -l /usr/bin | jc --ls -p -r
[
{
"filename": "apropos",
"link_to": "whatis",
"flags": "lrwxrwxrwx.",
"links": "1",
"owner": "root",
"group": "root",
"size": "6",
"date": "Aug 15 10:53"
},
{
"filename": "arch",
"flags": "-rwxr-xr-x.",
"links": "1",
"owner": "root",
"group": "root",
"size": "33080",
"date": "Aug 19 23:25"
},
{
"filename": "awk",
"link_to": "gawk",
"flags": "lrwxrwxrwx.",
"links": "1",
"owner": "root",
"group": "root",
"size": "4",
"date": "Aug 15 10:53"
},
{
"filename": "base64",
"flags": "-rwxr-xr-x.",
"links": "1",
"owner": "root",
"group": "root",
"size": "37360",
"date": "Aug 19 23:25"
},
{
"filename": "basename",
"flags": "-rwxr-xr-x.",
"links": "1",
"owner": "root",
"group": "root",
"size": "29032",
"date": "Aug 19 23:25"
},
{
"filename": "bash",
"flags": "-rwxr-xr-x.",
"links": "1",
"owner": "root",
"group": "root",
"size": "964600",
"date": "Aug 8 05:06"
},
...
]
$ ls -l /usr/bin | jc --ls | jq '.[] | select(.size > 50000000)'
{
"filename": "emacs",
"flags": "-r-xr-xr-x",
"links": 1,
"owner": "root",
"group": "wheel",
"size": 117164432,
"date": "May 3 2019"
}
"""
import re
import jc.utils
def parse(data):
output = []
cleandata = data.splitlines()
# Delete first line if it starts with 'total'
if cleandata[0].find('total') == 0:
cleandata.pop(0)
class info():
version = '1.1'
description = 'ls command parser'
author = 'Kelly Brazil'
author_email = 'kellyjonbrazil@gmail.com'
# Delete last line if it is blank
if cleandata[-1] == '':
cleandata.pop(-1)
# compatible options: linux, darwin, cygwin, win32, aix, freebsd
compatible = ['linux', 'darwin', 'cygwin', 'aix', 'freebsd']
magic_commands = ['ls']
# Check if -l was used to parse extra data
if re.match('^[-dclpsbDCMnP?]([-r][-w][-xsS]){2}([-r][-w][-xtT])[+]?', cleandata[0]):
for entry in cleandata:
output_line = {}
parsed_line = entry.split()
__version__ = info.version
# split filenames and links
filename_field = ' '.join(parsed_line[8:]).split(' -> ')
# create list of dictionaries
output_line['filename'] = filename_field[0]
def process(proc_data):
"""
Final processing to conform to the schema.
if len(filename_field) > 1:
output_line['link_to'] = filename_field[1]
Parameters:
output_line['flags'] = parsed_line[0]
output_line['links'] = int(parsed_line[1])
output_line['owner'] = parsed_line[2]
output_line['group'] = parsed_line[3]
output_line['bytes'] = int(parsed_line[4])
output_line['date'] = ' '.join(parsed_line[5:8])
output.append(output_line)
proc_data: (dictionary) raw structured data to process
Returns:
List of dictionaries. Structured data with the following schema:
[
{
"filename": string,
"flags": string,
"links": integer,
"parent": string,
"owner": string,
"group": string,
"size": integer,
"date": string
}
]
"""
for entry in proc_data:
int_list = ['links', 'size']
for key in int_list:
if key in entry:
try:
key_int = int(entry[key])
entry[key] = key_int
except (ValueError):
entry[key] = 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)
raw_output = []
linedata = data.splitlines()
# Delete first line if it starts with 'total 1234'
if linedata:
if re.match('^total [0-9]+', linedata[0]):
linedata.pop(0)
parent = ''
next_is_parent = False
# Look for parent line if glob or -R is used
if not re.match('^[-dclpsbDCMnP?]([-r][-w][-xsS]){2}([-r][-w][-xtT])[+]?', linedata[0]) \
and linedata[0].endswith(':'):
parent = linedata.pop(0)[:-1]
# Pop following total line
linedata.pop(0)
if linedata:
# Check if -l was used to parse extra data
if re.match('^[-dclpsbDCMnP?]([-r][-w][-xsS]){2}([-r][-w][-xtT])[+]?', linedata[0]):
for entry in linedata:
output_line = {}
parsed_line = entry.split(maxsplit=8)
if not re.match('^[-dclpsbDCMnP?]([-r][-w][-xsS]){2}([-r][-w][-xtT])[+]?', entry) \
and entry.endswith(':'):
parent = entry[:-1]
continue
if re.match('^total [0-9]+', entry):
continue
if entry == '':
continue
# split filenames and links
filename_field = parsed_line[8].split(' -> ')
# create list of dictionaries
output_line['filename'] = filename_field[0]
if len(filename_field) > 1:
output_line['link_to'] = filename_field[1]
if parent:
output_line['parent'] = parent
output_line['flags'] = parsed_line[0]
output_line['links'] = parsed_line[1]
output_line['owner'] = parsed_line[2]
output_line['group'] = parsed_line[3]
output_line['size'] = parsed_line[4]
output_line['date'] = ' '.join(parsed_line[5:8])
raw_output.append(output_line)
else:
for entry in linedata:
output_line = {}
if entry == '':
next_is_parent = True
continue
if next_is_parent:
parent = entry[:-1]
next_is_parent = False
continue
output_line['filename'] = entry
if parent:
output_line['parent'] = parent
raw_output.append(output_line)
if raw:
return raw_output
else:
for entry in cleandata:
output_line = {}
output_line['filename'] = entry
output.append(output_line)
return output
return process(raw_output)

348
jc/parsers/lsblk.py Normal file
View File

@@ -0,0 +1,348 @@
"""jc - JSON CLI output utility lsblk Parser
Usage:
specify --lsblk as the first argument if the piped input is coming from lsblk
Compatibility:
'linux'
Examples:
$ lsblk | jc --lsblk -p
[
{
"name": "sda",
"maj_min": "8:0",
"rm": false,
"size": "20G",
"ro": false,
"type": "disk",
"mountpoint": null
},
{
"name": "sda1",
"maj_min": "8:1",
"rm": false,
"size": "1G",
"ro": false,
"type": "part",
"mountpoint": "/boot"
},
...
]
$ lsblk -o +KNAME,FSTYPE,LABEL,UUID,PARTLABEL,PARTUUID,RA,MODEL,SERIAL,STATE,OWNER,GROUP,MODE,ALIGNMENT,MIN-IO,OPT-IO,PHY-SEC,LOG-SEC,ROTA,SCHED,RQ-SIZE,DISC-ALN,DISC-GRAN,DISC-MAX,DISC-ZERO,WSAME,WWN,RAND,PKNAME,HCTL,TRAN,REV,VENDOR | jc --lsblk -p
[
{
"name": "sda",
"maj_min": "8:0",
"rm": false,
"size": "20G",
"ro": false,
"type": "disk",
"mountpoint": null,
"kname": "sda",
"fstype": null,
"label": null,
"uuid": null,
"partlabel": null,
"partuuid": null,
"ra": 4096,
"model": "VMware Virtual S",
"serial": null,
"state": "running",
"owner": "root",
"group": "disk",
"mode": "brw-rw----",
"alignment": 0,
"min_io": 512,
"opt_io": 0,
"phy_sec": 512,
"log_sec": 512,
"rota": true,
"sched": "deadline",
"rq_size": 128,
"disc_aln": 0,
"disc_gran": "0B",
"disc_max": "0B",
"disc_zero": false,
"wsame": "32M",
"wwn": null,
"rand": true,
"pkname": null,
"hctl": "0:0:0:0",
"tran": "spi",
"rev": "1.0",
"vendor": "VMware,"
},
{
"name": "sda1",
"maj_min": "8:1",
"rm": false,
"size": "1G",
"ro": false,
"type": "part",
"mountpoint": "/boot",
"kname": "sda1",
"fstype": "xfs",
"label": null,
"uuid": "05d927bb-5875-49e3-ada1-7f46cb31c932",
"partlabel": null,
"partuuid": null,
"ra": 4096,
"model": null,
"serial": null,
"state": null,
"owner": "root",
"group": "disk",
"mode": "brw-rw----",
"alignment": 0,
"min_io": 512,
"opt_io": 0,
"phy_sec": 512,
"log_sec": 512,
"rota": true,
"sched": "deadline",
"rq_size": 128,
"disc_aln": 0,
"disc_gran": "0B",
"disc_max": "0B",
"disc_zero": false,
"wsame": "32M",
"wwn": null,
"rand": true,
"pkname": "sda",
"hctl": null,
"tran": null,
"rev": null,
"vendor": null
},
...
]
$ lsblk -o +KNAME,FSTYPE,LABEL,UUID,PARTLABEL,PARTUUID,RA,MODEL,SERIAL,STATE,OWNER,GROUP,MODE,ALIGNMENT,MIN-IO,OPT-IO,PHY-SEC,LOG-SEC,ROTA,SCHED,RQ-SIZE,DISC-ALN,DISC-GRAN,DISC-MAX,DISC-ZERO,WSAME,WWN,RAND,PKNAME,HCTL,TRAN,REV,VENDOR | jc --lsblk -p -r
[
{
"name": "sda",
"maj_min": "8:0",
"rm": "0",
"size": "20G",
"ro": "0",
"type": "disk",
"mountpoint": null,
"kname": "sda",
"fstype": null,
"label": null,
"uuid": null,
"partlabel": null,
"partuuid": null,
"ra": "4096",
"model": "VMware Virtual S",
"serial": null,
"state": "running",
"owner": "root",
"group": "disk",
"mode": "brw-rw----",
"alignment": "0",
"min_io": "512",
"opt_io": "0",
"phy_sec": "512",
"log_sec": "512",
"rota": "1",
"sched": "deadline",
"rq_size": "128",
"disc_aln": "0",
"disc_gran": "0B",
"disc_max": "0B",
"disc_zero": "0",
"wsame": "32M",
"wwn": null,
"rand": "1",
"pkname": null,
"hctl": "0:0:0:0",
"tran": "spi",
"rev": "1.0",
"vendor": "VMware,"
},
{
"name": "sda1",
"maj_min": "8:1",
"rm": "0",
"size": "1G",
"ro": "0",
"type": "part",
"mountpoint": "/boot",
"kname": "sda1",
"fstype": "xfs",
"label": null,
"uuid": "05d927bb-5875-49e3-ada1-7f46cb31c932",
"partlabel": null,
"partuuid": null,
"ra": "4096",
"model": null,
"serial": null,
"state": null,
"owner": "root",
"group": "disk",
"mode": "brw-rw----",
"alignment": "0",
"min_io": "512",
"opt_io": "0",
"phy_sec": "512",
"log_sec": "512",
"rota": "1",
"sched": "deadline",
"rq_size": "128",
"disc_aln": "0",
"disc_gran": "0B",
"disc_max": "0B",
"disc_zero": "0",
"wsame": "32M",
"wwn": null,
"rand": "1",
"pkname": "sda",
"hctl": null,
"tran": null,
"rev": null,
"vendor": null
},
...
]
"""
import jc.utils
import jc.parsers.universal
class info():
version = '1.3'
description = 'lsblk command parser'
author = 'Kelly Brazil'
author_email = 'kellyjonbrazil@gmail.com'
# compatible options: linux, darwin, cygwin, win32, aix, freebsd
compatible = ['linux']
magic_commands = ['lsblk']
__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:
[
{
"name": string,
"maj_min": string,
"rm": boolean,
"size": string,
"ro": boolean,
"type": string,
"mountpoint": string,
"kname": string,
"fstype": string,
"label": string,
"uuid": string,
"partlabel": string,
"partuuid": string,
"ra": integer,
"model": string,
"serial": string,
"state": string,
"owner": string,
"group": string,
"mode": string,
"alignment": integer,
"min_io": integer,
"opt_io": integer,
"phy_sec": integer,
"log_sec": integer,
"rota": boolean,
"sched": string,
"rq_size": integer,
"disc_aln": integer,
"disc_gran": string,
"disc_max": string,
"disc_zero": boolean,
"wsame": string,
"wwn": string,
"rand": boolean,
"pkname": string,
"hctl": string,
"tran": string,
"rev": string,
"vendor": string
}
]
"""
for entry in proc_data:
# boolean changes
bool_list = ['rm', 'ro', 'rota', 'disc_zero', 'rand']
for key in bool_list:
if key in entry:
try:
key_bool = bool(int(entry[key]))
entry[key] = key_bool
except (ValueError):
entry[key] = None
# integer changes
int_list = ['ra', 'alignment', 'min_io', 'opt_io', 'phy_sec', 'log_sec', 'rq_size', 'disc_aln']
for key in int_list:
if key in entry:
try:
key_int = int(entry[key])
entry[key] = key_int
except (ValueError):
entry[key] = 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)
linedata = data.splitlines()
# Clear any blank lines
cleandata = list(filter(None, linedata))
cleandata = data.splitlines()
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
else:
return process(raw_output)

189
jc/parsers/lsmod.py Normal file
View File

@@ -0,0 +1,189 @@
"""jc - JSON CLI output utility lsmod Parser
Usage:
specify --lsmod as the first argument if the piped input is coming from lsmod
Compatibility:
'linux'
Examples:
$ lsmod | jc --lsmod -p
[
...
{
"module": "nf_nat",
"size": 26583,
"used": 3,
"by": [
"nf_nat_ipv4",
"nf_nat_ipv6",
"nf_nat_masquerade_ipv4"
]
},
{
"module": "iptable_mangle",
"size": 12695,
"used": 1
},
{
"module": "iptable_security",
"size": 12705,
"used": 1
},
{
"module": "iptable_raw",
"size": 12678,
"used": 1
},
{
"module": "nf_conntrack",
"size": 139224,
"used": 7,
"by": [
"nf_nat",
"nf_nat_ipv4",
"nf_nat_ipv6",
"xt_conntrack",
"nf_nat_masquerade_ipv4",
"nf_conntrack_ipv4",
"nf_conntrack_ipv6"
]
},
...
]
$ lsmod | jc --lsmod -p -r
[
...
{
"module": "nf_conntrack",
"size": "139224",
"used": "7",
"by": [
"nf_nat",
"nf_nat_ipv4",
"nf_nat_ipv6",
"xt_conntrack",
"nf_nat_masquerade_ipv4",
"nf_conntrack_ipv4",
"nf_conntrack_ipv6"
]
},
{
"module": "ip_set",
"size": "45799",
"used": "0"
},
{
"module": "nfnetlink",
"size": "14519",
"used": "1",
"by": [
"ip_set"
]
},
{
"module": "ebtable_filter",
"size": "12827",
"used": "1"
},
{
"module": "ebtables",
"size": "35009",
"used": "2",
"by": [
"ebtable_nat",
"ebtable_filter"
]
},
...
]
"""
import jc.utils
import jc.parsers.universal
class info():
version = '1.1'
description = 'lsmod command parser'
author = 'Kelly Brazil'
author_email = 'kellyjonbrazil@gmail.com'
# compatible options: linux, darwin, cygwin, win32, aix, freebsd
compatible = ['linux']
magic_commands = ['lsmod']
__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:
[
{
"module": string,
"size": integer,
"used": integer,
"by": [
string
]
}
]
"""
for entry in proc_data:
# integer changes
int_list = ['size', 'used']
for key in int_list:
if key in entry:
try:
key_int = int(entry[key])
entry[key] = key_int
except (ValueError):
entry[key] = 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)
cleandata = data.splitlines()
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
else:
return process(raw_output)

227
jc/parsers/lsof.py Normal file
View File

@@ -0,0 +1,227 @@
"""jc - JSON CLI output utility lsof Parser
Usage:
specify --lsof as the first argument if the piped input is coming from lsof
Compatibility:
'linux'
Examples:
$ sudo lsof | jc --lsof -p
[
{
"command": "systemd",
"pid": 1,
"tid": null,
"user": "root",
"fd": "cwd",
"type": "DIR",
"device": "253,0",
"size_off": 224,
"node": 64,
"name": "/"
},
{
"command": "systemd",
"pid": 1,
"tid": null,
"user": "root",
"fd": "rtd",
"type": "DIR",
"device": "253,0",
"size_off": 224,
"node": 64,
"name": "/"
},
{
"command": "systemd",
"pid": 1,
"tid": null,
"user": "root",
"fd": "txt",
"type": "REG",
"device": "253,0",
"size_off": 1624520,
"node": 50360451,
"name": "/usr/lib/systemd/systemd"
},
...
]
$ sudo lsof | jc --lsof -p -r
[
{
"command": "systemd",
"pid": "1",
"tid": null,
"user": "root",
"fd": "cwd",
"type": "DIR",
"device": "8,2",
"size_off": "4096",
"node": "2",
"name": "/"
},
{
"command": "systemd",
"pid": "1",
"tid": null,
"user": "root",
"fd": "rtd",
"type": "DIR",
"device": "8,2",
"size_off": "4096",
"node": "2",
"name": "/"
},
{
"command": "systemd",
"pid": "1",
"tid": null,
"user": "root",
"fd": "txt",
"type": "REG",
"device": "8,2",
"size_off": "1595792",
"node": "668802",
"name": "/lib/systemd/systemd"
},
...
]
"""
import jc.utils
import jc.parsers.universal
class info():
version = '1.0'
description = 'lsof command parser'
author = 'Kelly Brazil'
author_email = 'kellyjonbrazil@gmail.com'
# compatible options: linux, darwin, cygwin, win32, aix, freebsd
compatible = ['linux']
magic_commands = ['lsof']
__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:
[
{
"command": string,
"pid": integer,
"tid": integer,
"user": string,
"fd": string,
"type": string,
"device": string,
"size_off": integer,
"node": integer,
"name": string
}
]
"""
for entry in proc_data:
# integer changes
int_list = ['pid', 'tid', 'size_off', 'node']
for key in int_list:
if key in entry:
try:
key_int = int(entry[key])
entry[key] = key_int
except (ValueError, TypeError):
entry[key] = 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)
raw_output = []
linedata = data.splitlines()
# Clear any blank lines
cleandata = list(filter(None, linedata))
if cleandata:
cleandata[0] = cleandata[0].lower()
cleandata[0] = cleandata[0].replace('/', '_')
raw_output = jc.parsers.universal.sparse_table_parse(cleandata)
'''
# find column value of last character of each header
header_text = cleandata.pop(0).lower()
# clean up 'size/off' header
# even though forward slash in a key is valid json, it can make things difficult
header_row = header_text.replace('/', '_')
headers = header_row.split()
header_spec = []
for i, h in enumerate(headers):
# header tuple is (index, header_name, col)
header_spec.append((i, h, header_row.find(h) + len(h)))
# parse lines
for entry in cleandata:
output_line = {}
# normalize data by inserting Null for missing data
temp_line = entry.split(maxsplit=len(headers) - 1)
for spec in header_spec:
index = spec[0]
header_name = spec[1]
col = spec[2] - 1 # subtract one since column starts at 0 instead of 1
if header_name == 'command' or header_name == 'name':
continue
if entry[col] in string.whitespace:
temp_line.insert(index, None)
name = ' '.join(temp_line[9:])
fixed_line = temp_line[0:9]
fixed_line.append(name)
output_line = dict(zip(headers, fixed_line))
raw_output.append(output_line)
'''
if raw:
return raw_output
else:
return process(raw_output)

177
jc/parsers/mount.py Normal file
View File

@@ -0,0 +1,177 @@
"""jc - JSON CLI output utility mount Parser
Usage:
specify --mount as the first argument if the piped input is coming from mount
Compatibility:
'linux', 'darwin'
Example:
$ mount | jc --mount -p
[
{
"filesystem": "sysfs",
"mount_point": "/sys",
"type": "sysfs",
"access": [
"rw",
"nosuid",
"nodev",
"noexec",
"relatime"
]
},
{
"filesystem": "proc",
"mount_point": "/proc",
"type": "proc",
"access": [
"rw",
"nosuid",
"nodev",
"noexec",
"relatime"
]
},
{
"filesystem": "udev",
"mount_point": "/dev",
"type": "devtmpfs",
"access": [
"rw",
"nosuid",
"relatime",
"size=977500k",
"nr_inodes=244375",
"mode=755"
]
},
...
]
"""
import jc.utils
class info():
version = '1.1'
description = 'mount command parser'
author = 'Kelly Brazil'
author_email = 'kellyjonbrazil@gmail.com'
# compatible options: linux, darwin, cygwin, win32, aix, freebsd
compatible = ['linux', 'darwin']
magic_commands = ['mount']
__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:
[
{
"filesystem": string,
"mount_point": string,
"type": string,
"access": [
string
]
}
]
"""
# nothing to process
return proc_data
def osx_parse(data):
output = []
for entry in data:
output_line = {}
filesystem = entry.split(' on ')
filesystem = filesystem[0]
output_line['filesystem'] = filesystem
mount_point = entry.split(' on ')
mount_point = mount_point[1].split(' (')
mount_point = mount_point[0]
output_line['mount_point'] = mount_point
options = entry.split('(', maxsplit=1)
options = options[1].rstrip(')')
options = options.split(', ')
output_line['options'] = options
output.append(output_line)
return output
def linux_parse(data):
output = []
for entry in data:
output_line = {}
parsed_line = entry.split()
output_line['filesystem'] = parsed_line[0]
output_line['mount_point'] = parsed_line[2]
output_line['type'] = parsed_line[4]
options = parsed_line[5].lstrip('(').rstrip(')').split(',')
output_line['options'] = options
output.append(output_line)
return output
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)
linedata = data.splitlines()
# Clear any blank lines
cleandata = list(filter(None, linedata))
if cleandata:
# check for OSX output
if cleandata[0].find(' type ') == -1:
raw_output = osx_parse(cleandata)
else:
raw_output = linux_parse(cleandata)
if raw:
return raw_output
else:
return process(raw_output)

View File

@@ -1,314 +1,579 @@
"""jc - JSON CLI output utility netstat Parser
Usage:
Specify --netstat as the first argument if the piped input is coming from netstat
Supports -lnp netstat options
Compatibility:
Limitations:
Only supports TCP and UDP
'linux'
Examples:
$ netstat -p | jc --netstat -p
{
"client": {
"tcp": {
"ipv4": [
{
"local_address": "localhost.localdo",
"local_port": "34480",
"foreign_address": "lb-192-30-255-113",
"foreign_port": "https",
"state": "ESTABLISHED",
"pid": 53550,
"program_name": "git-remote-ht",
"receive_q": 0,
"send_q": 0
},
{
"local_address": "localhost.localdo",
"local_port": "34478",
"foreign_address": "lb-192-30-255-113",
"foreign_port": "https",
"state": "ESTABLISHED",
"pid": 53550,
"program_name": "git-remote-ht",
"receive_q": 0,
"send_q": 0
}
]
}
}
}
$ sudo netstat -apee | 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"
},
{
"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"
},
{
"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",
"foreign_port_num": 52186
},
{
"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",
"local_port_num": 52186
},
{
"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
},
...
]
$ netstat -lp | jc --netstat -p
{
"server": {
"tcp": {
"ipv4": [
{
"local_address": "localhost",
"local_port": "smtp",
"foreign_address": "0.0.0.0",
"foreign_port": "*",
"state": "LISTEN",
"pid": 1594,
"program_name": "master",
"receive_q": 0,
"send_q": 0
},
{
"local_address": "0.0.0.0",
"local_port": "ssh",
"foreign_address": "0.0.0.0",
"foreign_port": "*",
"state": "LISTEN",
"pid": 21918,
"program_name": "sshd",
"receive_q": 0,
"send_q": 0
}
],
"ipv6": [
{
"local_address": "localhost",
"local_port": "smtp",
"foreign_address": "[::]",
"foreign_port": "*",
"state": "LISTEN",
"pid": 1594,
"program_name": "master",
"receive_q": 0,
"send_q": 0
},
{
"local_address": "[::]",
"local_port": "ssh",
"foreign_address": "[::]",
"foreign_port": "*",
"state": "LISTEN",
"pid": 21918,
"program_name": "sshd",
"receive_q": 0,
"send_q": 0
}
]
},
"udp": {
"ipv4": [
{
"local_address": "0.0.0.0",
"local_port": "bootpc",
"foreign_address": "0.0.0.0",
"foreign_port": "*",
"pid": 13903,
"program_name": "dhclient",
"receive_q": 0,
"send_q": 0
},
{
"local_address": "localhost",
"local_port": "323",
"foreign_address": "0.0.0.0",
"foreign_port": "*",
"pid": 30926,
"program_name": "chronyd",
"receive_q": 0,
"send_q": 0
}
],
"ipv6": [
{
"local_address": "localhost",
"local_port": "323",
"foreign_address": "[::]",
"foreign_port": "*",
"pid": 30926,
"program_name": "chronyd",
"receive_q": 0,
"send_q": 0
}
]
}
}
}
$ sudo netstat -apee | jc --netstat -p -r
[
{
"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"
},
{
"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"
},
{
"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"
},
...
]
"""
import string
import jc.utils
output = {}
class state():
section = ''
session = ''
network = ''
class info():
version = '1.2'
description = 'netstat command parser'
author = 'Kelly Brazil'
author_email = 'kellyjonbrazil@gmail.com'
client_tcp_ip4 = []
client_tcp_ip6 = []
client_udp_ip4 = []
client_udp_ip6 = []
server_tcp_ip4 = []
server_tcp_ip6 = []
server_udp_ip4 = []
server_udp_ip6 = []
# compatible options: linux, darwin, cygwin, win32, aix, freebsd
compatible = ['linux']
magic_commands = ['netstat']
def parse_line(entry):
parsed_line = entry.split()
output_line = {}
output_line['local_address'] = parsed_line[3].rsplit(':', 1)[0]
output_line['local_port'] = parsed_line[3].rsplit(':', 1)[-1]
output_line['foreign_address'] = parsed_line[4].rsplit(':', 1)[0]
output_line['foreign_port'] = parsed_line[4].rsplit(':', 1)[-1]
__version__ = info.version
if len(parsed_line) > 5:
if parsed_line[5][0] not in string.digits:
output_line['state'] = parsed_line[5]
if len(parsed_line) > 6:
output_line['pid'] = int(parsed_line[6].split('/')[0])
output_line['program_name'] = parsed_line[6].split('/')[1]
else:
output_line['pid'] = int(parsed_line[5].split('/')[0])
output_line['program_name'] = parsed_line[5].split('/')[1]
def process(proc_data):
"""
Final processing to conform to the schema.
output_line['receive_q'] = int(parsed_line[1])
output_line['send_q'] = int(parsed_line[2])
Parameters:
proc_data: (dictionary) raw structured data to process
Returns:
List of dictionaries. Structured data with the following schema:
[
{
"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
}
]
"""
for entry in proc_data:
# integer changes
int_list = ['recv_q', 'send_q', 'pid', 'refcnt', 'inode']
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 'local_port' in entry:
try:
entry['local_port_num'] = int(entry['local_port'])
except (ValueError):
pass
if 'foreign_port' in entry:
try:
entry['foreign_port_num'] = int(entry['foreign_port'])
except (ValueError):
pass
return proc_data
def normalize_headers(header):
header = header.lower()
header = header.replace('local address', 'local_address')
header = header.replace('foreign address', 'foreign_address')
header = header.replace('pid/program name', 'program_name')
header = header.replace('security context', 'security_context')
header = header.replace('i-node', 'inode')
header = header.replace('-', '_')
return header
def parse_network(headers, entry):
# Count words in header
# if len of line is one less than len of header, then insert None in field 5
entry = entry.split(maxsplit=len(headers) - 1)
if len(entry) == len(headers) - 1:
entry.insert(5, None)
output_line = dict(zip(headers, entry))
output_line['kind'] = 'network'
return output_line
def parse(data):
def parse_socket(header_text, headers, entry):
output_line = {}
# get the column # of first letter of "state"
state_col = header_text.find('state')
# get the program name column area
pn_start = header_text.find('program_name')
pn_end = header_text.find('path') - 1
# remove [ and ] from each line
entry = entry.replace('[ ]', '---')
entry = entry.replace('[', ' ').replace(']', ' ')
# find program_name column area and substitute spaces with \u2063 there
old_pn = entry[pn_start:pn_end]
new_pn = old_pn.replace(' ', '\u2063')
entry = entry.replace(old_pn, new_pn)
entry_list = entry.split(maxsplit=len(headers) - 1)
# check column # to see if state column is populated
if entry[state_col] in string.whitespace:
entry_list.insert(4, None)
output_line = dict(zip(headers, entry_list))
output_line['kind'] = 'socket'
# fix program_name field to turn \u2063 back to spaces
if 'program_name' in output_line:
if output_line['program_name']:
old_d_pn = output_line['program_name']
new_d_pn = old_d_pn.replace('\u2063', ' ')
output_line['program_name'] = new_d_pn
return output_line
def parse_post(raw_data):
# clean up trailing whitespace on each item in each entry
# flags --- = null
# program_name - = null
# split pid and program name and ip addresses and ports
# create network and transport protocol fields
for entry in raw_data:
for item in entry:
try:
entry[item] = entry[item].rstrip()
except (AttributeError):
# skips trying to rstrip Null entries
pass
if 'flags' in entry:
if entry['flags'] == '---':
entry['flags'] = None
if 'program_name' in entry:
entry['program_name'] = entry['program_name'].strip()
if entry['program_name'] == '-':
entry['program_name'] = None
if entry['program_name']:
pid = entry['program_name'].split('/', maxsplit=1)[0]
name = entry['program_name'].split('/', maxsplit=1)[1]
entry['pid'] = pid
entry['program_name'] = name
if 'local_address' in entry:
if entry['local_address']:
ladd = entry['local_address'].rsplit(':', maxsplit=1)[0]
lport = entry['local_address'].rsplit(':', maxsplit=1)[1]
entry['local_address'] = ladd
entry['local_port'] = lport
if 'foreign_address' in entry:
if entry['foreign_address']:
fadd = entry['foreign_address'].rsplit(':', maxsplit=1)[0]
fport = entry['foreign_address'].rsplit(':', maxsplit=1)[1]
entry['foreign_address'] = fadd
entry['foreign_port'] = fport
if 'proto' in entry and 'kind' in entry:
if entry['kind'] == 'network':
if entry['proto'].find('tcp') != -1:
entry['transport_protocol'] = 'tcp'
elif entry['proto'].find('udp') != -1:
entry['transport_protocol'] = 'udp'
else:
entry['transport_protocol'] = None
if entry['proto'].find('6') != -1:
entry['network_protocol'] = 'ipv6'
else:
entry['network_protocol'] = 'ipv4'
return raw_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)
cleandata = data.splitlines()
cleandata = list(filter(None, cleandata))
raw_output = []
network = False
socket = False
headers = ''
network_list = []
socket_list = []
for line in cleandata:
if line.find('Active Internet connections (w/o servers)') == 0:
state.section = "client"
continue
if line.find('Active Internet connections (only servers)') == 0:
state.section = "server"
continue
if line.find('Proto') == 0:
if line.find('Active Internet') == 0:
network_list = []
network = True
socket = False
continue
if line.find('Active UNIX') == 0:
break
if state.section == 'client':
if line.find('tcp') == 0:
state.session = 'tcp'
if line.find('p6') == 2:
state.network = 'ipv6'
else:
state.network = 'ipv4'
elif line.find('udp') == 0:
state.session = 'udp'
if line.find('p6') == 2:
state.network = 'ipv6'
else:
state.network = 'ipv4'
elif state.section == 'server':
if line.find('tcp') == 0:
state.session = 'tcp'
if line.find('p6') == 2:
state.network = 'ipv6'
else:
state.network = 'ipv4'
elif line.find('udp') == 0:
state.session = 'udp'
if line.find('p6') == 2:
state.network = 'ipv6'
else:
state.network = 'ipv4'
socket_list = []
network = False
socket = True
continue
if state.section == 'client' and state.session == 'tcp' and state.network == 'ipv4':
state.client_tcp_ip4.append(parse_line(line))
if line.find('Proto') == 0:
header_text = normalize_headers(line)
headers = header_text.split()
continue
if state.section == 'client' and state.session == 'tcp' and state.network == 'ipv6':
state.client_tcp_ip6.append(parse_line(line))
if network:
network_list.append(parse_network(headers, line))
continue
if state.section == 'client' and state.session == 'udp' and state.network == 'ipv4':
state.client_udp_ip4.append(parse_line(line))
if socket:
socket_list.append(parse_socket(header_text, headers, line))
continue
if state.section == 'client' and state.session == 'udp' and state.network == 'ipv6':
state.client_udp_ip6.append(parse_line(line))
for item in [network_list, socket_list]:
for entry in item:
raw_output.append(entry)
raw_output = parse_post(raw_output)
if state.section == 'server' and state.session == 'tcp' and state.network == 'ipv4':
state.server_tcp_ip4.append(parse_line(line))
if state.section == 'server' and state.session == 'tcp' and state.network == 'ipv6':
state.server_tcp_ip6.append(parse_line(line))
if state.section == 'server' and state.session == 'udp' and state.network == 'ipv4':
state.server_udp_ip4.append(parse_line(line))
if state.section == 'server' and state.session == 'udp' and state.network == 'ipv6':
state.server_udp_ip6.append(parse_line(line))
state.session = ''
state.network = ''
# build dictionary
if state.client_tcp_ip4:
if 'client' not in output:
output['client'] = {}
if 'tcp' not in output['client']:
output['client']['tcp'] = {}
output['client']['tcp']['ipv4'] = state.client_tcp_ip4
if state.client_tcp_ip6:
if 'client' not in output:
output['client'] = {}
if 'tcp' not in output['client']:
output['client']['tcp'] = {}
output['client']['tcp']['ipv6'] = state.client_tcp_ip6
if state.client_udp_ip4:
if 'client' not in output:
output['client'] = {}
if 'udp' not in output['client']:
output['client']['udp'] = {}
output['client']['udp']['ipv4'] = state.client_udp_ip4
if state.client_udp_ip6:
if 'client' not in output:
output['client'] = {}
if 'udp' not in output['client']:
output['client']['udp'] = {}
output['client']['udp']['ipv6'] = state.client_udp_ip6
if state.server_tcp_ip4:
if 'server' not in output:
output['server'] = {}
if 'tcp' not in output['server']:
output['server']['tcp'] = {}
output['server']['tcp']['ipv4'] = state.server_tcp_ip4
if state.server_tcp_ip6:
if 'server' not in output:
output['server'] = {}
if 'tcp' not in output['server']:
output['server']['tcp'] = {}
output['server']['tcp']['ipv6'] = state.server_tcp_ip6
if state.server_udp_ip4:
if 'server' not in output:
output['server'] = {}
if 'udp' not in output['server']:
output['server']['udp'] = {}
output['server']['udp']['ipv4'] = state.server_udp_ip4
if state.server_udp_ip6:
if 'server' not in output:
output['server'] = {}
if 'udp' not in output['server']:
output['server']['udp'] = {}
output['server']['udp']['ipv6'] = state.server_udp_ip6
return output
if raw:
return raw_output
else:
return process(raw_output)

117
jc/parsers/pip_list.py Normal file
View File

@@ -0,0 +1,117 @@
"""jc - JSON CLI output utility pip-list Parser
Usage:
specify --pip-list as the first argument if the piped input is coming from pip list
Compatibility:
'linux', 'darwin', 'cygwin', 'win32', 'aix', 'freebsd'
Examples:
$ pip list | jc --pip-list -p
[
{
"package": "ansible",
"version": "2.8.5"
},
{
"package": "antlr4-python3-runtime",
"version": "4.7.2"
},
{
"package": "asn1crypto",
"version": "0.24.0"
},
...
]
"""
import jc.utils
import jc.parsers.universal
class info():
version = '1.0'
description = 'pip list command parser'
author = 'Kelly Brazil'
author_email = 'kellyjonbrazil@gmail.com'
# compatible options: linux, darwin, cygwin, win32, aix, freebsd
compatible = ['linux', 'darwin', 'cygwin', 'win32', 'aix', 'freebsd']
magic_commands = ['pip list', 'pip3 list']
__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:
[
{
"package": string,
"version": string,
"location": string
}
]
"""
# no further processing
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)
raw_output = []
linedata = data.splitlines()
# Clear any blank lines
cleandata = list(filter(None, linedata))
# detect legacy output type
if cleandata[0].find(' (') != -1:
for row in cleandata:
raw_output.append({'package': row.split(' (')[0],
'version': row.split(' (')[1].rstrip(')')})
# otherwise normal table output
else:
# clear separator line
for i, line in reversed(list(enumerate(cleandata))):
if line.find('---') != -1:
cleandata.pop(i)
cleandata[0] = cleandata[0].lower()
if cleandata:
raw_output = jc.parsers.universal.simple_table_parse(cleandata)
if raw:
return raw_output
else:
return process(raw_output)

135
jc/parsers/pip_show.py Normal file
View File

@@ -0,0 +1,135 @@
"""jc - JSON CLI output utility pip-show Parser
Usage:
specify --pip-show as the first argument if the piped input is coming from pip show
Compatibility:
'linux', 'darwin', 'cygwin', 'win32', 'aix', 'freebsd'
Examples:
$ pip show wrapt jc wheel | jc --pip-show -p
[
{
"name": "wrapt",
"version": "1.11.2",
"summary": "Module for decorators, wrappers and monkey patching.",
"home_page": "https://github.com/GrahamDumpleton/wrapt",
"author": "Graham Dumpleton",
"author_email": "Graham.Dumpleton@gmail.com",
"license": "BSD",
"location": "/usr/local/lib/python3.7/site-packages",
"requires": null,
"required_by": "astroid"
},
{
"name": "wheel",
"version": "0.33.4",
"summary": "A built-package format for Python.",
"home_page": "https://github.com/pypa/wheel",
"author": "Daniel Holth",
"author_email": "dholth@fastmail.fm",
"license": "MIT",
"location": "/usr/local/lib/python3.7/site-packages",
"requires": null,
"required_by": null
}
]
"""
import jc.utils
class info():
version = '1.0'
description = 'pip show command parser'
author = 'Kelly Brazil'
author_email = 'kellyjonbrazil@gmail.com'
# compatible options: linux, darwin, cygwin, win32, aix, freebsd
compatible = ['linux', 'darwin', 'cygwin', 'win32', 'aix', 'freebsd']
magic_commands = ['pip show', 'pip3 show']
__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:
[
{
"name": string,
"version": string,
"summary": string,
"home_page": string,
"author": string,
"author_email": string,
"license": string,
"location": string,
"requires": string,
"required_by": string
}
]
"""
# no further processing
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)
raw_output = []
package = {}
linedata = data.splitlines()
# Clear any blank lines
cleandata = list(filter(None, linedata))
if cleandata:
for row in cleandata:
if row.startswith('---'):
raw_output.append(package)
package = {}
continue
item_key = row.split(': ', maxsplit=1)[0].lower().replace('-', '_')
item_value = row.split(': ', maxsplit=1)[1]
if item_value == '':
item_value = None
package.update({item_key: item_value})
raw_output.append(package)
if raw:
return raw_output
else:
return process(raw_output)

292
jc/parsers/ps.py Normal file
View File

@@ -0,0 +1,292 @@
"""jc - JSON CLI output utility ps Parser
Usage:
specify --ps as the first argument if the piped input is coming from ps
ps options supported:
- ef
- axu
Compatibility:
'linux', 'darwin', 'cygwin', 'aix', 'freebsd'
Examples:
$ ps -ef | jc --ps -p
[
{
"uid": "root",
"pid": 1,
"ppid": 0,
"c": 0,
"stime": "Nov01",
"tty": null,
"time": "00:00:11",
"cmd": "/usr/lib/systemd/systemd --switched-root --system --deserialize 22"
},
{
"uid": "root",
"pid": 2,
"ppid": 0,
"c": 0,
"stime": "Nov01",
"tty": null,
"time": "00:00:00",
"cmd": "[kthreadd]"
},
{
"uid": "root",
"pid": 4,
"ppid": 2,
"c": 0,
"stime": "Nov01",
"tty": null,
"time": "00:00:00",
"cmd": "[kworker/0:0H]"
},
...
]
$ ps -ef | jc --ps -p -r
[
{
"uid": "root",
"pid": "1",
"ppid": "0",
"c": "0",
"stime": "Nov01",
"tty": "?",
"time": "00:00:11",
"cmd": "/usr/lib/systemd/systemd --switched-root --system --deserialize 22"
},
{
"uid": "root",
"pid": "2",
"ppid": "0",
"c": "0",
"stime": "Nov01",
"tty": "?",
"time": "00:00:00",
"cmd": "[kthreadd]"
},
{
"uid": "root",
"pid": "4",
"ppid": "2",
"c": "0",
"stime": "Nov01",
"tty": "?",
"time": "00:00:00",
"cmd": "[kworker/0:0H]"
},
...
]
$ ps axu | jc --ps -p
[
{
"user": "root",
"pid": 1,
"cpu_percent": 0.0,
"mem_percent": 0.1,
"vsz": 128072,
"rss": 6784,
"tty": null,
"stat": "Ss",
"start": "Nov09",
"time": "0:08",
"command": "/usr/lib/systemd/systemd --switched-root --system --deserialize 22"
},
{
"user": "root",
"pid": 2,
"cpu_percent": 0.0,
"mem_percent": 0.0,
"vsz": 0,
"rss": 0,
"tty": null,
"stat": "S",
"start": "Nov09",
"time": "0:00",
"command": "[kthreadd]"
},
{
"user": "root",
"pid": 4,
"cpu_percent": 0.0,
"mem_percent": 0.0,
"vsz": 0,
"rss": 0,
"tty": null,
"stat": "S<",
"start": "Nov09",
"time": "0:00",
"command": "[kworker/0:0H]"
},
...
]
$ ps axu | jc --ps -p -r
[
{
"user": "root",
"pid": "1",
"cpu_percent": "0.0",
"mem_percent": "0.1",
"vsz": "128072",
"rss": "6784",
"tty": "?",
"stat": "Ss",
"start": "Nov09",
"time": "0:08",
"command": "/usr/lib/systemd/systemd --switched-root --system --deserialize 22"
},
{
"user": "root",
"pid": "2",
"cpu_percent": "0.0",
"mem_percent": "0.0",
"vsz": "0",
"rss": "0",
"tty": "?",
"stat": "S",
"start": "Nov09",
"time": "0:00",
"command": "[kthreadd]"
},
{
"user": "root",
"pid": "4",
"cpu_percent": "0.0",
"mem_percent": "0.0",
"vsz": "0",
"rss": "0",
"tty": "?",
"stat": "S<",
"start": "Nov09",
"time": "0:00",
"command": "[kworker/0:0H]"
},
...
]
"""
import jc.utils
import jc.parsers.universal
class info():
version = '1.1'
description = 'ps command parser'
author = 'Kelly Brazil'
author_email = 'kellyjonbrazil@gmail.com'
# compatible options: linux, darwin, cygwin, win32, aix, freebsd
compatible = ['linux', 'darwin', 'cygwin', 'aix', 'freebsd']
magic_commands = ['ps']
__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:
[
{
"uid": string,
"pid": integer,
"ppid": integer,
"c": integer,
"stime": string,
"tty": string, # ? or ?? = Null
"tt": string, # ?? = Null
"time": string,
"cmd": string,
"user": string,
"cpu_percent": float,
"mem_percent": float,
"vsz": integer,
"rss": integer,
"stat": string,
"start": string,
"command": string
}
]
"""
for entry in proc_data:
# change key name '%cpu' to 'cpu_percent'
if '%cpu' in entry:
entry['cpu_percent'] = entry.pop('%cpu')
# change key name '%mem' to 'mem_percent'
if '%mem' in entry:
entry['mem_percent'] = entry.pop('%mem')
# change to int
int_list = ['pid', 'ppid', 'c', 'vsz', 'rss']
for key in int_list:
if key in entry:
try:
key_int = int(entry[key])
entry[key] = key_int
except (ValueError):
entry[key] = None
# change to float
float_list = ['cpu_percent', 'mem_percent']
for key in float_list:
if key in entry:
try:
key_float = float(entry[key])
entry[key] = key_float
except (ValueError):
entry[key] = None
if 'tty' in entry:
if entry['tty'] == '?' or entry['tty'] == '??':
entry['tty'] = None
if 'tt' in entry:
if entry['tt'] == '??':
entry['tt'] = 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)
cleandata = data.splitlines()
cleandata[0] = cleandata[0].lower()
raw_output = jc.parsers.universal.simple_table_parse(cleandata)
if raw:
return raw_output
else:
return process(raw_output)

183
jc/parsers/route.py Normal file
View File

@@ -0,0 +1,183 @@
"""jc - JSON CLI output utility route Parser
Usage:
specify --route as the first argument if the piped input is coming from route
Compatibility:
'linux'
Examples:
$ route -ee | jc --route -p
[
{
"destination": "default",
"gateway": "gateway",
"genmask": "0.0.0.0",
"flags": "UG",
"metric": 100,
"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
},
{
"destination": "192.168.71.0",
"gateway": "0.0.0.0",
"genmask": "255.255.255.0",
"flags": "U",
"metric": 100,
"ref": 0,
"use": 0,
"iface": "ens33",
"mss": 0,
"window": 0,
"irtt": 0
}
]
$ route -ee | jc --route -p -r
[
{
"destination": "default",
"gateway": "gateway",
"genmask": "0.0.0.0",
"flags": "UG",
"metric": "100",
"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"
},
{
"destination": "192.168.71.0",
"gateway": "0.0.0.0",
"genmask": "255.255.255.0",
"flags": "U",
"metric": "100",
"ref": "0",
"use": "0",
"iface": "ens33",
"mss": "0",
"window": "0",
"irtt": "0"
}
]
"""
import jc.utils
import jc.parsers.universal
class info():
version = '1.0'
description = 'route command parser'
author = 'Kelly Brazil'
author_email = 'kellyjonbrazil@gmail.com'
# compatible options: linux, darwin, cygwin, win32, aix, freebsd
compatible = ['linux']
magic_commands = ['route']
__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:
[
{
"destination": string,
"gateway": string,
"genmask": string,
"flags": string,
"metric": integer,
"ref": integer,
"use": integer,
"mss": integer,
"window": integer,
"irtt": integer,
"iface": string
}
]
"""
for entry in proc_data:
int_list = ['metric', 'ref', 'use', 'mss', 'window', 'irtt']
for key in int_list:
if key in entry:
try:
key_int = int(entry[key])
entry[key] = key_int
except (ValueError):
entry[key] = 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)
cleandata = data.splitlines()[1:]
cleandata[0] = cleandata[0].lower()
raw_output = jc.parsers.universal.simple_table_parse(cleandata)
if raw:
return raw_output
else:
return process(raw_output)

413
jc/parsers/ss.py Normal file
View File

@@ -0,0 +1,413 @@
"""jc - JSON CLI output utility ss Parser
Usage:
specify --ss as the first argument if the piped input is coming from ss
Limitations:
Extended information options like -e and -p are not supported and may cause parsing irregularities
Compatibility:
'linux'
Examples:
$ sudo ss -a | jc --ss -p
[
{
"netid": "nl",
"state": "UNCONN",
"recv_q": 0,
"send_q": 0,
"peer_address": "*",
"channel": "rtnl:kernel"
},
{
"netid": "nl",
"state": "UNCONN",
"recv_q": 0,
"send_q": 0,
"peer_address": "*",
"pid": 893,
"channel": "rtnl:systemd-resolve"
},
...
{
"netid": "p_raw",
"state": "UNCONN",
"recv_q": 0,
"send_q": 0,
"peer_address": "*",
"link_layer": "LLDP",
"interface": "ens33"
},
{
"netid": "u_dgr",
"state": "UNCONN",
"recv_q": 0,
"send_q": 0,
"local_port": "93066",
"peer_address": "*",
"peer_port": "0",
"path": "/run/user/1000/systemd/notify"
},
{
"netid": "u_seq",
"state": "LISTEN",
"recv_q": 0,
"send_q": 128,
"local_port": "20699",
"peer_address": "*",
"peer_port": "0",
"path": "/run/udev/control"
},
...
{
"netid": "icmp6",
"state": "UNCONN",
"recv_q": 0,
"send_q": 0,
"local_address": "*",
"local_port": "ipv6-icmp",
"peer_address": "*",
"peer_port": "*",
"interface": "ens33"
},
{
"netid": "udp",
"state": "UNCONN",
"recv_q": 0,
"send_q": 0,
"local_address": "127.0.0.53",
"local_port": "domain",
"peer_address": "0.0.0.0",
"peer_port": "*",
"interface": "lo"
},
{
"netid": "tcp",
"state": "LISTEN",
"recv_q": 0,
"send_q": 128,
"local_address": "127.0.0.53",
"local_port": "domain",
"peer_address": "0.0.0.0",
"peer_port": "*",
"interface": "lo"
},
{
"netid": "tcp",
"state": "LISTEN",
"recv_q": 0,
"send_q": 128,
"local_address": "0.0.0.0",
"local_port": "ssh",
"peer_address": "0.0.0.0",
"peer_port": "*"
},
{
"netid": "tcp",
"state": "LISTEN",
"recv_q": 0,
"send_q": 128,
"local_address": "[::]",
"local_port": "ssh",
"peer_address": "[::]",
"peer_port": "*"
},
{
"netid": "v_str",
"state": "ESTAB",
"recv_q": 0,
"send_q": 0,
"local_address": "999900439",
"local_port": "1023",
"peer_address": "0",
"peer_port": "976",
"local_port_num": 1023,
"peer_port_num": 976
}
]
$ sudo ss -a | jc --ss -p -r
[
{
"netid": "nl",
"state": "UNCONN",
"recv_q": "0",
"send_q": "0",
"peer_address": "*",
"channel": "rtnl:kernel"
},
{
"netid": "nl",
"state": "UNCONN",
"recv_q": "0",
"send_q": "0",
"peer_address": "*",
"pid": "893",
"channel": "rtnl:systemd-resolve"
},
...
{
"netid": "p_raw",
"state": "UNCONN",
"recv_q": "0",
"send_q": "0",
"peer_address": "*",
"link_layer": "LLDP",
"interface": "ens33"
},
{
"netid": "u_dgr",
"state": "UNCONN",
"recv_q": "0",
"send_q": "0",
"local_port": "93066",
"peer_address": "*",
"peer_port": "0",
"path": "/run/user/1000/systemd/notify"
},
{
"netid": "u_seq",
"state": "LISTEN",
"recv_q": "0",
"send_q": "128",
"local_port": "20699",
"peer_address": "*",
"peer_port": "0",
"path": "/run/udev/control"
},
...
{
"netid": "icmp6",
"state": "UNCONN",
"recv_q": "0",
"send_q": "0",
"local_address": "*",
"local_port": "ipv6-icmp",
"peer_address": "*",
"peer_port": "*",
"interface": "ens33"
},
{
"netid": "udp",
"state": "UNCONN",
"recv_q": "0",
"send_q": "0",
"local_address": "127.0.0.53",
"local_port": "domain",
"peer_address": "0.0.0.0",
"peer_port": "*",
"interface": "lo"
},
{
"netid": "tcp",
"state": "LISTEN",
"recv_q": "0",
"send_q": "128",
"local_address": "127.0.0.53",
"local_port": "domain",
"peer_address": "0.0.0.0",
"peer_port": "*",
"interface": "lo"
},
{
"netid": "tcp",
"state": "LISTEN",
"recv_q": "0",
"send_q": "128",
"local_address": "0.0.0.0",
"local_port": "ssh",
"peer_address": "0.0.0.0",
"peer_port": "*"
},
{
"netid": "tcp",
"state": "LISTEN",
"recv_q": "0",
"send_q": "128",
"local_address": "[::]",
"local_port": "ssh",
"peer_address": "[::]",
"peer_port": "*"
},
{
"netid": "v_str",
"state": "ESTAB",
"recv_q": "0",
"send_q": "0",
"local_address": "999900439",
"local_port": "1023",
"peer_address": "0",
"peer_port": "976"
}
]
"""
import string
import jc.utils
class info():
version = '1.0'
description = 'ss command parser'
author = 'Kelly Brazil'
author_email = 'kellyjonbrazil@gmail.com'
# compatible options: linux, darwin, cygwin, win32, aix, freebsd
compatible = ['linux']
magic_commands = ['ss']
__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:
[
{
"netid": string,
"state": string,
"recv_q": integer,
"send_q": integer,
"local_address": string,
"local_port": string,
"local_port_num": integer,
"peer_address": string,
"peer_port": string,
"peer_port_num": integer,
"interface": string,
"link_layer" string,
"channel": string,
"path": string,
"pid": integer
}
]
Information from https://www.cyberciti.biz/files/ss.html used to define field names
"""
for entry in proc_data:
int_list = ['recv_q', 'send_q', 'pid']
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 'local_port' in entry:
try:
entry['local_port_num'] = int(entry['local_port'])
except (ValueError):
pass
if 'peer_port' in entry:
try:
entry['peer_port_num'] = int(entry['peer_port'])
except (ValueError):
pass
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)
contains_colon = ['nl', 'p_raw', 'raw', 'udp', 'tcp', 'v_str', 'icmp6']
raw_output = []
cleandata = data.splitlines()
# Clear any blank lines
cleandata = list(filter(None, cleandata))
if cleandata:
header_text = cleandata[0].lower()
header_text = header_text.replace('netidstate', 'netid state')
header_text = header_text.replace('local address:port', 'local_address local_port')
header_text = header_text.replace('peer address:port', 'peer_address peer_port')
header_text = header_text.replace('-', '_')
header_list = header_text.split()
for entry in cleandata[1:]:
output_line = {}
if entry[0] not in string.whitespace:
# fix weird ss bug where first two columns have no space between them sometimes
entry = entry[:5] + ' ' + entry[5:]
entry_list = entry.split()
if entry_list[0] in contains_colon and ':' in entry_list[4]:
l_field = entry_list[4].rsplit(':', maxsplit=1)
l_address = l_field[0]
l_port = l_field[1]
entry_list[4] = l_address
entry_list.insert(5, l_port)
if entry_list[0] in contains_colon and ':' in entry_list[6]:
p_field = entry_list[6].rsplit(':', maxsplit=1)
p_address = p_field[0]
p_port = p_field[1]
entry_list[6] = p_address
entry_list.insert(7, p_port)
output_line = dict(zip(header_list, entry_list))
# some post processing to pull out fields: interface, link_layer, path, pid, channel
# Information from https://www.cyberciti.biz/files/ss.html used to define field names
if '%' in output_line['local_address']:
i_field = output_line['local_address'].rsplit('%', maxsplit=1)
output_line['local_address'] = i_field[0]
output_line['interface'] = i_field[1]
if output_line['netid'] == 'nl':
channel = output_line.pop('local_address')
channel = channel + ':' + output_line.pop('local_port')
if '/' in channel:
pid = channel.rsplit('/', maxsplit=1)[1]
channel = channel.rsplit('/', maxsplit=1)[0]
output_line['pid'] = pid
output_line['channel'] = channel
if output_line['netid'] == 'p_raw':
output_line['link_layer'] = output_line.pop('local_address')
output_line['interface'] = output_line.pop('local_port')
if output_line['netid'] not in contains_colon:
output_line['path'] = output_line.pop('local_address')
raw_output.append(output_line)
if raw:
return raw_output
else:
return process(raw_output)

280
jc/parsers/stat.py Normal file
View File

@@ -0,0 +1,280 @@
"""jc - JSON CLI output utility stat Parser
Usage:
specify --stat as the first argument if the piped input is coming from stat
Compatibility:
'linux'
Examples:
$ stat /bin/* | jc --stat -p
[
{
"file": "/bin/bash",
"size": 1113504,
"blocks": 2176,
"io_blocks": 4096,
"type": "regular file",
"device": "802h/2050d",
"inode": 131099,
"links": 1,
"access": "0755",
"flags": "-rwxr-xr-x",
"uid": 0,
"user": "root",
"gid": 0,
"group": "root",
"access_time": "2019-11-14 08:18:03.509681766 +0000",
"modify_time": "2019-06-06 22:28:15.000000000 +0000",
"change_time": "2019-08-12 17:21:29.521945390 +0000",
"birth_time": null
},
{
"file": "/bin/btrfs",
"size": 716464,
"blocks": 1400,
"io_blocks": 4096,
"type": "regular file",
"device": "802h/2050d",
"inode": 131100,
"links": 1,
"access": "0755",
"flags": "-rwxr-xr-x",
"uid": 0,
"user": "root",
"gid": 0,
"group": "root",
"access_time": "2019-11-14 08:18:28.990834276 +0000",
"modify_time": "2018-03-12 23:04:27.000000000 +0000",
"change_time": "2019-08-12 17:21:29.545944399 +0000",
"birth_time": null
},
...
]
$ stat /bin/* | jc --stat -p -r
[
{
"file": "/bin/bash",
"size": "1113504",
"blocks": "2176",
"io_blocks": "4096",
"type": "regular file",
"device": "802h/2050d",
"inode": "131099",
"links": "1",
"access": "0755",
"flags": "-rwxr-xr-x",
"uid": "0",
"user": "root",
"gid": "0",
"group": "root",
"access_time": "2019-11-14 08:18:03.509681766 +0000",
"modify_time": "2019-06-06 22:28:15.000000000 +0000",
"change_time": "2019-08-12 17:21:29.521945390 +0000",
"birth_time": null
},
{
"file": "/bin/btrfs",
"size": "716464",
"blocks": "1400",
"io_blocks": "4096",
"type": "regular file",
"device": "802h/2050d",
"inode": "131100",
"links": "1",
"access": "0755",
"flags": "-rwxr-xr-x",
"uid": "0",
"user": "root",
"gid": "0",
"group": "root",
"access_time": "2019-11-14 08:18:28.990834276 +0000",
"modify_time": "2018-03-12 23:04:27.000000000 +0000",
"change_time": "2019-08-12 17:21:29.545944399 +0000",
"birth_time": null
},
..
]
"""
import jc.utils
class info():
version = '1.0'
description = 'stat command parser'
author = 'Kelly Brazil'
author_email = 'kellyjonbrazil@gmail.com'
# compatible options: linux, darwin, cygwin, win32, aix, freebsd
compatible = ['linux']
magic_commands = ['stat']
__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:
[
{
"file": string,
"link_to" string,
"size": integer,
"blocks": integer,
"io_blocks": integer,
"type": string,
"device": string,
"inode": integer,
"links": integer,
"access": string,
"flags": string,
"uid": integer,
"user": string,
"gid": integer,
"group": string,
"access_time": string, # - = null
"modify_time": string, # - = null
"change_time": string, # - = null
"birth_time": string # - = null
}
]
"""
for entry in proc_data:
int_list = ['size', 'blocks', 'io_blocks', 'inode', 'links', 'uid', 'gid']
for key in int_list:
if key in entry:
try:
key_int = int(entry[key])
entry[key] = key_int
except (ValueError):
entry[key] = None
# turn - into null for time fields
for entry in proc_data:
null_list = ['access_time', 'modify_time', 'change_time', 'birth_time']
for key in null_list:
if key in entry:
if entry[key] == '-':
entry[key] = 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)
raw_output = []
cleandata = data.splitlines()
# Clear any blank lines
cleandata = list(filter(None, cleandata))
if cleandata:
# stats output contains 8 lines
for line in cleandata:
# line #1
if line.find('File:') == 2:
output_line = {}
line_list = line.split(maxsplit=1)
output_line['file'] = line_list[1]
# populate link_to field if -> found
if output_line['file'].find(' -> ') != -1:
filename = output_line['file'].split(' -> ')[0].strip('\u2018').rstrip('\u2019')
link = output_line['file'].split(' -> ')[1].strip('\u2018').rstrip('\u2019')
output_line['file'] = filename
output_line['link_to'] = link
else:
filename = output_line['file'].split(' -> ')[0].strip('\u2018').rstrip('\u2019')
output_line['file'] = filename
continue
# line #2
if line.find('Size:') == 2:
line_list = line.split(maxsplit=7)
output_line['size'] = line_list[1]
output_line['blocks'] = line_list[3]
output_line['io_blocks'] = line_list[6]
output_line['type'] = line_list[7]
continue
# line #3
if line.find('Device:') == 0:
line_list = line.split()
output_line['device'] = line_list[1]
output_line['inode'] = line_list[3]
output_line['links'] = line_list[5]
continue
# line #4
if line.find('Access: (') == 0:
line = line.replace('(', ' ').replace(')', ' ').replace('/', ' ')
line_list = line.split()
output_line['access'] = line_list[1]
output_line['flags'] = line_list[2]
output_line['uid'] = line_list[4]
output_line['user'] = line_list[5]
output_line['gid'] = line_list[7]
output_line['group'] = line_list[8]
continue
# line #5
if line.find('Access: 2') == 0:
line_list = line.split(maxsplit=1)
output_line['access_time'] = line_list[1]
continue
# line #6
if line.find('Modify:') == 0:
line_list = line.split(maxsplit=1)
output_line['modify_time'] = line_list[1]
continue
# line #7
if line.find('Change:') == 0:
line_list = line.split(maxsplit=1)
output_line['change_time'] = line_list[1]
continue
# line #8
if line.find('Birth:') == 1:
line_list = line.split(maxsplit=1)
output_line['birth_time'] = line_list[1]
raw_output.append(output_line)
continue
if raw:
return raw_output
else:
return process(raw_output)

124
jc/parsers/systemctl.py Normal file
View File

@@ -0,0 +1,124 @@
"""jc - JSON CLI output utility systemctl Parser
Usage:
specify --systemctl as the first argument if the piped input is coming from systemctl
Compatibility:
'linux'
Examples:
$ systemctl -a | jc --systemctl -p
[
{
"unit": "proc-sys-fs-binfmt_misc.automount",
"load": "loaded",
"active": "active",
"sub": "waiting",
"description": "Arbitrary Executable File Formats File System Automount Point"
},
{
"unit": "dev-block-8:2.device",
"load": "loaded",
"active": "active",
"sub": "plugged",
"description": "LVM PV 3klkIj-w1qk-DkJi-0XBJ-y3o7-i2Ac-vHqWBM on /dev/sda2 2"
},
{
"unit": "dev-cdrom.device",
"load": "loaded",
"active": "active",
"sub": "plugged",
"description": "VMware_Virtual_IDE_CDROM_Drive"
},
...
]
"""
import jc.utils
class info():
version = '1.0'
description = 'systemctl command parser'
author = 'Kelly Brazil'
author_email = 'kellyjonbrazil@gmail.com'
# compatible options: linux, darwin, cygwin, win32, aix, freebsd
compatible = ['linux']
magic_commands = ['systemctl']
__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:
[
{
"unit": string,
"load": string,
"active": string,
"sub": string,
"description": string
}
]
"""
# nothing more to process
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)
linedata = data.splitlines()
# Clear any blank lines
linedata = list(filter(None, linedata))
# clean up non-ascii characters, if any
cleandata = []
for entry in linedata:
cleandata.append(entry.encode('ascii', errors='ignore').decode())
header_text = cleandata[0]
header_list = header_text.lower().split()
raw_output = []
for entry in cleandata[1:]:
if entry.find('LOAD = ') != -1:
break
else:
entry_list = entry.rstrip().split(maxsplit=4)
output_line = dict(zip(header_list, entry_list))
raw_output.append(output_line)
if raw:
return raw_output
else:
return process(raw_output)

151
jc/parsers/systemctl_lj.py Normal file
View File

@@ -0,0 +1,151 @@
"""jc - JSON CLI output utility systemctl-lj Parser
Usage:
specify --systemctl-lj as the first argument if the piped input is coming from systemctl list-jobs
Compatibility:
'linux'
Examples:
$ systemctl list-jobs| jc --systemctl-lj -p
[
{
"job": 3543,
"unit": "nginxAfterGlusterfs.service",
"type": "start",
"state": "waiting"
},
{
"job": 3545,
"unit": "glusterReadyForLocalhostMount.service",
"type": "start",
"state": "running"
},
{
"job": 3506,
"unit": "nginx.service",
"type": "start",
"state": "waiting"
}
]
$ systemctl list-jobs| jc --systemctl-lj -p -r
[
{
"job": "3543",
"unit": "nginxAfterGlusterfs.service",
"type": "start",
"state": "waiting"
},
{
"job": "3545",
"unit": "glusterReadyForLocalhostMount.service",
"type": "start",
"state": "running"
},
{
"job": "3506",
"unit": "nginx.service",
"type": "start",
"state": "waiting"
}
]
"""
import jc.utils
class info():
version = '1.0'
description = 'systemctl list-jobs command parser'
author = 'Kelly Brazil'
author_email = 'kellyjonbrazil@gmail.com'
# compatible options: linux, darwin, cygwin, win32, aix, freebsd
compatible = ['linux']
magic_commands = ['systemctl list-jobs']
__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:
[
{
"job": integer,
"unit": string,
"type": string,
"state": string
}
]
"""
for entry in proc_data:
int_list = ['job']
for key in int_list:
if key in entry:
try:
key_int = int(entry[key])
entry[key] = key_int
except (ValueError):
entry[key] = 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)
linedata = data.splitlines()
# Clear any blank lines
linedata = list(filter(None, linedata))
# clean up non-ascii characters, if any
cleandata = []
for entry in linedata:
cleandata.append(entry.encode('ascii', errors='ignore').decode())
header_text = cleandata[0]
header_text = header_text.lower()
header_list = header_text.split()
raw_output = []
for entry in cleandata[1:]:
if entry.find('No jobs running.') != -1 or entry.find('jobs listed.') != -1:
break
else:
entry_list = entry.split(maxsplit=4)
output_line = dict(zip(header_list, entry_list))
raw_output.append(output_line)
if raw:
return raw_output
else:
return process(raw_output)

116
jc/parsers/systemctl_ls.py Normal file
View File

@@ -0,0 +1,116 @@
"""jc - JSON CLI output utility systemctl-ls Parser
Usage:
specify --systemctl-ls as the first argument if the piped input is coming from systemctl list-sockets
Compatibility:
'linux'
Examples:
$ systemctl list-sockets | jc --systemctl-ls -p
[
{
"listen": "/dev/log",
"unit": "systemd-journald.socket",
"activates": "systemd-journald.service"
},
{
"listen": "/run/dbus/system_bus_socket",
"unit": "dbus.socket",
"activates": "dbus.service"
},
{
"listen": "/run/dmeventd-client",
"unit": "dm-event.socket",
"activates": "dm-event.service"
},
...
]
"""
import jc.utils
class info():
version = '1.0'
description = 'systemctl list-sockets command parser'
author = 'Kelly Brazil'
author_email = 'kellyjonbrazil@gmail.com'
# compatible options: linux, darwin, cygwin, win32, aix, freebsd
compatible = ['linux']
magic_commands = ['systemctl list-sockets']
__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:
[
{
"listen": string,
"unit": string,
"activates": string
}
]
"""
# nothing more to process
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)
linedata = data.splitlines()
# Clear any blank lines
linedata = list(filter(None, linedata))
# clean up non-ascii characters, if any
cleandata = []
for entry in linedata:
cleandata.append(entry.encode('ascii', errors='ignore').decode())
header_text = cleandata[0].lower()
header_list = header_text.split()
raw_output = []
for entry in cleandata[1:]:
if entry.find('sockets listed.') != -1:
break
else:
entry_list = entry.rsplit(maxsplit=2)
output_line = dict(zip(header_list, entry_list))
raw_output.append(output_line)
if raw:
return raw_output
else:
return process(raw_output)

113
jc/parsers/systemctl_luf.py Normal file
View File

@@ -0,0 +1,113 @@
"""jc - JSON CLI output utility systemctl-luf Parser
Usage:
specify --systemctl-luf as the first argument if the piped input is coming from systemctl list-unit-files
Compatibility:
'linux'
Examples:
$ systemctl list-unit-files | jc --systemctl-luf -p
[
{
"unit_file": "proc-sys-fs-binfmt_misc.automount",
"state": "static"
},
{
"unit_file": "dev-hugepages.mount",
"state": "static"
},
{
"unit_file": "dev-mqueue.mount",
"state": "static"
},
...
]
"""
import jc.utils
class info():
version = '1.0'
description = 'systemctl list-unit-files command parser'
author = 'Kelly Brazil'
author_email = 'kellyjonbrazil@gmail.com'
# compatible options: linux, darwin, cygwin, win32, aix, freebsd
compatible = ['linux']
magic_commands = ['systemctl list-unit-files']
__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:
[
{
"unit_file": string,
"state": string
}
]
"""
# nothing more to process
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)
linedata = data.splitlines()
# Clear any blank lines
linedata = list(filter(None, linedata))
# clean up non-ascii characters, if any
cleandata = []
for entry in linedata:
cleandata.append(entry.encode('ascii', errors='ignore').decode())
header_text = cleandata[0]
header_text = header_text.lower().replace('unit file', 'unit_file')
header_list = header_text.split()
raw_output = []
for entry in cleandata[1:]:
if entry.find('unit files listed.') != -1:
break
else:
entry_list = entry.split(maxsplit=4)
output_line = dict(zip(header_list, entry_list))
raw_output.append(output_line)
if raw:
return raw_output
else:
return process(raw_output)

122
jc/parsers/uname.py Normal file
View File

@@ -0,0 +1,122 @@
"""jc - JSON CLI output utility uname Parser
Usage:
specify --uname as the first argument if the piped input is coming from uname
Limitations:
must use 'uname -a'
Compatibility:
'linux', 'darwin'
Example:
$ uname -a | jc --uname -p
{
"kernel_name": "Linux",
"node_name": "user-ubuntu",
"kernel_release": "4.15.0-65-generic",
"operating_system": "GNU/Linux",
"hardware_platform": "x86_64",
"processor": "x86_64",
"machine": "x86_64",
"kernel_version": "#74-Ubuntu SMP Tue Sep 17 17:06:04 UTC 2019"
}
"""
import jc.utils
class info():
version = '1.1'
description = 'uname -a command parser'
author = 'Kelly Brazil'
author_email = 'kellyjonbrazil@gmail.com'
# compatible options: linux, darwin, cygwin, win32, aix, freebsd
compatible = ['linux', 'darwin']
magic_commands = ['uname']
__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:
{
"kernel_name": string,
"node_name": string,
"kernel_release": string,
"operating_system": string,
"hardware_platform": string,
"processor": string,
"machine": string,
"kernel_version": string
}
"""
# nothing to process
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:
Dictionary. Raw or processed structured data.
"""
if not quiet:
jc.utils.compatibility(__name__, info.compatible)
raw_output = {}
split_line = data.split()
if len(split_line) > 1:
# check for OSX output
if data.startswith('Darwin'):
parsed_line = data.split()
raw_output['machine'] = parsed_line.pop(-1)
raw_output['kernel_name'] = parsed_line.pop(0)
raw_output['node_name'] = parsed_line.pop(0)
raw_output['kernel_release'] = parsed_line.pop(0)
raw_output['kernel_version'] = ' '.join(parsed_line)
# otherwise use linux parser
else:
parsed_line = data.split(maxsplit=3)
raw_output['kernel_name'] = parsed_line.pop(0)
raw_output['node_name'] = parsed_line.pop(0)
raw_output['kernel_release'] = parsed_line.pop(0)
parsed_line = parsed_line[-1].rsplit(maxsplit=4)
raw_output['operating_system'] = parsed_line.pop(-1)
raw_output['hardware_platform'] = parsed_line.pop(-1)
raw_output['processor'] = parsed_line.pop(-1)
raw_output['machine'] = parsed_line.pop(-1)
raw_output['kernel_version'] = parsed_line.pop(0)
if raw:
return raw_output
else:
return process(raw_output)

110
jc/parsers/universal.py Normal file
View File

@@ -0,0 +1,110 @@
"""jc - JSON CLI output utility universal Parsers"""
import string
def simple_table_parse(data):
"""
Parse simple tables. The last column may contain data with spaces
code adapted from Conor Heine at:
https://gist.github.com/cahna/43a1a3ff4d075bcd71f9d7120037a501
Parameters:
data: (list) Text data to parse that has been split into lines via .splitlines().
Item 0 must be the header row. Any spaces in header names should be
changed to underscore '_'. You should also ensure headers are
lowercase by using .lower().
Also, ensure there are no blank lines (list items) in the data.
Returns:
dictionary raw structured data
"""
headers = [h for h in ' '.join(data[0].strip().split()).split() if h]
raw_data = map(lambda s: s.strip().split(None, len(headers) - 1), data[1:])
raw_output = [dict(zip(headers, r)) for r in raw_data]
return raw_output
def sparse_table_parse(data, delim='\u2063'):
"""
Parse tables with missing column data or with spaces in column data.
Parameters:
data: (list) Text data to parse that has been split into lines via .splitlines().
Item 0 must be the header row. Any spaces in header names should be
changed to underscore '_'. You should also ensure headers are
lowercase by using .lower(). Do not change the position of header
names as the positions are used to find the data.
Also, ensure there are no blank lines (list items) in the data.
delim: (string) Delimiter to use. By default 'u\2063' (invisible separator) is used
since this is unlikely to ever be seen in terminal output. You can
change this for troubleshooting purposes or if there is a delimiter
conflict with your data.
Returns:
dictionary raw structured data
"""
output = []
header_text = data.pop(0)
header_text = header_text + ' '
header_list = header_text.split()
# find each column index and end position
header_search = [header_list[0]]
for h in header_list[1:]:
header_search.append(' ' + h + ' ')
header_spec_list = []
for i, column in enumerate(header_list[0:len(header_list) - 1]):
header_spec = {
'name': column,
'end': header_text.find(header_search[i + 1])
}
header_spec_list.append(header_spec)
# parse lines
if data:
for entry in data:
output_line = {}
# insert new separator since data can contain spaces
for col in reversed(header_list):
# find the right header_spec
for h_spec in header_spec_list:
if h_spec['name'] == col:
h_end = h_spec['end']
# check if the location contains whitespace. if not
# then move to the left until a space is found
while h_end > 0 and entry[h_end] not in string.whitespace:
h_end -= 1
# insert custom delimiter
entry = entry[:h_end] + delim + entry[h_end + 1:]
# create the entry list from the new custom delimiter
entry_list = entry.split(delim, maxsplit=len(header_list) - 1)
# clean up leading and trailing spaces in entry
clean_entry_list = []
for col in entry_list:
clean_entry = col.strip()
if clean_entry == '':
clean_entry = None
clean_entry_list.append(clean_entry)
output_line = dict(zip(header_list, clean_entry_list))
output.append(output_line)
return output

136
jc/parsers/uptime.py Normal file
View File

@@ -0,0 +1,136 @@
"""jc - JSON CLI output utility uptime Parser
Usage:
specify --uptime as the first argument if the piped input is coming from uptime
Compatibility:
'linux', 'darwin', 'cygwin', 'aix', 'freebsd'
Example:
$ uptime | jc --uptime -p
{
"time": "11:30:44",
"uptime": "1 day, 21:17",
"users": 1,
"load_1m": 0.01,
"load_5m": 0.04,
"load_15m": 0.05
}
$ uptime | jc --uptime -p -r
{
"time": "11:31:09",
"uptime": "1 day, 21:17",
"users": "1",
"load_1m": "0.00",
"load_5m": "0.04",
"load_15m": "0.05"
}
"""
import jc.utils
class info():
version = '1.0'
description = 'uptime command parser'
author = 'Kelly Brazil'
author_email = 'kellyjonbrazil@gmail.com'
# compatible options: linux, darwin, cygwin, win32, aix, freebsd
compatible = ['linux', 'darwin', 'cygwin', 'aix', 'freebsd']
magic_commands = ['uptime']
__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:
{
"time": string,
"uptime": string,
"users": integer,
"load_1m": float,
"load_5m": float,
"load_15m": float
}
"""
int_list = ['users']
for key in int_list:
if key in proc_data:
try:
key_int = int(proc_data[key])
proc_data[key] = key_int
except (ValueError):
proc_data[key] = None
float_list = ['load_1m', 'load_5m', 'load_15m']
for key in float_list:
if key in proc_data:
try:
key_float = float(proc_data[key])
proc_data[key] = key_float
except (ValueError):
proc_data[key] = 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:
Dictionary. Raw or processed structured data
"""
if not quiet:
jc.utils.compatibility(__name__, info.compatible)
raw_output = {}
cleandata = data.splitlines()
if cleandata:
parsed_line = cleandata[0].split()
# allow space for odd times
while len(parsed_line) < 20:
parsed_line.insert(2, ' ')
# find first part of time
for i, word in enumerate(parsed_line[2:]):
if word != ' ':
marker = i + 2
break
raw_output['time'] = parsed_line[0]
raw_output['uptime'] = ' '.join(parsed_line[marker:13]).lstrip().rstrip(',')
raw_output['users'] = parsed_line[13]
raw_output['load_1m'] = parsed_line[17].rstrip(',')
raw_output['load_5m'] = parsed_line[18].rstrip(',')
raw_output['load_15m'] = parsed_line[19]
if raw:
return raw_output
else:
return process(raw_output)

180
jc/parsers/w.py Normal file
View File

@@ -0,0 +1,180 @@
"""jc - JSON CLI output utility w Parser
Usage:
specify --w as the first argument if the piped input is coming from w
Compatibility:
'linux', 'darwin', 'cygwin', 'aix', 'freebsd'
Examples:
$ w | jc --w -p
[
{
"user": "root",
"tty": "tty1",
"from": null,
"login_at": "07:49",
"idle": "1:15m",
"jcpu": "0.00s",
"pcpu": "0.00s",
"what": "-bash"
},
{
"user": "root",
"tty": "ttyS0",
"from": null,
"login_at": "06:24",
"idle": "0.00s",
"jcpu": "0.43s",
"pcpu": "0.00s",
"what": "w"
},
{
"user": "root",
"tty": "pts/0",
"from": "192.168.71.1",
"login_at": "06:29",
"idle": "2:35m",
"jcpu": "0.00s",
"pcpu": "0.00s",
"what": "-bash"
}
]
$ w | jc --w -p -r
[
{
"user": "kbrazil",
"tty": "tty1",
"from": "-",
"login_at": "07:49",
"idle": "1:16m",
"jcpu": "0.00s",
"pcpu": "0.00s",
"what": "-bash"
},
{
"user": "kbrazil",
"tty": "ttyS0",
"from": "-",
"login_at": "06:24",
"idle": "2.00s",
"jcpu": "0.46s",
"pcpu": "0.00s",
"what": "w"
},
{
"user": "kbrazil",
"tty": "pts/0",
"from": "192.168.71.1",
"login_at": "06:29",
"idle": "2:36m",
"jcpu": "0.00s",
"pcpu": "0.00s",
"what": "-bash"
}
]
"""
import string
import jc.utils
class info():
version = '1.0'
description = 'w command parser'
author = 'Kelly Brazil'
author_email = 'kellyjonbrazil@gmail.com'
# compatible options: linux, darwin, cygwin, win32, aix, freebsd
compatible = ['linux', 'darwin', 'cygwin', 'aix', 'freebsd']
magic_commands = ['w']
__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:
[
{
"user": string, # '-'' = null
"tty": string, # '-'' = null
"from": string, # '-'' = null
"login_at": string, # '-'' = null
"idle": string, # '-'' = null
"jcpu": string,
"pcpu": string,
"what": string # '-'' = null
}
]
"""
for entry in proc_data:
null_list = ['user', 'tty', 'from', 'login_at', 'idle', 'what']
for key in null_list:
if key in entry:
if entry[key] == '-':
entry[key] = 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)
cleandata = data.splitlines()[1:]
header_text = cleandata[0].lower()
# fixup for 'from' column that can be blank
from_col = header_text.find('from')
# clean up 'login@' header
# even though @ in a key is valid json, it can make things difficult
header_text = header_text.replace('login@', 'login_at')
headers = [h for h in ' '.join(header_text.strip().split()).split() if h]
# parse lines
raw_output = []
if cleandata:
for entry in cleandata[1:]:
output_line = {}
# normalize data by inserting Null for missing data
temp_line = entry.split(maxsplit=len(headers) - 1)
# fix from column, always at column 2
if 'from' in headers:
if entry[from_col] in string.whitespace:
temp_line.insert(2, '-')
output_line = dict(zip(headers, temp_line))
raw_output.append(output_line)
if raw:
return raw_output
else:
return process(raw_output)

120
jc/parsers/xml.py Normal file
View File

@@ -0,0 +1,120 @@
"""jc - JSON CLI output utility XML Parser
Usage:
specify --xml as the first argument if the piped input is coming from an XML file
Compatibility:
'linux', 'darwin', 'cygwin', 'win32', 'aix', 'freebsd'
Examples:
$ cat cd_catalog.xml
<?xml version="1.0" encoding="UTF-8"?>
<CATALOG>
<CD>
<TITLE>Empire Burlesque</TITLE>
<ARTIST>Bob Dylan</ARTIST>
<COUNTRY>USA</COUNTRY>
<COMPANY>Columbia</COMPANY>
<PRICE>10.90</PRICE>
<YEAR>1985</YEAR>
</CD>
<CD>
<TITLE>Hide your heart</TITLE>
<ARTIST>Bonnie Tyler</ARTIST>
<COUNTRY>UK</COUNTRY>
<COMPANY>CBS Records</COMPANY>
<PRICE>9.90</PRICE>
<YEAR>1988</YEAR>
</CD>
...
$ cat cd_catalog.xml | jc --xml -p
{
"CATALOG": {
"CD": [
{
"TITLE": "Empire Burlesque",
"ARTIST": "Bob Dylan",
"COUNTRY": "USA",
"COMPANY": "Columbia",
"PRICE": "10.90",
"YEAR": "1985"
},
{
"TITLE": "Hide your heart",
"ARTIST": "Bonnie Tyler",
"COUNTRY": "UK",
"COMPANY": "CBS Records",
"PRICE": "9.90",
"YEAR": "1988"
},
...
}
"""
import jc.utils
import xmltodict
class info():
version = '1.0'
description = 'XML file parser'
author = 'Kelly Brazil'
author_email = 'kellyjonbrazil@gmail.com'
details = 'Using the xmltodict library at https://github.com/martinblech/xmltodict'
# compatible options: linux, darwin, cygwin, win32, aix, freebsd
compatible = ['linux', 'darwin', 'cygwin', 'win32', 'aix', 'freebsd']
__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 representing an XML document:
{
XML Document converted to a Dictionary
See https://github.com/martinblech/xmltodict for details
}
"""
# No further processing
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:
Dictionary. Raw or processed structured data.
"""
if not quiet:
jc.utils.compatibility(__name__, info.compatible)
if data:
raw_output = xmltodict.parse(data)
if raw:
return raw_output
else:
return process(raw_output)

137
jc/parsers/yaml.py Normal file
View File

@@ -0,0 +1,137 @@
"""jc - JSON CLI output utility YAML Parser
Usage:
specify --yaml as the first argument if the piped input is coming from a YAML file
Compatibility:
'linux', 'darwin', 'cygwin', 'win32', 'aix', 'freebsd'
Examples:
$ cat istio-mtls-permissive.yaml
apiVersion: "authentication.istio.io/v1alpha1"
kind: "Policy"
metadata:
name: "default"
namespace: "default"
spec:
peers:
- mtls: {}
---
apiVersion: "networking.istio.io/v1alpha3"
kind: "DestinationRule"
metadata:
name: "default"
namespace: "default"
spec:
host: "*.default.svc.cluster.local"
trafficPolicy:
tls:
mode: ISTIO_MUTUAL
$ cat istio-mtls-permissive.yaml | jc --yaml -p
[
{
"apiVersion": "authentication.istio.io/v1alpha1",
"kind": "Policy",
"metadata": {
"name": "default",
"namespace": "default"
},
"spec": {
"peers": [
{
"mtls": {}
}
]
}
},
{
"apiVersion": "networking.istio.io/v1alpha3",
"kind": "DestinationRule",
"metadata": {
"name": "default",
"namespace": "default"
},
"spec": {
"host": "*.default.svc.cluster.local",
"trafficPolicy": {
"tls": {
"mode": "ISTIO_MUTUAL"
}
}
}
}
]
"""
import jc.utils
from ruamel.yaml import YAML
class info():
version = '1.0'
description = 'YAML file parser'
author = 'Kelly Brazil'
author_email = 'kellyjonbrazil@gmail.com'
details = 'Using the ruamel.yaml library at https://pypi.org/project/ruamel.yaml'
# compatible options: linux, darwin, cygwin, win32, aix, freebsd
compatible = ['linux', 'darwin', 'cygwin', 'win32', 'aix', 'freebsd']
__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. Each dictionary represents a YAML document:
[
{
YAML Document converted to a Dictionary
See https://pypi.org/project/ruamel.yaml for details
}
]
"""
# No further processing
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)
raw_output = []
yaml = YAML(typ='safe')
for document in yaml.load_all(data):
raw_output.append(document)
if raw:
return raw_output
else:
return process(raw_output)

62
jc/utils.py Normal file
View File

@@ -0,0 +1,62 @@
"""jc - JSON CLI output utility utils"""
import textwrap
import sys
def warning_message(message):
"""
Prints a warning message for non-fatal issues
Parameters:
message: (string) text of message
Returns:
no return, just prints output to STDERR
"""
error_string = f'''
jc: Warning - {message}
'''
print(textwrap.dedent(error_string), file=sys.stderr)
def error_message(message):
"""
Prints an error message for fatal issues
Parameters:
message: (string) text of message
Returns:
no return, just prints output to STDERR
"""
error_string = f'''
jc: Error - {message}
'''
print(textwrap.dedent(error_string), file=sys.stderr)
def compatibility(mod_name, compatible):
"""Checks for the parser's compatibility with the running OS platform.
Parameters:
mod_name: (string) __name__ of the calling module
compatible: (list) sys.platform name(s) compatible with the parser
compatible options:
linux, darwin, cygwin, win32, aix, freebsd
Returns:
no return, just prints output to STDERR
"""
if sys.platform not in compatible:
mod = mod_name.split('.')[-1]
compat_list = ', '.join(compatible)
warning_message(f'{mod} parser not compatible with your OS ({sys.platform}).\n Compatible platforms: {compat_list}')

3
runtests.sh Executable file
View File

@@ -0,0 +1,3 @@
#!/bin/bash
python3 -m unittest -v

View File

@@ -5,27 +5,31 @@ with open('README.md', 'r') as f:
setuptools.setup(
name='jc',
version='0.2.0',
version='1.7.4',
author='Kelly Brazil',
author_email='kellyjonbrazil@gmail.com',
description='This tool serializes the output of popular command line tools to structured JSON output.',
description='This tool serializes the output of popular command line tools and filetypes to structured JSON output.',
install_requires=[
'ifconfig-parser'
'ifconfig-parser>=0.0.5',
'ruamel.yaml>=0.15.0',
'xmltodict>=0.12.0'
],
license='MIT',
long_description=long_description,
long_description_content_type='text/markdown',
python_requires='~=3.4',
python_requires='>=3.6',
url='https://github.com/kellyjonbrazil/jc',
packages=setuptools.find_packages(),
include_package_data=True,
entry_points={
'console_scripts': [
'jc=jc.jc:main',
],
'jc=jc.cli:main'
]
},
classifiers=[
'Programming Language :: Python :: 3',
'License :: OSI Approved :: MIT License',
'Operating System :: OS Independent',
'Topic :: Utilities'
]
)

0
tests/__init__.py Normal file
View File

1
tests/fixtures/centos-7.7/arp-a.json vendored Normal file
View File

@@ -0,0 +1 @@
[{"name": "gateway", "address": "192.168.71.2", "hwtype": "ether", "hwaddress": "00:50:56:f7:4a:fc", "iface": "ens33"}, {"name": null, "address": "192.168.71.1", "hwtype": "ether", "hwaddress": "00:50:56:c0:00:08", "iface": "ens33"}, {"name": null, "address": "192.168.71.254", "hwtype": "ether", "hwaddress": "00:50:56:fe:7a:b4", "iface": "ens33"}]

3
tests/fixtures/centos-7.7/arp-a.out vendored Normal file
View File

@@ -0,0 +1,3 @@
gateway (192.168.71.2) at 00:50:56:f7:4a:fc [ether] on ens33
? (192.168.71.1) at 00:50:56:c0:00:08 [ether] on ens33
? (192.168.71.254) at 00:50:56:fe:7a:b4 [ether] on ens33

1
tests/fixtures/centos-7.7/arp-v.json vendored Normal file
View File

@@ -0,0 +1 @@
[{"address": "gateway", "hwtype": "ether", "hwaddress": "00:50:56:f7:4a:fc", "flags_mask": "C", "iface": "ens33"}, {"address": "192.168.71.254", "hwtype": "ether", "hwaddress": "00:50:56:fe:7a:b4", "flags_mask": "C", "iface": "ens33"}]

4
tests/fixtures/centos-7.7/arp-v.out vendored Normal file
View File

@@ -0,0 +1,4 @@
Address HWtype HWaddress Flags Mask Iface
gateway ether 00:50:56:f7:4a:fc C ens33
192.168.71.254 ether 00:50:56:fe:7a:b4 C ens33
Entries: 2 Skipped: 0 Found: 2

1
tests/fixtures/centos-7.7/arp.json vendored Normal file
View File

@@ -0,0 +1 @@
[{"address": "gateway", "hwtype": "ether", "hwaddress": "00:50:56:f7:4a:fc", "flags_mask": "C", "iface": "ens33"}, {"address": "192.168.71.254", "hwtype": "ether", "hwaddress": "00:50:56:fe:7a:b4", "flags_mask": "C", "iface": "ens33"}]

3
tests/fixtures/centos-7.7/arp.out vendored Normal file
View File

@@ -0,0 +1,3 @@
Address HWtype HWaddress Flags Mask Iface
gateway ether 00:50:56:f7:4a:fc C ens33
192.168.71.254 ether 00:50:56:fe:7a:b4 C ens33

View File

@@ -0,0 +1 @@
{"variables": [{"name": "MAILTO", "value": "root"}, {"name": "PATH", "value": "/sbin:/bin:/usr/sbin:/usr/bin"}, {"name": "SHELL", "value": "/bin/bash"}], "schedule": [{"minute": ["01"], "hour": ["*"], "day_of_month": ["*"], "month": ["*"], "day_of_week": ["*"], "user": "root", "command": "run-parts /etc/cron.hourly"}, {"occurrence": "hourly", "user": "root", "command": "/usr/local/bin/backup"}]}

View File

@@ -0,0 +1,6 @@
# Run the hourly jobs
SHELL=/bin/bash
PATH=/sbin:/bin:/usr/sbin:/usr/bin
MAILTO=root
@hourly root /usr/local/bin/backup
01 * * * * root run-parts /etc/cron.hourly

View File

@@ -0,0 +1 @@
{"variables": [{"name": "MAILTO", "value": "root"}, {"name": "PATH", "value": "/sbin:/bin:/usr/sbin:/usr/bin"}, {"name": "SHELL", "value": "/bin/bash"}], "schedule": [{"minute": ["0"], "hour": ["*"], "day_of_month": ["*"], "month": ["*"], "day_of_week": ["*"], "command": "/usr/bin/wget -O - -q -t 1 http://localhost/cron.php"}, {"minute": ["*"], "hour": ["*"], "day_of_month": ["*"], "month": ["*"], "day_of_week": ["*"], "command": "/var/www/devdaily.com/bin/check-apache.sh"}, {"minute": ["5"], "hour": ["10-11", "22"], "day_of_month": ["*"], "month": ["*"], "day_of_week": ["*"], "command": "/var/www/devdaily.com/bin/mk-new-links.php"}, {"minute": ["30"], "hour": ["4/2"], "day_of_month": ["*"], "month": ["*"], "day_of_week": ["*"], "command": "/var/www/devdaily.com/bin/create-all-backups.sh"}, {"minute": ["5"], "hour": ["0", "4", "10", "16"], "day_of_month": ["*"], "month": ["*"], "day_of_week": ["*"], "command": "/var/www/devdaily.com/bin/create-cat-list.sh"}, {"minute": ["5"], "hour": ["0"], "day_of_month": ["*"], "month": ["*"], "day_of_week": ["*"], "command": "/var/www/devdaily.com/bin/resetContactForm.sh"}, {"minute": ["0", "20", "40"], "hour": ["*"], "day_of_month": ["*"], "month": ["*"], "day_of_week": ["*"], "command": "/var/www/bin/ads/freshMint.sh"}, {"minute": ["5", "25", "45"], "hour": ["*"], "day_of_month": ["*"], "month": ["*"], "day_of_week": ["*"], "command": "/var/www/bin/ads/greenTaffy.sh"}, {"minute": ["10", "30", "50"], "hour": ["*"], "day_of_month": ["*"], "month": ["*"], "day_of_week": ["*"], "command": "/var/www/bin/ads/raspberry.sh"}, {"minute": ["15", "35", "55"], "hour": ["*"], "day_of_month": ["*"], "month": ["*"], "day_of_week": ["*"], "command": "/var/www/bin/ads/robinsEgg.sh"}, {"occurrence": "yearly", "command": "/home/maverick/bin/annual-maintenance"}, {"occurrence": "reboot", "command": "/home/cleanup"}, {"occurrence": "monthly", "command": "/home/maverick/bin/tape-backup"}]}

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