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

Compare commits

...

697 Commits

Author SHA1 Message Date
Kelly Brazil
5b08469b87 Merge pull request #57 from kellyjonbrazil/dev
Dev v1.10.7
2020-05-01 15:55:50 -07:00
Kelly Brazil
4a77ec63a4 add IfconfigParser class 2020-05-01 14:57:50 -07:00
Kelly Brazil
d13606b6dc modify dependencies for easier packaging into Fedora 2020-05-01 14:37:23 -07:00
Kelly Brazil
05291c93bb vendorize ifconfig-parser module for easier packaging in Fedora 2020-05-01 14:36:54 -07:00
Kelly Brazil
8cf00a208e change text to strings 2020-04-29 15:57:55 -07:00
Kelly Brazil
06d73c8876 formatting 2020-04-23 07:06:44 -07:00
Kelly Brazil
649c646ea2 add brew install option 2020-04-22 16:08:34 -07:00
Kelly Brazil
b7756d9250 version bump 2020-04-20 16:33:26 -07:00
Kelly Brazil
1cd2cd954c remove references to homebrew/shim to allow tests to pass in homebrew packaging ci/cd 2020-04-20 16:31:22 -07:00
Kelly Brazil
72020b8da9 move packages info to jc-packages github page 2020-04-17 10:20:25 -07:00
Kelly Brazil
cf9720b749 update install info 2020-04-16 14:03:31 -07:00
Kelly Brazil
967b9db7f9 spelling 2020-04-15 21:27:22 -07:00
Kelly Brazil
bb3acb1182 formatting 2020-04-15 21:25:06 -07:00
Kelly Brazil
560c7f7e6d formatting 2020-04-15 21:23:55 -07:00
Kelly Brazil
79b2841764 add new binary package install info 2020-04-15 21:22:43 -07:00
Kelly Brazil
a06a89cbd1 version bump 2020-04-14 11:15:24 -07:00
Kelly Brazil
431bd969eb use sys.exit(0) instead of exit() 2020-04-14 11:10:31 -07:00
Kelly Brazil
c87b722aec spelling 2020-04-12 13:23:58 -07:00
Kelly Brazil
3688b8b014 Merge pull request #56 from kellyjonbrazil/dev
Dev v1.10.4
2020-04-12 13:21:38 -07:00
Kelly Brazil
07b8d9e0c0 version bump 2020-04-12 13:18:28 -07:00
Kelly Brazil
7454b53e39 formatting 2020-04-12 13:13:28 -07:00
Kelly Brazil
3d6a76024d update with JC_COLORS info 2020-04-12 13:10:57 -07:00
Kelly Brazil
421b980957 JC_COLORS working 2020-04-12 13:03:09 -07:00
Kelly Brazil
4a22e27d6a add set_env_colors function 2020-04-12 12:43:51 -07:00
Kelly Brazil
99f7842dee fix brek on pipe error 2020-04-09 13:38:33 -07:00
Kelly Brazil
7f869b4b18 change colors to ansi and match jello style 2020-04-09 07:31:21 -07:00
Kelly Brazil
9665f4ee84 add pypi badge 2020-04-07 08:44:15 -07:00
Kelly Brazil
606904d48b Merge pull request #53 from kellyjonbrazil/dev
Dev v1.10.1
2020-04-04 17:28:21 -07:00
Kelly Brazil
3f5279b97c version bump to 1.10.1 2020-04-04 17:25:55 -07:00
Kelly Brazil
f5ec21e6ac use in instead of find() 2020-04-04 17:19:32 -07:00
Kelly Brazil
578a284465 use in instead of find() 2020-04-04 17:18:39 -07:00
Kelly Brazil
422e392d9d use in instead of find() 2020-04-04 17:17:43 -07:00
Kelly Brazil
54dfffd34a use in instead of find() 2020-04-04 17:16:25 -07:00
Kelly Brazil
cffba64d2b use in and startswith() instead of find() 2020-04-04 17:15:03 -07:00
Kelly Brazil
56a0c12a59 use in instead of find() 2020-04-04 17:12:22 -07:00
Kelly Brazil
c174d3de18 use in and startswith() instead of find() 2020-04-04 17:10:46 -07:00
Kelly Brazil
a9c59ef9fc fix logic to not for ' type ' in cleandata[0] 2020-04-04 17:07:38 -07:00
Kelly Brazil
abdb9b2673 use in instead of find() 2020-04-04 17:05:17 -07:00
Kelly Brazil
548aaab626 remove old commented code 2020-04-04 17:04:20 -07:00
Kelly Brazil
20571c87ae us in instead of find() 2020-04-04 17:01:56 -07:00
Kelly Brazil
19e49200de version bump 2020-04-04 16:59:48 -07:00
Kelly Brazil
d32f5c67a9 use startswith() instead of find() 2020-04-04 16:59:03 -07:00
Kelly Brazil
b83b626435 use startswith() instead of find() 2020-04-04 16:57:23 -07:00
Kelly Brazil
ab2c1b25ec use startswith() and in instead of find() 2020-04-04 16:56:11 -07:00
Kelly Brazil
f2d46313a4 use startswith() instead of find() 2020-04-04 16:53:55 -07:00
Kelly Brazil
87e4796a6c use in instead of .find() 2020-04-04 16:52:45 -07:00
Kelly Brazil
0014a5c2f4 us startswith() and in instead of .find() 2020-04-04 16:51:36 -07:00
Kelly Brazil
7af56e0dad use startswith() and in instead of find() 2020-04-04 16:50:05 -07:00
Kelly Brazil
a5ae6e3c01 use startswith() instead of find() 2020-04-04 16:48:16 -07:00
Kelly Brazil
fe1a0d1faf use in instead of .find() 2020-04-04 16:46:09 -07:00
Kelly Brazil
302f05cdda prettify style block 2020-04-03 14:50:20 -07:00
Kelly Brazil
c0044be7b0 rename color grey to gray 2020-04-03 14:48:19 -07:00
Kelly Brazil
0110078807 update badge 2020-04-03 14:47:08 -07:00
Kelly Brazil
42eacb45f8 rename to Tests 2020-04-03 14:45:04 -07:00
Kelly Brazil
a43e2e1991 add -m option info 2020-04-02 17:40:06 -07:00
Kelly Brazil
c8b721d4f6 version bump to 1.10.0 2020-04-02 17:35:35 -07:00
Kelly Brazil
d0bfddc3d9 add color and -m monochrome option 2020-04-02 17:29:25 -07:00
Kelly Brazil
6b925a16c8 add tests badge 2020-04-02 10:55:32 -07:00
Kelly Brazil
89ebd9fc22 add axfr info to schema 2020-03-27 07:31:08 -07:00
Kelly Brazil
6b4ba66231 Merge pull request #52 from kellyjonbrazil/dev
Dev v1.9.3
2020-03-26 17:15:13 -07:00
Kelly Brazil
5b697dc381 add more dig tests 2020-03-26 17:09:29 -07:00
Kelly Brazil
9ba73c95d1 add tests 2020-03-26 16:45:29 -07:00
Kelly Brazil
93aa390447 version bump to v1.9.3 2020-03-26 16:30:17 -07:00
Kelly Brazil
3cfb8945dd use startswith() instead of find 2020-03-26 16:29:59 -07:00
Kelly Brazil
cd8d38f2a1 add axfr support 2020-03-26 16:22:53 -07:00
Kelly Brazil
8ec8cd6294 Merge pull request #50 from kellyjonbrazil/dev
Dev v1.9.2
2020-03-12 17:09:04 -07:00
Kelly Brazil
c028113561 version bump to v1.9.2 2020-03-12 17:06:55 -07:00
Kelly Brazil
5f22e1c803 fix and test for osx arp entries without ifscope 2020-03-12 17:02:26 -07:00
Kelly Brazil
d3351787e5 change osx detection 2020-03-12 16:52:33 -07:00
Kelly Brazil
e5bea9ae3b version bump 2020-03-12 08:52:01 -07:00
Kelly Brazil
93c710abe9 Merge pull request #49 from kellyjonbrazil/dev
Dev v1.9.1
2020-03-12 08:23:10 -07:00
Kelly Brazil
c29e7cfe5c version bump to 1.9.1 2020-03-12 08:17:28 -07:00
Kelly Brazil
cb5c1ba00d add tests for fix to make the file parser splitting more robust 2020-03-11 17:04:48 -07:00
Kelly Brazil
9a012b94e1 make splitting more robust 2020-03-11 15:40:34 -07:00
Kelly Brazil
400f5a44ec Merge pull request #48 from kellyjonbrazil/dev
Dev v1.9.0
2020-03-11 13:37:22 -07:00
Kelly Brazil
a2ab5bab91 version bump to v1.9.0 2020-03-11 13:32:58 -07:00
Kelly Brazil
fc8ab27361 bugfix for misaligned columns and additional test for ntpq #31 2020-03-11 13:24:55 -07:00
Kelly Brazil
59f19d33a5 add file command tests for #41 2020-03-11 12:39:59 -07:00
Kelly Brazil
dfc9618115 add file parser for issue #41 2020-03-11 12:20:58 -07:00
Kelly Brazil
8e02e5c75a fix issue with getting options with some commands #47 2020-03-11 09:21:14 -07:00
Kelly Brazil
970493ab93 add magic commands 2020-03-11 06:22:54 -07:00
Kelly Brazil
64d78956eb update acknowledgment 2020-03-10 22:18:26 -07:00
Kelly Brazil
40c05346f4 re-adding optimizations from https://github.com/philippeitis 2020-03-10 22:16:40 -07:00
Kelly Brazil
e9b0bc1409 doc update 2020-03-10 22:03:54 -07:00
Kelly Brazil
798e6bb7d9 tests passing for airport -s. issue #46 2020-03-10 22:03:44 -07:00
Kelly Brazil
12a370deed add airport -s parser for issue #46 2020-03-10 21:51:02 -07:00
Kelly Brazil
553bfbe1a0 tests passing for airport -I. Issue #46 2020-03-10 21:02:17 -07:00
Kelly Brazil
52494321fc fixes and docs for airport parser issue #46 2020-03-10 20:55:07 -07:00
Kelly Brazil
c6c9e06496 added airport command parser 2020-03-10 20:35:52 -07:00
Kelly Brazil
e3a6c05a58 timedatectl fixes, tests, and fixtures for issue #42 2020-03-10 20:26:53 -07:00
Kelly Brazil
391d06f68d change selection_state to state 2020-03-10 20:16:41 -07:00
Kelly Brazil
99804ea06e added timedatectl status parser 2020-03-10 18:37:55 -07:00
Kelly Brazil
51935deb2a timedatectl test fixtures 2020-03-10 18:00:47 -07:00
Kelly Brazil
b24d0c3a47 ntpq docs 2020-03-10 18:00:26 -07:00
Kelly Brazil
762a886d6f add ntpq tests 2020-03-10 15:17:25 -07:00
Kelly Brazil
2c3e9ddfe4 add ntpq parser for issue #31 2020-03-10 14:18:55 -07:00
Kelly Brazil
c7cd2b63c8 delete unused test file 2020-03-09 11:46:17 -07:00
Kelly Brazil
f0528ea831 Merge pull request #45 from kellyjonbrazil/dev
Dev v1.8.1
2020-03-08 14:54:13 -07:00
Kelly Brazil
5bc5596f60 version bump to 1.8.1 2020-03-08 14:49:23 -07:00
Kelly Brazil
2c27ac46be add ls test fixtures 2020-03-08 14:43:51 -07:00
Kelly Brazil
caad840153 Merge pull request #44 from philippeitis/patch-5
Move core magic() logic into seperate function for testability, minor tweaks
2020-03-08 14:19:37 -07:00
philippeitis
65bd7e2904 Merge pull request #1 from kellyjonbrazil/pr/44
Merge changes
2020-03-08 14:10:35 -07:00
Kelly Brazil
c3d7d7db12 removed whitespace 2020-03-08 14:03:08 -07:00
Kelly Brazil
5605310362 added tests, removed os import, changed to 'assertEqual' 2020-03-08 14:02:54 -07:00
philippeitis
17b6efe82e Create basic tests for generate_magic_commands() 2020-03-08 13:35:01 -07:00
philippeitis
a032ae56ae Pass args to generate_magic_command() to allow testing. 2020-03-08 13:26:15 -07:00
philippeitis
eab2f4b056 Move core magic() logic into seperate function for testability, minor tweaks.
We only care about the command when testing magic() - by moving that out, we can easily test the command. I modified the code to return a boolean signalling that the command is valid, and the command itself to maintain the original functionality.

I also made some small tweaks (removed a list() call, fixed a possible bug with no arguments., moved magic_dict instantiation past the fast path checks to avoid making a dict if not needed.)
2020-03-08 13:20:38 -07:00
Kelly Brazil
aff86ae6c7 reimpliment magic() based on the dictionary approach suggested by philippeitis 2020-03-08 12:58:26 -07:00
Kelly Brazil
7ece9ddc1a version bump ls 2020-03-07 17:26:42 -08:00
Kelly Brazil
7cd048e839 changelog update 2020-03-07 17:25:10 -08:00
Kelly Brazil
1e22f610a3 fix for osx - doesn't print 'total xx' line if empty directory (issue #40) 2020-03-07 17:22:08 -08:00
Kelly Brazil
5249c972ae add to changelog 2020-03-06 12:09:20 -08:00
Kelly Brazil
fd45f856a0 import jc.utils instead of jc 2020-03-06 12:09:09 -08:00
Kelly Brazil
c8ab40cd33 ignore .github folder 2020-03-05 09:19:58 -08:00
Kelly Brazil
b2c872925b add utf-8 encoding for testing on Windows 2020-03-04 19:47:03 -08:00
Kelly Brazil
f48e229202 utf-8 open for windows tests 2020-03-04 19:40:32 -08:00
Kelly Brazil
799fec92c3 utf-8 for windows support 2020-03-04 19:33:45 -08:00
Kelly Brazil
87a41c2fca add utf-8 to open function 2020-03-04 19:30:30 -08:00
Kelly Brazil
7f85de0c46 add windows-latest 2020-03-04 19:28:21 -08:00
Kelly Brazil
13661b1993 Merge pull request #37 from philippeitis/continuous_integration
Enable Continuous Integration with GitHub Actions.
2020-03-04 16:54:26 -08:00
philippeitis
51d5c3892d Remove Windows tests, due to lack of support. 2020-03-04 16:21:06 -08:00
philippeitis
e4eab4641a Change line in blkid.py to trigger CI 2020-03-04 16:17:58 -08:00
philippeitis
9b148e0ba3 Add requirements.txt 2020-03-04 16:16:19 -08:00
philippeitis
de28932650 Consolidate dictionary into creation, trigger CI 2020-03-04 16:14:03 -08:00
Kelly Brazil
5f798d603e version bump and ack to philippeitis 2020-03-04 16:11:14 -08:00
Kelly Brazil
a0757b2dd3 optimize line parsing 2020-03-04 16:07:53 -08:00
philippeitis
498d51b4e8 Enable Continuous Integration with GitHub Actions.
This automatically runs unit tests on various operating systems and Python versions when Python files are modified to ensure that functionality remains correct.
2020-03-04 16:07:32 -08:00
Kelly Brazil
b06b6bae3f Merge pull request #36 from philippeitis/patch-3
Simplify process() in history.py, avoid list allocation in parse()
2020-03-04 16:04:05 -08:00
Kelly Brazil
b5eaff2137 Merge pull request #35 from kellyjonbrazil/revert-34-patch-3
Revert "Simplify process() in history.py, avoid list allocation in parse()"
2020-03-04 15:33:13 -08:00
Kelly Brazil
c01bcd3734 Revert "Simplify process() in history.py, avoid list allocation in parse()" 2020-03-04 15:32:23 -08:00
Kelly Brazil
d75c4068ca Merge pull request #34 from philippeitis/patch-3
Simplify process() in history.py, avoid list allocation in parse()
2020-03-04 15:31:55 -08:00
Kelly Brazil
6aa2d5a3d2 Merge pull request #33 from philippeitis/patch-2
Handle case where only options are passed.
2020-03-04 15:28:09 -08:00
philippeitis
065276805f Simplify process() in history.py, avoid list allocation in parse() 2020-03-04 13:35:31 -08:00
philippeitis
a63408c8cf Handle case where only options are passed. 2020-03-04 13:16:35 -08:00
Kelly Brazil
69576f6bfa minor sytax fixes 2020-03-04 12:03:40 -08:00
Kelly Brazil
19845624e2 Merge pull request #32 from philippeitis/patch-1
Simplify main(), magic() methods.
2020-03-04 11:59:29 -08:00
philippeitis
22ff2964e9 Simplify main(), magic() methods. 2020-03-04 10:33:42 -08:00
Kelly Brazil
d96b3a65a9 formatting 2020-03-04 08:30:52 -08:00
Kelly Brazil
4989445ef4 Merge pull request #30 from kellyjonbrazil/dev
Dev v1.8.0
2020-03-03 11:46:09 -08:00
Kelly Brazil
6770892acd add release notes link 2020-03-03 11:37:59 -08:00
Kelly Brazil
d4eba8740f release date 3/3 2020-03-03 11:08:52 -08:00
Kelly Brazil
9f60760560 add group and gshadow tests 2020-03-03 10:54:27 -08:00
Kelly Brazil
0a8f8ac934 add group and gshadow parsers 2020-03-03 09:55:43 -08:00
Kelly Brazil
6ae24c8244 add group and gshadow test fixtures 2020-03-03 09:55:17 -08:00
Kelly Brazil
d3679082a8 add group and gshadow parsers 2020-03-03 09:36:16 -08:00
Kelly Brazil
fb08b42dca change 'group_list' to 'members' 2020-03-03 09:32:56 -08:00
Kelly Brazil
4aeaa9f42a add /etc/gshadow parser 2020-03-03 09:32:25 -08:00
Kelly Brazil
5f5693da04 spelling fix 2020-03-03 09:07:28 -08:00
Kelly Brazil
5eb0f61727 add /etc/group file parser 2020-03-03 09:07:09 -08:00
Kelly Brazil
958e998991 formatting 2020-03-02 17:15:05 -08:00
Kelly Brazil
b78c1509f6 try/except dialect detection 2020-03-02 15:06:25 -08:00
Kelly Brazil
ce184d4d57 add csv parser tests 2020-03-02 15:05:56 -08:00
Kelly Brazil
b4c3714ced removed [OPTIONS] PARSER syntax. still works but prefer the PARSER [OPTIONS] syntax for better performance 2020-03-02 14:10:15 -08:00
Kelly Brazil
5b7dfa0438 formatting 2020-03-02 14:07:56 -08:00
Kelly Brazil
391a388476 doc update 2020-03-02 14:07:29 -08:00
Kelly Brazil
d9c4e2ed4c add csv file parser 2020-03-02 14:03:58 -08:00
Kelly Brazil
0c42db38b1 doc update 2020-03-02 10:30:12 -08:00
Kelly Brazil
2f9be8bf33 simplify usage 2020-03-02 08:32:42 -08:00
Kelly Brazil
e8c00155e8 add -b to warning message 2020-03-02 07:43:45 -08:00
Kelly Brazil
cc88fdd9ee update example 2020-03-01 21:17:50 -08:00
Kelly Brazil
d9de11ef1d add another who example 2020-03-01 21:16:57 -08:00
Kelly Brazil
0ceda97d09 who parser tests 2020-03-01 19:03:27 -08:00
Kelly Brazil
d0dec92ba8 add who test fixtures 2020-03-01 18:57:51 -08:00
Kelly Brazil
d420c008d8 fix for pts lines with no user info 2020-03-01 17:52:14 -08:00
Kelly Brazil
f0b32db433 who doc update 2020-03-01 17:39:02 -08:00
Kelly Brazil
bc838eda59 fix output for non-extended 2020-03-01 17:38:51 -08:00
Kelly Brazil
afe55b6af0 add who parser 2020-03-01 17:07:28 -08:00
Kelly Brazil
dd3a3ac302 doc update and process pid integers 2020-03-01 17:04:06 -08:00
Kelly Brazil
f9982a7947 fixes for from and comment fields 2020-03-01 16:49:52 -08:00
Kelly Brazil
07c1be9e9a add who command parser 2020-03-01 16:30:04 -08:00
Kelly Brazil
f832b88755 add passwd and shadow tests 2020-03-01 10:17:47 -08:00
Kelly Brazil
0fac757efc add passwd and shadow parsers 2020-02-29 12:25:41 -08:00
Kelly Brazil
fc15742065 passwd and shadow test fixtures 2020-02-29 12:25:22 -08:00
Kelly Brazil
6f2466a131 update readme with /etc/passwd and /etc/shadow file parsers 2020-02-29 11:56:12 -08:00
Kelly Brazil
4b90e22f0a doc update 2020-02-29 11:50:46 -08:00
Kelly Brazil
c493568785 doc fix 2020-02-29 11:46:38 -08:00
Kelly Brazil
1cdf004b77 add /etc/shadow parser 2020-02-29 11:46:24 -08:00
Kelly Brazil
a4ea504261 add /etc/passwd parser 2020-02-29 11:33:14 -08:00
Kelly Brazil
4c2c234c3b add last and lastb tests 2020-02-28 15:15:24 -08:00
Kelly Brazil
3d4c0f3e89 add blkid tests 2020-02-28 14:50:29 -08:00
Kelly Brazil
52fad02903 doc update 2020-02-28 13:31:38 -08:00
Kelly Brazil
9dcabc057c support multi device udev output 2020-02-28 10:57:14 -08:00
Kelly Brazil
db8c1079dd use maxsplit=1 in case there are multiple '=' delimiters 2020-02-28 09:54:07 -08:00
Kelly Brazil
8f954673ab use shlex split for values within quotations that have spaces 2020-02-28 09:07:36 -08:00
Kelly Brazil
79522d1c7d doc fixes 2020-02-28 08:51:48 -08:00
Kelly Brazil
a18bf03079 use raw strings for regular expressions 2020-02-28 08:50:35 -08:00
Kelly Brazil
c02b6b5d82 doc updates 2020-02-27 21:21:19 -08:00
Kelly Brazil
f99b423284 doc update 2020-02-27 21:04:24 -08:00
Kelly Brazil
d7d9d45d4f add missing comma 2020-02-27 20:59:09 -08:00
Kelly Brazil
90065ec0cd add more integers 2020-02-27 20:57:22 -08:00
Kelly Brazil
51157ebb86 another devname fix 2020-02-27 20:49:14 -08:00
Kelly Brazil
96d95c79ca devname fix 2020-02-27 20:47:07 -08:00
Kelly Brazil
e5da34c233 check if devname key exists before renaming 2020-02-27 20:41:06 -08:00
Kelly Brazil
f09d657f77 rename devname to device 2020-02-27 20:36:19 -08:00
Kelly Brazil
0f4b0189f5 process integer values 2020-02-27 20:31:17 -08:00
Kelly Brazil
4666042abb add blkid parser 2020-02-27 20:21:02 -08:00
Kelly Brazil
027d544c2b add last and lastb parser 2020-02-27 16:08:56 -08:00
Kelly Brazil
f1967d0138 system_boot fix 2020-02-27 16:08:39 -08:00
Kelly Brazil
c1d896027d fix system_boot tty 2020-02-27 15:58:12 -08:00
Kelly Brazil
5c2d2a6618 process function and docs 2020-02-27 15:44:36 -08:00
Kelly Brazil
997b269b0b btmp fix 2020-02-27 15:26:09 -08:00
Kelly Brazil
61257e7525 add last and lastb parser 2020-02-27 15:14:43 -08:00
Kelly Brazil
53ee2c3631 Merge pull request #29 from kellyjonbrazil/dev
Dev v1.7.5
2020-02-27 10:59:14 -08:00
Kelly Brazil
8bfa0bddec version bump to 1.7.5 2020-02-27 10:50:05 -08:00
Kelly Brazil
ad61e6bc81 add ls tests for filenames with newline characters 2020-02-27 10:48:09 -08:00
Kelly Brazil
873b5ba8ac move examples to bottom 2020-02-27 09:36:57 -08:00
Kelly Brazil
6ae50054e2 readme update 2020-02-24 20:30:44 -08:00
Kelly Brazil
22a35f41bf move variables to top 2020-02-24 17:50:56 -08:00
Kelly Brazil
961696c963 add a warning if newlines are detected in naked ls 2020-02-24 17:47:31 -08:00
Kelly Brazil
c7b7f1a5dc fix for files with newlines in naked ls 2020-02-24 17:24:56 -08:00
Kelly Brazil
b5a0d650b1 ls output with newlines 2020-02-24 17:01:33 -08:00
Kelly Brazil
573b279464 fixup for filenames that start with a newline character 2020-02-24 17:01:12 -08:00
Kelly Brazil
116e07f161 fixes for multiple consecutive newlines and trailing newlines in filenames 2020-02-24 16:38:29 -08:00
Kelly Brazil
964868c8af add support for newlines in filenames (only with ls -l) 2020-02-24 15:19:43 -08:00
Kelly Brazil
c8dac32df8 readme update 2020-02-24 13:05:35 -08:00
Kelly Brazil
72a0016bd8 use link to anchor for Parsers 2020-02-20 15:38:45 -08:00
Kelly Brazil
2ad3167434 update doc url 2020-02-19 07:12:43 -08:00
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
645 changed files with 143838 additions and 733 deletions

31
.github/workflows/pythonapp.yml vendored Normal file
View File

@@ -0,0 +1,31 @@
name: Tests
on:
push:
paths:
- "**/*.py"
pull_request:
paths:
- "**/*.py"
jobs:
build:
runs-on: ${{ matrix.os }}
strategy:
matrix:
os: [macos-latest, ubuntu-latest, windows-latest]
python-version: [3.6, 3.7, 3.8]
steps:
- uses: actions/checkout@v2
- name: Set up Python ${{ matrix.python-version }}
uses: actions/setup-python@v1
with:
python-version: ${{ matrix.python-version }}
- name: Install dependencies
run: |
python -m pip install --upgrade pip
pip install -r requirements.txt
- name: Test with unittest
run: |
python -m unittest discover tests

1
.gitignore vendored
View File

@@ -4,3 +4,4 @@ dist/
build/
*.egg-info/
jc/parsers.old/
.github/

1
MANIFEST.in Normal file
View File

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

2542
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

View File

@@ -1,5 +1,151 @@
jc changelog
20200501 v1.10.7
- Requirements modifications for Fedora RPM packaging requirements
20200420 v1.10.6
- Remove homebrew shim references from du osx tests
20200414 v1.10.5
- Minor change of using sys.exit(0) instead of exit()
20200412 v1.10.4
- Add color customization via JC_COLORS env variable
20200409 v1.10.3
- Fix break on pipe error
20200409 v1.10.2
- Change colors to ansi and match jello colors
20200402 v1.10.1
- Code cleanup
20200402 v1.10.0
- Add color output by default when not piping data to another program
- Add -m option for monochrome output
20200326 v1.9.3
- Add axfr support for dig command parser
20200312 v1.9.2
- Updated arp parser to fix OSX detection for some edge cases
20200312 v1.9.1
- Updated file command parser to make filename splitting more robust
20200311 v1.9.0
- Added ntpq command parser
- Added timedatectl status command parser
- Added airport -I and airport -s command parser
- Added file command parser
- Optimized history command parser by https://github.com/philippeitis
- Magic syntax fix for certain edge cases
20200308 v1.8.1
- CLI optimizations by https://github.com/philippeitis
- Refactored magic syntax function and added tests (https://github.com/philippeitis)
- Github actions for CI testing on multiple platforms by https://github.com/philippeitis
- Updated ls parser to fix parsing error in OSX with -lR when there are empty folders
20200303 v1.8.0
- Added blkid command parser
- Added last and lastb command parser
- Added who command parser
- Added CSV file parser
- Added /etc/passwd file parser
- Added /etc/shadow file parser
- Added /etc/group file parser
- Added /etc/gshadow file parser
20200227 v1.7.5
- Updated ls parser to support filenames with newline characters
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

56
docgen.sh Executable file
View File

@@ -0,0 +1,56 @@
#!/bin/bash
# Generate docs.md
cd jc
pydocmd simple jc+ > ../docs/readme.md
pydocmd simple utils+ > ../docs/utils.md
pydocmd simple jc.parsers.airport+ > ../docs/parsers/airport.md
pydocmd simple jc.parsers.airport_s+ > ../docs/parsers/airport_s.md
pydocmd simple jc.parsers.arp+ > ../docs/parsers/arp.md
pydocmd simple jc.parsers.blkid+ > ../docs/parsers/blkid.md
pydocmd simple jc.parsers.crontab+ > ../docs/parsers/crontab.md
pydocmd simple jc.parsers.crontab_u+ > ../docs/parsers/crontab_u.md
pydocmd simple jc.parsers.csv+ > ../docs/parsers/csv.md
pydocmd simple jc.parsers.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.file+ > ../docs/parsers/file.md
pydocmd simple jc.parsers.free+ > ../docs/parsers/free.md
pydocmd simple jc.parsers.fstab+ > ../docs/parsers/fstab.md
pydocmd simple jc.parsers.group+ > ../docs/parsers/group.md
pydocmd simple jc.parsers.gshadow+ > ../docs/parsers/gshadow.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.last+ > ../docs/parsers/last.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.ntpq+ > ../docs/parsers/ntpq.md
pydocmd simple jc.parsers.passwd+ > ../docs/parsers/passwd.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.shadow+ > ../docs/parsers/shadow.md
pydocmd simple jc.parsers.ss+ > ../docs/parsers/ss.md
pydocmd simple jc.parsers.stat+ > ../docs/parsers/stat.md
pydocmd simple jc.parsers.systemctl+ > ../docs/parsers/systemctl.md
pydocmd simple jc.parsers.systemctl_lj+ > ../docs/parsers/systemctl_lj.md
pydocmd simple jc.parsers.systemctl_ls+ > ../docs/parsers/systemctl_ls.md
pydocmd simple jc.parsers.systemctl_luf+ > ../docs/parsers/systemctl_luf.md
pydocmd simple jc.parsers.timedatectl+ > ../docs/parsers/timedatectl.md
pydocmd simple jc.parsers.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.who+ > ../docs/parsers/who.md
pydocmd simple jc.parsers.xml+ > ../docs/parsers/xml.md
pydocmd simple jc.parsers.yaml+ > ../docs/parsers/yaml.md

109
docs/parsers/airport.md Normal file
View File

@@ -0,0 +1,109 @@
# jc.parsers.airport
jc - JSON CLI output utility airport -I Parser
Usage:
specify --airport as the first argument if the piped input is coming from airport -I (OSX)
This program can be found at:
/System/Library/PrivateFrameworks/Apple80211.framework/Versions/Current/Resources/airport
Compatibility:
'darwin'
Examples:
$ airport -I | jc --airport -p
{
"agrctlrssi": -66,
"agrextrssi": 0,
"agrctlnoise": -90,
"agrextnoise": 0,
"state": "running",
"op_mode": "station",
"lasttxrate": 195,
"maxrate": 867,
"lastassocstatus": 0,
"802_11_auth": "open",
"link_auth": "wpa2-psk",
"bssid": "3c:37:86:15:ad:f9",
"ssid": "SnazzleDazzle",
"mcs": 0,
"channel": "48,80"
}
$ airport -I | jc --airport -p -r
{
"agrctlrssi": "-66",
"agrextrssi": "0",
"agrctlnoise": "-90",
"agrextnoise": "0",
"state": "running",
"op_mode": "station",
"lasttxrate": "195",
"maxrate": "867",
"lastassocstatus": "0",
"802_11_auth": "open",
"link_auth": "wpa2-psk",
"bssid": "3c:37:86:15:ad:f9",
"ssid": "SnazzleDazzle",
"mcs": "0",
"channel": "48,80"
}
## 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:
{
"agrctlrssi": integer,
"agrextrssi": integer,
"agrctlnoise": integer,
"agrextnoise": integer,
"state": string,
"op_mode": string,
"lasttxrate": integer,
"maxrate": integer,
"lastassocstatus": integer,
"802_11_auth": string,
"link_auth": string,
"bssid": string,
"ssid": string,
"mcs": integer,
"channel": 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.

136
docs/parsers/airport_s.md Normal file
View File

@@ -0,0 +1,136 @@
# jc.parsers.airport_s
jc - JSON CLI output utility airport -s Parser
Usage:
specify --airport as the first argument if the piped input is coming from airport -s (OSX)
This program can be found at:
/System/Library/PrivateFrameworks/Apple80211.framework/Versions/Current/Resources/airport
Compatibility:
'darwin'
Examples:
$ airport -s | jc --airport-s -p
[
{
"ssid": "DIRECT-4A-HP OfficeJet 3830",
"bssid": "00:67:eb:2a:a7:3b",
"rssi": -90,
"channel": "6",
"ht": true,
"cc": "--",
"security": [
"WPA2(PSK/AES/AES)"
]
},
{
"ssid": "Latitude38",
"bssid": "c0:ff:d5:d2:7a:f3",
"rssi": -85,
"channel": "11",
"ht": true,
"cc": "US",
"security": [
"WPA2(PSK/AES/AES)"
]
},
{
"ssid": "xfinitywifi",
"bssid": "6e:e3:0e:b8:45:99",
"rssi": -83,
"channel": "11",
"ht": true,
"cc": "US",
"security": [
"NONE"
]
},
...
]
$ airport -s | jc --airport -p -r
[
{
"ssid": "DIRECT-F3-HP ENVY 5660 series",
"bssid": "b0:5a:da:6f:0a:d4",
"rssi": "-93",
"channel": "1",
"ht": "Y",
"cc": "--",
"security": "WPA2(PSK/AES/AES)"
},
{
"ssid": "YouAreInfected-5",
"bssid": "5c:e3:0e:c2:85:da",
"rssi": "-85",
"channel": "36",
"ht": "Y",
"cc": "US",
"security": "WPA(PSK/AES,TKIP/TKIP) WPA2(PSK/AES,TKIP/TKIP)"
},
{
"ssid": "YuanFamily",
"bssid": "5c:e3:0e:b8:5f:9a",
"rssi": "-84",
"channel": "11",
"ht": "Y",
"cc": "US",
"security": "WPA(PSK/AES,TKIP/TKIP) WPA2(PSK/AES,TKIP/TKIP)"
},
...
]
## 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:
[
{
"ssid": string,
"bssid": string,
"rssi": integer,
"channel": string,
"ht": boolean,
"cc": string,
"security": [
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.

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.

148
docs/parsers/blkid.md Normal file
View File

@@ -0,0 +1,148 @@
# jc.parsers.blkid
jc - JSON CLI output utility blkid Parser
Usage:
specify --blkid as the first argument if the piped input is coming from blkid
Compatibility:
'linux'
Examples:
$ blkid | jc --blkid -p
[
{
"device": "/dev/sda1",
"uuid": "05d927ab-5875-49e4-ada1-7f46cb32c932",
"type": "xfs"
},
{
"device": "/dev/sda2",
"uuid": "3klkIj-w1kk-DkJi-0XBJ-y3i7-i2Ac-vHqWBM",
"type": "LVM2_member"
},
{
"device": "/dev/mapper/centos-root",
"uuid": "07d718ff-950c-4e5b-98f0-42a1147c77d9",
"type": "xfs"
},
{
"device": "/dev/mapper/centos-swap",
"uuid": "615eb89a-bcbf-46fd-80e3-c483ff5c931f",
"type": "swap"
}
]
$ sudo blkid -o udev -ip /dev/sda2 | jc --blkid -p
[
{
"id_fs_uuid": "3klkIj-w1kk-DkJi-0XBJ-y3i7-i2Ac-vHqWBM",
"id_fs_uuid_enc": "3klkIj-w1kk-DkJi-0XBJ-y3i7-i2Ac-vHqWBM",
"id_fs_version": "LVM2\x20001",
"id_fs_type": "LVM2_member",
"id_fs_usage": "raid",
"id_iolimit_minimum_io_size": 512,
"id_iolimit_physical_sector_size": 512,
"id_iolimit_logical_sector_size": 512,
"id_part_entry_scheme": "dos",
"id_part_entry_type": "0x8e",
"id_part_entry_number": 2,
"id_part_entry_offset": 2099200,
"id_part_entry_size": 39843840,
"id_part_entry_disk": "8:0"
}
]
$ sudo blkid -ip /dev/sda1 | jc --blkid -p -r
[
{
"devname": "/dev/sda1",
"uuid": "05d927bb-5875-49e3-ada1-7f46cb31c932",
"type": "xfs",
"usage": "filesystem",
"minimum_io_size": "512",
"physical_sector_size": "512",
"logical_sector_size": "512",
"part_entry_scheme": "dos",
"part_entry_type": "0x83",
"part_entry_flags": "0x80",
"part_entry_number": "1",
"part_entry_offset": "2048",
"part_entry_size": "2097152",
"part_entry_disk": "8: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:
[
{
"device": string,
"uuid": string,
"type": string,
"usage": string,
"part_entry_scheme": string,
"part_entry_type": string,
"part_entry_flags": string,
"part_entry_number": integer,
"part_entry_offset": integer,
"part_entry_size": integer,
"part_entry_disk": string,
"id_fs_uuid": string,
"id_fs_uuid_enc": string,
"id_fs_version": string,
"id_fs_type": string,
"id_fs_usage": string,
"id_part_entry_scheme": string,
"id_part_entry_type": string,
"id_part_entry_flags": string,
"id_part_entry_number": integer,
"id_part_entry_offset": integer,
"id_part_entry_size": integer,
"id_iolimit_minimum_io_size": integer,
"id_iolimit_physical_sector_size": integer,
"id_iolimit_logical_sector_size": integer,
"id_part_entry_disk": string,
"minimum_io_size": integer,
"physical_sector_size": integer,
"logical_sector_size": 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.

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.

105
docs/parsers/csv.md Normal file
View File

@@ -0,0 +1,105 @@
# jc.parsers.csv
jc - JSON CLI output utility csv Parser
Usage:
specify --csv as the first argument if the piped input is coming from a csv file.
the csv parser will attempt to automatically detect the delimiter character.
if the delimiter cannot be detected it will default to comma.
the first row of the file must be a header row.
Compatibility:
'linux', 'darwin', 'cygwin', 'win32', 'aix', 'freebsd'
Examples:
$ cat homes.csv
"Sell", "List", "Living", "Rooms", "Beds", "Baths", "Age", "Acres", "Taxes"
142, 160, 28, 10, 5, 3, 60, 0.28, 3167
175, 180, 18, 8, 4, 1, 12, 0.43, 4033
129, 132, 13, 6, 3, 1, 41, 0.33, 1471
...
$ cat homes.csv | jc --csv -p
[
{
"Sell": "142",
"List": "160",
"Living": "28",
"Rooms": "10",
"Beds": "5",
"Baths": "3",
"Age": "60",
"Acres": "0.28",
"Taxes": "3167"
},
{
"Sell": "175",
"List": "180",
"Living": "18",
"Rooms": "8",
"Beds": "4",
"Baths": "1",
"Age": "12",
"Acres": "0.43",
"Taxes": "4033"
},
{
"Sell": "129",
"List": "132",
"Living": "13",
"Rooms": "6",
"Beds": "3",
"Baths": "1",
"Age": "41",
"Acres": "0.33",
"Taxes": "1471"
},
...
]
## 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 row in the csv file:
[
{
csv file converted to a Dictionary
https://docs.python.org/3/library/csv.html
}
]
## 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.

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.

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

@@ -0,0 +1,412 @@
# 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,
"axfr": [
{
"name": string,
"class": string,
"type": string,
"ttl": integer,
"data": string
}
],
"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
"size": 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.

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

90
docs/parsers/file.md Normal file
View File

@@ -0,0 +1,90 @@
# jc.parsers.file
jc - JSON CLI output utility file command Parser
Usage:
specify --file as the first argument if the piped input is coming from file.
Compatibility:
'linux', 'aix', 'freebsd', 'darwin'
Examples:
$ file * | jc --file -p
[
{
"filename": "Applications",
"type": "directory"
},
{
"filename": "another file with spaces",
"type": "empty"
},
{
"filename": "argstest.py",
"type": "Python script text executable, ASCII text"
},
{
"filename": "blkid-p.out",
"type": "ASCII text"
},
{
"filename": "blkid-pi.out",
"type": "ASCII text, with very long lines"
},
{
"filename": "cd_catalog.xml",
"type": "XML 1.0 document text, ASCII text, with CRLF line terminators"
},
{
"filename": "centosserial.sh",
"type": "Bourne-Again shell script text executable, UTF-8 Unicode text"
},
...
]
## 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,
"type ": 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.

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.

141
docs/parsers/group.md Normal file
View File

@@ -0,0 +1,141 @@
# jc.parsers.group
jc - JSON CLI output utility /etc/group file Parser
Usage:
specify --group as the first argument if the piped input is coming from /etc/group
Compatibility:
'linux', 'darwin', 'aix', 'freebsd'
Examples:
$ cat /etc/group | jc --group -p
[
{
"group_name": "nobody",
"password": "*",
"gid": -2,
"members": []
},
{
"group_name": "nogroup",
"password": "*",
"gid": -1,
"members": []
},
{
"group_name": "wheel",
"password": "*",
"gid": 0,
"members": [
"root"
]
},
{
"group_name": "certusers",
"password": "*",
"gid": 29,
"members": [
"root",
"_jabber",
"_postfix",
"_cyrus",
"_calendar",
"_dovecot"
]
},
...
]
$ cat /etc/group | jc --group -p -r
[
{
"group_name": "nobody",
"password": "*",
"gid": "-2",
"members": [
""
]
},
{
"group_name": "nogroup",
"password": "*",
"gid": "-1",
"members": [
""
]
},
{
"group_name": "wheel",
"password": "*",
"gid": "0",
"members": [
"root"
]
},
{
"group_name": "certusers",
"password": "*",
"gid": "29",
"members": [
"root",
"_jabber",
"_postfix",
"_cyrus",
"_calendar",
"_dovecot"
]
},
...
]
## 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:
[
{
"group_name": string,
"password": string,
"gid": integer,
"members": [
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.

109
docs/parsers/gshadow.md Normal file
View File

@@ -0,0 +1,109 @@
# jc.parsers.gshadow
jc - JSON CLI output utility /etc/gshadow file Parser
Usage:
specify --gshadow as the first argument if the piped input is coming from /etc/gshadow
Compatibility:
'linux', 'aix', 'freebsd'
Examples:
$ cat /etc/gshadow | jc --gshadow -p
[
{
"group_name": "root",
"password": "*",
"administrators": [],
"members": []
},
{
"group_name": "adm",
"password": "*",
"administrators": [],
"members": [
"syslog",
"joeuser"
]
},
...
]
$ cat /etc/gshadow | jc --gshadow -p -r
[
{
"group_name": "root",
"password": "*",
"administrators": [
""
],
"members": [
""
]
},
{
"group_name": "adm",
"password": "*",
"administrators": [
""
],
"members": [
"syslog",
"joeuser"
]
},
...
]
## 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:
[
{
"group_name": string,
"password": string,
"administrators": [
string
],
"members": [
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.

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.

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

@@ -0,0 +1,225 @@
# 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)
```
## IfconfigParser
```python
IfconfigParser(self, console_output)
```
## InterfaceNotFound
```python
InterfaceNotFound(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.

118
docs/parsers/last.md Normal file
View File

@@ -0,0 +1,118 @@
# jc.parsers.last
jc - JSON CLI output utility last Parser
Usage:
specify --last as the first argument if the piped input is coming from last or lastb
Compatibility:
'linux', 'darwin', 'aix', 'freebsd'
Examples:
$ last | jc --last -p
[
{
"user": "kbrazil",
"tty": "ttys002",
"hostname": null,
"login": "Thu Feb 27 14:31",
"logout": "still logged in"
},
{
"user": "kbrazil",
"tty": "ttys003",
"hostname": null,
"login": "Thu Feb 27 10:38",
"logout": "10:38",
"duration": "00:00"
},
{
"user": "kbrazil",
"tty": "ttys003",
"hostname": null,
"login": "Thu Feb 27 10:18",
"logout": "10:18",
"duration": "00:00"
},
...
]
$ last | jc --last -p -r
[
{
"user": "kbrazil",
"tty": "ttys002",
"hostname": "-",
"login": "Thu Feb 27 14:31",
"logout": "still_logged_in"
},
{
"user": "kbrazil",
"tty": "ttys003",
"hostname": "-",
"login": "Thu Feb 27 10:38",
"logout": "10:38",
"duration": "00:00"
},
{
"user": "kbrazil",
"tty": "ttys003",
"hostname": "-",
"login": "Thu Feb 27 10:18",
"logout": "10:18",
"duration": "00:00"
},
...
]
## 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,
"tty": string,
"hostname": string,
"login": string,
"logout": string,
"duration": 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/ls.md Normal file
View File

@@ -0,0 +1,197 @@
# jc.parsers.ls
jc - JSON CLI output utility ls Parser
Note: The -l or -b option of ls should be used to correctly parse filenames that include newline characters.
Since ls does not encode newlines in filenames when outputting to a pipe it will cause jc to see
multiple files instead of a single file if -l or -b is not used.
Usage:
specify --ls as the first argument if the piped input is coming from ls
ls options supported:
-lbaR
--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.

235
docs/parsers/ntpq.md Normal file
View File

@@ -0,0 +1,235 @@
# jc.parsers.ntpq
jc - JSON CLI output utility ntpq Parser
Usage:
specify --ntpq as the first argument if the piped input is coming from ntpq -p
Compatibility:
'linux'
Examples:
$ ntpq -p | jc --ntpq -p
[
{
"remote": "44.190.6.254",
"refid": "127.67.113.92",
"st": 2,
"t": "u",
"when": 1,
"poll": 64,
"reach": 1,
"delay": 23.399,
"offset": -2.805,
"jitter": 2.131,
"state": null
},
{
"remote": "ntp.wdc1.us.lea",
"refid": "130.133.1.10",
"st": 2,
"t": "u",
"when": null,
"poll": 64,
"reach": 1,
"delay": 93.053,
"offset": -0.807,
"jitter": 2.839,
"state": null
},
{
"remote": "clock.team-cymr",
"refid": "204.9.54.119",
"st": 2,
"t": "u",
"when": null,
"poll": 64,
"reach": 1,
"delay": 70.337,
"offset": -2.909,
"jitter": 2.6,
"state": null
},
{
"remote": "mirror1.sjc02.s",
"refid": "216.218.254.202",
"st": 2,
"t": "u",
"when": 2,
"poll": 64,
"reach": 1,
"delay": 29.325,
"offset": 1.044,
"jitter": 4.069,
"state": null,
}
]
$ ntpq -pn| jc --ntpq -p
[
{
"remote": "44.190.6.254",
"refid": "127.67.113.92",
"st": 2,
"t": "u",
"when": 66,
"poll": 64,
"reach": 377,
"delay": 22.69,
"offset": -0.392,
"jitter": 2.085,
"state": "+"
},
{
"remote": "108.59.2.24",
"refid": "130.133.1.10",
"st": 2,
"t": "u",
"when": 63,
"poll": 64,
"reach": 377,
"delay": 90.805,
"offset": 2.84,
"jitter": 1.908,
"state": "-"
},
{
"remote": "38.229.71.1",
"refid": "204.9.54.119",
"st": 2,
"t": "u",
"when": 64,
"poll": 64,
"reach": 377,
"delay": 68.699,
"offset": -0.61,
"jitter": 2.576,
"state": "+"
},
{
"remote": "72.5.72.15",
"refid": "216.218.254.202",
"st": 2,
"t": "u",
"when": 63,
"poll": 64,
"reach": 377,
"delay": 22.654,
"offset": 0.231,
"jitter": 1.964,
"state": "*"
}
]
$ ntpq -pn| jc --ntpq -p -r
[
{
"s": "+",
"remote": "44.190.6.254",
"refid": "127.67.113.92",
"st": "2",
"t": "u",
"when": "66",
"poll": "64",
"reach": "377",
"delay": "22.690",
"offset": "-0.392",
"jitter": "2.085"
},
{
"s": "-",
"remote": "108.59.2.24",
"refid": "130.133.1.10",
"st": "2",
"t": "u",
"when": "63",
"poll": "64",
"reach": "377",
"delay": "90.805",
"offset": "2.840",
"jitter": "1.908"
},
{
"s": "+",
"remote": "38.229.71.1",
"refid": "204.9.54.119",
"st": "2",
"t": "u",
"when": "64",
"poll": "64",
"reach": "377",
"delay": "68.699",
"offset": "-0.610",
"jitter": "2.576"
},
{
"s": "*",
"remote": "72.5.72.15",
"refid": "216.218.254.202",
"st": "2",
"t": "u",
"when": "63",
"poll": "64",
"reach": "377",
"delay": "22.654",
"offset": "0.231",
"jitter": "1.964"
}
]
## 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:
[
{
"state": string, # space/~ converted to null
"remote": string,
"refid": string,
"st": integer,
"t": string,
"when": integer, # - converted to null
"poll": integer,
"reach": integer,
"delay": float,
"offset": float,
"jitter": 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:
List of dictionaries. Raw or processed structured data.

126
docs/parsers/passwd.md Normal file
View File

@@ -0,0 +1,126 @@
# jc.parsers.passwd
jc - JSON CLI output utility /etc/passwd file Parser
Usage:
specify --passwd as the first argument if the piped input is coming from /etc/passwd
Compatibility:
'linux', 'darwin', 'aix', 'freebsd'
Examples:
$ cat /etc/passwd | jc --passwd -p
[
{
"username": "nobody",
"password": "*",
"uid": -2,
"gid": -2,
"comment": "Unprivileged User",
"home": "/var/empty",
"shell": "/usr/bin/false"
},
{
"username": "root",
"password": "*",
"uid": 0,
"gid": 0,
"comment": "System Administrator",
"home": "/var/root",
"shell": "/bin/sh"
},
{
"username": "daemon",
"password": "*",
"uid": 1,
"gid": 1,
"comment": "System Services",
"home": "/var/root",
"shell": "/usr/bin/false"
},
...
]
$ cat /etc/passwd | jc --passwd -p -r
[
{
"username": "nobody",
"password": "*",
"uid": "-2",
"gid": "-2",
"comment": "Unprivileged User",
"home": "/var/empty",
"shell": "/usr/bin/false"
},
{
"username": "root",
"password": "*",
"uid": "0",
"gid": "0",
"comment": "System Administrator",
"home": "/var/root",
"shell": "/bin/sh"
},
{
"username": "daemon",
"password": "*",
"uid": "1",
"gid": "1",
"comment": "System Services",
"home": "/var/root",
"shell": "/usr/bin/false"
},
...
]
## 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:
[
{
"username": string,
"password": string,
"uid": integer,
"gid": integer,
"comment": string,
"home": string,
"shell": 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.

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

@@ -0,0 +1,133 @@
# jc.parsers.shadow
jc - JSON CLI output utility /etc/shadow file Parser
Usage:
specify --shadow as the first argument if the piped input is coming from /etc/shadow
Compatibility:
'linux', 'darwin', 'aix', 'freebsd'
Examples:
$ sudo cat /etc/shadow | jc --shadow -p
[
{
"username": "root",
"password": "*",
"last_changed": 18113,
"minimum": 0,
"maximum": 99999,
"warn": 7,
"inactive": null,
"expire": null
},
{
"username": "daemon",
"password": "*",
"last_changed": 18113,
"minimum": 0,
"maximum": 99999,
"warn": 7,
"inactive": null,
"expire": null
},
{
"username": "bin",
"password": "*",
"last_changed": 18113,
"minimum": 0,
"maximum": 99999,
"warn": 7,
"inactive": null,
"expire": null
},
...
]
$ sudo cat /etc/shadow | jc --shadow -p -r
[
{
"username": "root",
"password": "*",
"last_changed": "18113",
"minimum": "0",
"maximum": "99999",
"warn": "7",
"inactive": "",
"expire": ""
},
{
"username": "daemon",
"password": "*",
"last_changed": "18113",
"minimum": "0",
"maximum": "99999",
"warn": "7",
"inactive": "",
"expire": ""
},
{
"username": "bin",
"password": "*",
"last_changed": "18113",
"minimum": "0",
"maximum": "99999",
"warn": "7",
"inactive": "",
"expire": ""
},
...
]
## 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:
[
{
"username": string,
"password": string,
"last_changed": integer,
"minimum": integer,
"maximum": integer,
"warn": integer,
"inactive": integer,
"expire": 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.

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.

View File

@@ -0,0 +1,87 @@
# jc.parsers.timedatectl
jc - JSON CLI output utility timedatectl Parser
Usage:
specify --timedatectl as the first argument if the piped input is coming from timedatectl or timedatectl status
Compatibility:
'linux'
Examples:
$ timedatectl | jc --timedatectl -p
{
"local_time": "Tue 2020-03-10 17:53:21 PDT",
"universal_time": "Wed 2020-03-11 00:53:21 UTC",
"rtc_time": "Wed 2020-03-11 00:53:21",
"time_zone": "America/Los_Angeles (PDT, -0700)",
"ntp_enabled": true,
"ntp_synchronized": true,
"rtc_in_local_tz": false,
"dst_active": true
}
$ timedatectl | jc --timedatectl -p -r
{
"local_time": "Tue 2020-03-10 17:53:21 PDT",
"universal_time": "Wed 2020-03-11 00:53:21 UTC",
"rtc_time": "Wed 2020-03-11 00:53:21",
"time_zone": "America/Los_Angeles (PDT, -0700)",
"ntp_enabled": "yes",
"ntp_synchronized": "yes",
"rtc_in_local_tz": "no",
"dst_active": "yes"
}
## 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:
{
"local_time": string,
"universal_time": string,
"rtc_time": string,
"time_zone": string,
"ntp_enabled": boolean,
"ntp_synchronized": boolean,
"system_clock_synchronized": boolean,
"systemd-timesyncd.service_active": boolean,
"rtc_in_local_tz": boolean,
"dst_active": boolean
}
## parse
```python
parse(data, raw=False, quiet=False)
```
Main text parsing function
Parameters:
data: (string) text data to parse
raw: (boolean) output preprocessed JSON if True
quiet: (boolean) suppress warning messages if True
Returns:
Dictionary. Raw or processed structured data.

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.

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

@@ -0,0 +1,152 @@
# jc.parsers.who
jc - JSON CLI output utility who Parser
Usage:
specify --who as the first argument if the piped input is coming from who
accepts any of the following who options (or no options): -aTH
Compatibility:
'linux', 'darwin', 'cygwin', 'aix', 'freebsd'
Examples:
$ who -a | jc --who -p
[
{
"event": "reboot",
"time": "Feb 7 23:31",
"pid": 1
},
{
"user": "joeuser",
"writeable_tty": "-",
"tty": "console",
"time": "Feb 7 23:32",
"idle": "old",
"pid": 105
},
{
"user": "joeuser",
"writeable_tty": "+",
"tty": "ttys000",
"time": "Feb 13 16:44",
"idle": ".",
"pid": 51217,
"comment": "term=0 exit=0"
},
{
"user": "joeuser",
"writeable_tty": "?",
"tty": "ttys003",
"time": "Feb 28 08:59",
"idle": "01:36",
"pid": 41402
},
{
"user": "joeuser",
"writeable_tty": "+",
"tty": "ttys004",
"time": "Mar 1 16:35",
"idle": ".",
"pid": 15679,
"from": "192.168.1.5"
}
]
$ who -a | jc --who -p -r
[
{
"event": "reboot",
"time": "Feb 7 23:31",
"pid": "1"
},
{
"user": "joeuser",
"writeable_tty": "-",
"tty": "console",
"time": "Feb 7 23:32",
"idle": "old",
"pid": "105"
},
{
"user": "joeuser",
"writeable_tty": "+",
"tty": "ttys000",
"time": "Feb 13 16:44",
"idle": ".",
"pid": "51217",
"comment": "term=0 exit=0"
},
{
"user": "joeuser",
"writeable_tty": "?",
"tty": "ttys003",
"time": "Feb 28 08:59",
"idle": "01:36",
"pid": "41402"
},
{
"user": "joeuser",
"writeable_tty": "+",
"tty": "ttys004",
"time": "Mar 1 16:35",
"idle": ".",
"pid": "15679",
"from": "192.168.1.5"
}
]
## 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,
"event": string,
"writeable_tty": string,
"tty": string,
"time": string,
"idle": string,
"pid": integer,
"from": string,
"comment": 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.

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

@@ -2,58 +2,68 @@
* 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'

405
jc/cli.py Normal file
View File

@@ -0,0 +1,405 @@
#!/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
from pygments import highlight
from pygments.style import Style
from pygments.token import (Name, Number, String, Keyword)
from pygments.lexers import JsonLexer
from pygments.formatters import Terminal256Formatter
import jc.utils
class info():
version = '1.10.7'
description = 'jc cli output JSON conversion tool'
author = 'Kelly Brazil'
author_email = 'kellyjonbrazil@gmail.com'
__version__ = info.version
parsers = [
'airport',
'airport-s',
'arp',
'blkid',
'crontab',
'crontab-u',
'csv',
'df',
'dig',
'du',
'env',
'file',
'free',
'fstab',
'group',
'gshadow',
'history',
'hosts',
'id',
'ifconfig',
'ini',
'iptables',
'jobs',
'last',
'ls',
'lsblk',
'lsmod',
'lsof',
'mount',
'netstat',
'ntpq',
'passwd',
'pip-list',
'pip-show',
'ps',
'route',
'shadow',
'ss',
'stat',
'systemctl',
'systemctl-lj',
'systemctl-ls',
'systemctl-luf',
'timedatectl',
'uname',
'uptime',
'w',
'who',
'xml',
'yaml'
]
def set_env_colors():
"""
Grab custom colors from JC_COLORS environment variable. JC_COLORS env variable takes 4 comma
separated string values and should be in the format of:
JC_COLORS=<keyname_color>,<keyword_color>,<number_color>,<string_color>
Where colors are: black, red, green, yellow, blue, magenta, cyan, gray, brightblack, brightred,
brightgreen, brightyellow, brightblue, brightmagenta, brightcyan, white, default
Default colors:
JC_COLORS=blue,brightblack,magenta,green
or
JC_COLORS=default,default,default,default
"""
env_colors = os.getenv('JC_COLORS')
input_error = False
if env_colors:
color_list = env_colors.split(',')
else:
input_error = True
if env_colors and len(color_list) != 4:
print('jc: Warning: could not parse JC_COLORS environment variable\n', file=sys.stderr)
input_error = True
if env_colors:
for color in color_list:
if color not in ['black', 'red', 'green', 'yellow', 'blue', 'magenta', 'cyan', 'gray', 'brightblack', 'brightred',
'brightgreen', 'brightyellow', 'brightblue', 'brightmagenta', 'brightcyan', 'white', 'default']:
print('jc: Warning: could not parse JC_COLORS environment variable\n', file=sys.stderr)
input_error = True
# if there is an issue with the env variable, just set all colors to default and move on
if input_error:
color_list = ['default', 'default', 'default', 'default']
# Try the color set in the JC_COLORS env variable first. If it is set to default, then fall back to default colors
return {
Name.Tag: f'bold ansi{color_list[0]}' if not color_list[0] == 'default' else f'bold ansiblue', # key names
Keyword: f'ansi{color_list[1]}' if not color_list[1] == 'default' else f'ansibrightblack', # true, false, null
Number: f'ansi{color_list[2]}' if not color_list[2] == 'default' else f'ansimagenta', # numbers
String: f'ansi{color_list[3]}' if not color_list[3] == 'default' else f'ansigreen' # strings
}
def piped_output():
"""returns False if stdout is a TTY. True if output is being piped to another program"""
if sys.stdout.isatty():
return False
else:
return True
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 magic syntax:
jc [OPTIONS] COMMAND
Parsers:
{parsers_string}
Options:
-a about jc
-d debug - show trace messages
-m monochrome output
-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, mono=False, piped_out=False):
# set colors
class JcStyle(Style):
styles = set_env_colors()
if not mono and not piped_out:
if pretty:
print(highlight(json.dumps(data, indent=2), JsonLexer(), Terminal256Formatter(style=JcStyle))[0:-1])
else:
print(highlight(json.dumps(data), JsonLexer(), Terminal256Formatter(style=JcStyle))[0:-1])
else:
if pretty:
print(json.dumps(data, indent=2))
else:
print(json.dumps(data))
def generate_magic_command(args):
"""
Returns a tuple with a boolean and a command, where the boolean signifies that
the command is valid, and the command is either a command string or None.
"""
# Parse with magic syntax: jc -p ls -al
if len(args) <= 1 or args[1].startswith('--'):
return False, None
# correctly parse escape characters and spaces with shlex
args_given = ' '.join(map(shlex.quote, args[1:])).split()
options = []
# find the options
for arg in list(args_given):
# parser found - use standard syntax
if arg.startswith('--'):
return False, None
# option found - populate option list
elif arg.startswith('-'):
options.extend(args_given.pop(0)[1:])
# command found if iterator didn't already stop - stop iterating
else:
break
# all options popped and no command found - for case like 'jc -a'
if len(args_given) == 0:
return False, None
magic_dict = {}
parser_info = about_jc()['parsers']
# Create a dictionary of magic_commands to their respective parsers.
for entry in parser_info:
# Update the dict with all of the magic commands for this parser, if they exist.
magic_dict.update({mc: entry['argument'] for mc in entry.get('magic_commands', [])})
# find the command and parser
one_word_command = args_given[0]
two_word_command = ' '.join(args_given[0:2])
# Try to get a parser for two_word_command, otherwise get one for one_word_command
found_parser = magic_dict.get(two_word_command, magic_dict.get(one_word_command))
# construct a new command line using the standard syntax: COMMAND | jc --PARSER -OPTIONS
run_command = ' '.join(args_given)
if found_parser:
cmd_options = ('-' + ''.join(options)) if options else ''
return True, ' '.join([run_command, '|', 'jc', found_parser, cmd_options])
else:
return False, run_command
def magic():
valid_command, run_command = generate_magic_command(sys.argv)
if valid_command:
os.system(run_command)
sys.exit(0)
elif run_command is None:
return
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)
# break on pipe error. need try/except for windows compatibility
try:
signal.signal(signal.SIGPIPE, signal.SIG_DFL)
except AttributeError:
pass
# try magic syntax first: e.g. jc -p ls -al
magic()
options = []
# options
for opt in sys.argv:
if opt.startswith('-') and not opt.startswith('--'):
options.extend(opt[1:])
debug = 'd' in options
mono = 'm' in options
pretty = 'p' in options
quiet = 'q' in options
raw = 'r' in options
if 'a' in options:
json_out(about_jc(), pretty=pretty, mono=mono, piped_out=piped_output())
sys.exit(0)
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, mono=mono, piped_out=piped_output())
if __name__ == '__main__':
main()

View File

@@ -1,61 +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
import jc.parsers.ps
import jc.parsers.route
def main():
data = sys.stdin.read()
pretty = False
if '-p' in sys.argv:
pretty = True
if '--ifconfig' in sys.argv:
result = jc.parsers.ifconfig.parse(data)
elif '--ls' in sys.argv:
result = jc.parsers.ls.parse(data)
elif '--netstat' in sys.argv:
result = jc.parsers.netstat.parse(data)
elif '--ps' in sys.argv:
result = jc.parsers.ps.parse(data)
elif '--route' in sys.argv:
result = jc.parsers.route.parse(data)
else:
print('jc: missing arguments', file=sys.stderr)
print('Usage: jc [parser] [options]\n', file=sys.stderr)
print('Parsers:', file=sys.stderr)
print(' --ifconfig iconfig parser', file=sys.stderr)
print(' --ls ls parser', file=sys.stderr)
print(' --netstat netstat parser', file=sys.stderr)
print(' --ps ps parser', file=sys.stderr)
print(' --route route parser\n', file=sys.stderr)
print('Options:', file=sys.stderr)
print(' -p pretty print output\n', file=sys.stderr)
print('Example:', file=sys.stderr)
print(' ls -al | jc --ls -p\n', file=sys.stderr)
exit()
# output resulting dictionary as json
if pretty:
print(json.dumps(result, indent=2))
else:
print(json.dumps(result))
if __name__ == '__main__':
main()

141
jc/parsers/airport.py Normal file
View File

@@ -0,0 +1,141 @@
"""jc - JSON CLI output utility airport -I Parser
Usage:
specify --airport as the first argument if the piped input is coming from airport -I (OSX)
This program can be found at:
/System/Library/PrivateFrameworks/Apple80211.framework/Versions/Current/Resources/airport
Compatibility:
'darwin'
Examples:
$ airport -I | jc --airport -p
{
"agrctlrssi": -66,
"agrextrssi": 0,
"agrctlnoise": -90,
"agrextnoise": 0,
"state": "running",
"op_mode": "station",
"lasttxrate": 195,
"maxrate": 867,
"lastassocstatus": 0,
"802_11_auth": "open",
"link_auth": "wpa2-psk",
"bssid": "3c:37:86:15:ad:f9",
"ssid": "SnazzleDazzle",
"mcs": 0,
"channel": "48,80"
}
$ airport -I | jc --airport -p -r
{
"agrctlrssi": "-66",
"agrextrssi": "0",
"agrctlnoise": "-90",
"agrextnoise": "0",
"state": "running",
"op_mode": "station",
"lasttxrate": "195",
"maxrate": "867",
"lastassocstatus": "0",
"802_11_auth": "open",
"link_auth": "wpa2-psk",
"bssid": "3c:37:86:15:ad:f9",
"ssid": "SnazzleDazzle",
"mcs": "0",
"channel": "48,80"
}
"""
import jc.utils
class info():
version = '1.0'
description = 'airport -I 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 = ['darwin']
magic_commands = ['airport -I']
__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:
{
"agrctlrssi": integer,
"agrextrssi": integer,
"agrctlnoise": integer,
"agrextnoise": integer,
"state": string,
"op_mode": string,
"lasttxrate": integer,
"maxrate": integer,
"lastassocstatus": integer,
"802_11_auth": string,
"link_auth": string,
"bssid": string,
"ssid": string,
"mcs": integer,
"channel": string
}
"""
# integer changes
int_list = ['agrctlrssi', 'agrextrssi', 'agrctlnoise', 'agrextnoise',
'lasttxrate', 'maxrate', 'lastassocstatus', 'mcs']
for key in proc_data:
if key in int_list:
try:
proc_data[key] = int(proc_data[key])
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 = {}
for line in filter(None, data.splitlines()):
linedata = line.split(':', maxsplit=1)
raw_output[linedata[0].strip().lower().replace(' ', '_').replace('.', '_')] = linedata[1].strip()
if raw:
return raw_output
else:
return process(raw_output)

186
jc/parsers/airport_s.py Normal file
View File

@@ -0,0 +1,186 @@
"""jc - JSON CLI output utility airport -s Parser
Usage:
specify --airport as the first argument if the piped input is coming from airport -s (OSX)
This program can be found at:
/System/Library/PrivateFrameworks/Apple80211.framework/Versions/Current/Resources/airport
Compatibility:
'darwin'
Examples:
$ airport -s | jc --airport-s -p
[
{
"ssid": "DIRECT-4A-HP OfficeJet 3830",
"bssid": "00:67:eb:2a:a7:3b",
"rssi": -90,
"channel": "6",
"ht": true,
"cc": "--",
"security": [
"WPA2(PSK/AES/AES)"
]
},
{
"ssid": "Latitude38",
"bssid": "c0:ff:d5:d2:7a:f3",
"rssi": -85,
"channel": "11",
"ht": true,
"cc": "US",
"security": [
"WPA2(PSK/AES/AES)"
]
},
{
"ssid": "xfinitywifi",
"bssid": "6e:e3:0e:b8:45:99",
"rssi": -83,
"channel": "11",
"ht": true,
"cc": "US",
"security": [
"NONE"
]
},
...
]
$ airport -s | jc --airport -p -r
[
{
"ssid": "DIRECT-F3-HP ENVY 5660 series",
"bssid": "b0:5a:da:6f:0a:d4",
"rssi": "-93",
"channel": "1",
"ht": "Y",
"cc": "--",
"security": "WPA2(PSK/AES/AES)"
},
{
"ssid": "YouAreInfected-5",
"bssid": "5c:e3:0e:c2:85:da",
"rssi": "-85",
"channel": "36",
"ht": "Y",
"cc": "US",
"security": "WPA(PSK/AES,TKIP/TKIP) WPA2(PSK/AES,TKIP/TKIP)"
},
{
"ssid": "YuanFamily",
"bssid": "5c:e3:0e:b8:5f:9a",
"rssi": "-84",
"channel": "11",
"ht": "Y",
"cc": "US",
"security": "WPA(PSK/AES,TKIP/TKIP) WPA2(PSK/AES,TKIP/TKIP)"
},
...
]
"""
import jc.utils
import jc.parsers.universal
class info():
version = '1.0'
description = 'airport -s 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 = ['darwin']
magic_commands = ['airport -s']
__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:
[
{
"ssid": string,
"bssid": string,
"rssi": integer,
"channel": string,
"ht": boolean,
"cc": string,
"security": [
string,
]
}
]
"""
for entry in proc_data:
# integers
int_list = ['rssi']
for key in int_list:
if key in entry:
try:
entry[key] = int(entry[key])
except (ValueError):
entry[key] = None
# booleans
bool_list = ['ht']
for key in entry:
if key in bool_list:
try:
entry[key] = True if entry[key] == 'Y' else False
except (ValueError):
entry[key] = None
if 'security' in entry:
entry['security'] = entry['security'].split()
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('security (auth/unicast/group)', 'security')
# parse the data
raw_output = jc.parsers.universal.sparse_table_parse(cleandata)
if raw:
return raw_output
else:
return process(raw_output)

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

@@ -0,0 +1,212 @@
"""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.3'
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].startswith('Entries:'):
cleandata.pop(-1)
# detect if osx style was used
if cleandata[0][-1] == ']':
raw_output = []
for line in cleandata:
splitline = line.split()
output_line = {
'name': splitline[0],
'address': splitline[1].lstrip('(').rstrip(')'),
'hwtype': splitline[-1].lstrip('[').rstrip(']'),
'hwaddress': splitline[3],
'iface': splitline[5]
}
raw_output.append(output_line)
if raw:
return raw_output
else:
return process(raw_output)
# detect if linux style was used
elif cleandata[0].startswith('Address'):
# fix header row to change Flags Mask to flags_mask
cleandata[0] = cleandata[0].replace('Flags Mask', 'flags_mask')
cleandata[0] = cleandata[0].lower()
raw_output = jc.parsers.universal.simple_table_parse(cleandata)
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 = {
'name': line[0],
'address': line[1].lstrip('(').rstrip(')'),
'hwtype': line[4].lstrip('[').rstrip(']'),
'hwaddress': line[3],
'iface': line[6],
}
raw_output.append(output_line)
if raw:
return raw_output
else:
return process(raw_output)

218
jc/parsers/blkid.py Normal file
View File

@@ -0,0 +1,218 @@
"""jc - JSON CLI output utility blkid Parser
Usage:
specify --blkid as the first argument if the piped input is coming from blkid
Compatibility:
'linux'
Examples:
$ blkid | jc --blkid -p
[
{
"device": "/dev/sda1",
"uuid": "05d927ab-5875-49e4-ada1-7f46cb32c932",
"type": "xfs"
},
{
"device": "/dev/sda2",
"uuid": "3klkIj-w1kk-DkJi-0XBJ-y3i7-i2Ac-vHqWBM",
"type": "LVM2_member"
},
{
"device": "/dev/mapper/centos-root",
"uuid": "07d718ff-950c-4e5b-98f0-42a1147c77d9",
"type": "xfs"
},
{
"device": "/dev/mapper/centos-swap",
"uuid": "615eb89a-bcbf-46fd-80e3-c483ff5c931f",
"type": "swap"
}
]
$ sudo blkid -o udev -ip /dev/sda2 | jc --blkid -p
[
{
"id_fs_uuid": "3klkIj-w1kk-DkJi-0XBJ-y3i7-i2Ac-vHqWBM",
"id_fs_uuid_enc": "3klkIj-w1kk-DkJi-0XBJ-y3i7-i2Ac-vHqWBM",
"id_fs_version": "LVM2\\x20001",
"id_fs_type": "LVM2_member",
"id_fs_usage": "raid",
"id_iolimit_minimum_io_size": 512,
"id_iolimit_physical_sector_size": 512,
"id_iolimit_logical_sector_size": 512,
"id_part_entry_scheme": "dos",
"id_part_entry_type": "0x8e",
"id_part_entry_number": 2,
"id_part_entry_offset": 2099200,
"id_part_entry_size": 39843840,
"id_part_entry_disk": "8:0"
}
]
$ sudo blkid -ip /dev/sda1 | jc --blkid -p -r
[
{
"devname": "/dev/sda1",
"uuid": "05d927bb-5875-49e3-ada1-7f46cb31c932",
"type": "xfs",
"usage": "filesystem",
"minimum_io_size": "512",
"physical_sector_size": "512",
"logical_sector_size": "512",
"part_entry_scheme": "dos",
"part_entry_type": "0x83",
"part_entry_flags": "0x80",
"part_entry_number": "1",
"part_entry_offset": "2048",
"part_entry_size": "2097152",
"part_entry_disk": "8:0"
}
]
"""
import shlex
import jc.utils
class info():
version = '1.0'
description = 'blkid command parser'
author = 'Kelly Brazil'
author_email = 'kellyjonbrazil@gmail.com'
# details = 'enter any other details here'
# compatible options: linux, darwin, cygwin, win32, aix, freebsd
compatible = ['linux']
magic_commands = ['blkid']
__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:
[
{
"device": string,
"uuid": string,
"type": string,
"usage": string,
"part_entry_scheme": string,
"part_entry_type": string,
"part_entry_flags": string,
"part_entry_number": integer,
"part_entry_offset": integer,
"part_entry_size": integer,
"part_entry_disk": string,
"id_fs_uuid": string,
"id_fs_uuid_enc": string,
"id_fs_version": string,
"id_fs_type": string,
"id_fs_usage": string,
"id_part_entry_scheme": string,
"id_part_entry_type": string,
"id_part_entry_flags": string,
"id_part_entry_number": integer,
"id_part_entry_offset": integer,
"id_part_entry_size": integer,
"id_iolimit_minimum_io_size": integer,
"id_iolimit_physical_sector_size": integer,
"id_iolimit_logical_sector_size": integer,
"id_part_entry_disk": string,
"minimum_io_size": integer,
"physical_sector_size": integer,
"logical_sector_size": integer
}
]
"""
for entry in proc_data:
if 'devname' in entry:
entry['device'] = entry.pop('devname')
int_list = ['part_entry_number', 'part_entry_offset', 'part_entry_size', 'id_part_entry_number',
'id_part_entry_offset', 'id_part_entry_size', 'minimum_io_size', 'physical_sector_size',
'logical_sector_size', 'id_iolimit_minimum_io_size', 'id_iolimit_physical_sector_size',
'id_iolimit_logical_sector_size']
for key in int_list:
if key in entry:
try:
entry[key] = int(entry[key])
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 = []
if data:
# if the first field is a device, use normal parsing:
if data.split(maxsplit=1)[0][-1] == ':':
linedata = data.splitlines()
for line in linedata:
output_line = {}
entries = shlex.split(line)
output_line['device'] = entries.pop(0)[:-1]
for entry in entries:
key = entry.split('=', maxsplit=1)[0].lower()
value = entry.split('=', maxsplit=1)[1]
output_line[key] = value
raw_output.append(output_line)
# else use key/value per line parsing
else:
linedata = data.splitlines()
output_line = {}
for line in linedata:
if line == '':
if output_line:
raw_output.append(output_line)
output_line = {}
continue
continue
key = line.split('=', maxsplit=1)[0].lower()
value = line.split('=', maxsplit=1)[1]
output_line[key] = value
if output_line:
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.2'
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().startswith('#'):
cleandata.pop(i)
# Pop any variable assignment lines
cron_var = []
for i, line in reversed(list(enumerate(cleandata))):
if '=' in line:
var_line = cleandata.pop(i)
var_name = var_line.split('=', maxsplit=1)[0].strip()
var_value = var_line.split('=', maxsplit=1)[1].strip()
cron_var.append({'name': var_name,
'value': var_value})
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.1'
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().startswith('#'):
cleandata.pop(i)
# Pop any variable assignment lines
cron_var = []
for i, line in reversed(list(enumerate(cleandata))):
if '=' in line:
var_line = cleandata.pop(i)
var_name = var_line.split('=', maxsplit=1)[0].strip()
var_value = var_line.split('=', maxsplit=1)[1].strip()
cron_var.append({'name': var_name,
'value': var_value})
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)

141
jc/parsers/csv.py Normal file
View File

@@ -0,0 +1,141 @@
"""jc - JSON CLI output utility csv Parser
Usage:
specify --csv as the first argument if the piped input is coming from a csv file.
the csv parser will attempt to automatically detect the delimiter character.
if the delimiter cannot be detected it will default to comma.
the first row of the file must be a header row.
Compatibility:
'linux', 'darwin', 'cygwin', 'win32', 'aix', 'freebsd'
Examples:
$ cat homes.csv
"Sell", "List", "Living", "Rooms", "Beds", "Baths", "Age", "Acres", "Taxes"
142, 160, 28, 10, 5, 3, 60, 0.28, 3167
175, 180, 18, 8, 4, 1, 12, 0.43, 4033
129, 132, 13, 6, 3, 1, 41, 0.33, 1471
...
$ cat homes.csv | jc --csv -p
[
{
"Sell": "142",
"List": "160",
"Living": "28",
"Rooms": "10",
"Beds": "5",
"Baths": "3",
"Age": "60",
"Acres": "0.28",
"Taxes": "3167"
},
{
"Sell": "175",
"List": "180",
"Living": "18",
"Rooms": "8",
"Beds": "4",
"Baths": "1",
"Age": "12",
"Acres": "0.43",
"Taxes": "4033"
},
{
"Sell": "129",
"List": "132",
"Living": "13",
"Rooms": "6",
"Beds": "3",
"Baths": "1",
"Age": "41",
"Acres": "0.33",
"Taxes": "1471"
},
...
]
"""
import jc.utils
import csv
class info():
version = '1.0'
description = 'CSV file parser'
author = 'Kelly Brazil'
author_email = 'kellyjonbrazil@gmail.com'
details = 'Using the python standard csv 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:
List of dictionaries. Each dictionary represents a row in the csv file:
[
{
csv file converted to a Dictionary
https://docs.python.org/3/library/csv.html
}
]
"""
# 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 = []
cleandata = data.splitlines()
# Clear any blank lines
cleandata = list(filter(None, cleandata))
if cleandata:
dialect = None
try:
dialect = csv.Sniffer().sniff(data[:1024])
except Exception:
pass
reader = csv.DictReader(cleandata, dialect=dialect)
for row in reader:
raw_output.append(row)
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.2'
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 '_blocks' in str(k):
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)

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

@@ -0,0 +1,674 @@
"""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.2'
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,
"axfr": [
{
"name": string,
"class": string,
"type": string,
"ttl": integer,
"data": string
}
],
"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
"size": string
}
]
"""
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 'axfr' in entry:
for ax in entry['axfr']:
try:
ttl_int = int(ax['ttl'])
ax['ttl'] = ttl_int
except (ValueError):
ax['ttl'] = 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_axfr(axfr):
# ; <<>> DiG 9.11.14-3-Debian <<>> @81.4.108.41 axfr zonetransfer.me +nocookie
# ; (1 server found)
# ;; global options: +cmd
# zonetransfer.me. 7200 IN A 5.196.105.14
axfr = axfr.split(maxsplit=4)
axfr_name = axfr[0]
axfr_ttl = axfr[1]
axfr_class = axfr[2]
axfr_type = axfr[3]
axfr_data = axfr[4]
return {'name': axfr_name,
'ttl': axfr_ttl,
'class': axfr_class,
'type': axfr_type,
'data': axfr_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
axfr = False
output_entry = {}
for line in cleandata:
if line.startswith('; <<>> ') and ' axfr ' in line.lower():
question = False
authority = False
answer = False
axfr = True
axfr_list = []
continue
if ';' not in line and axfr:
axfr_list.append(parse_axfr(line))
output_entry.update({'axfr': axfr_list})
continue
if line.startswith(';; ->>HEADER<<-'):
output_entry = {}
output_entry.update(parse_header(line))
continue
if line.startswith(';; flags:'):
output_entry.update(parse_flags_line(line))
continue
if line.startswith(';; QUESTION SECTION:'):
question = True
authority = False
answer = False
axfr = False
continue
if question:
output_entry['question'] = parse_question(line)
question = False
authority = False
answer = False
axfr = False
continue
if line.startswith(';; AUTHORITY SECTION:'):
question = False
authority = True
answer = False
axfr = False
authority_list = []
continue
if ';' not in line and authority:
authority_list.append(parse_authority(line))
output_entry.update({'authority': authority_list})
continue
if line.startswith(';; ANSWER SECTION:'):
question = False
authority = False
answer = True
axfr = False
answer_list = []
continue
if ';' not in line 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.startswith(';; Query time:'):
output_entry.update({'query_time': line.split(':')[1].lstrip()})
continue
# footer line 2
if line.startswith(';; SERVER:'):
output_entry.update({'server': line.split(':')[1].lstrip()})
continue
# footer line 3
if line.startswith(';; WHEN:'):
output_entry.update({'when': line.split(':', maxsplit=1)[1].lstrip()})
continue
# footer line 4 (last line)
if line.startswith(';; MSG SIZE rcvd:'):
output_entry.update({'rcvd': line.split(':')[1].lstrip()})
if output_entry:
raw_output.append(output_entry)
elif line.startswith(';; XFR size:'):
output_entry.update({'size': line.split(':')[1].lstrip()})
if output_entry:
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)

128
jc/parsers/file.py Normal file
View File

@@ -0,0 +1,128 @@
"""jc - JSON CLI output utility file command Parser
Usage:
specify --file as the first argument if the piped input is coming from file.
Compatibility:
'linux', 'aix', 'freebsd', 'darwin'
Examples:
$ file * | jc --file -p
[
{
"filename": "Applications",
"type": "directory"
},
{
"filename": "another file with spaces",
"type": "empty"
},
{
"filename": "argstest.py",
"type": "Python script text executable, ASCII text"
},
{
"filename": "blkid-p.out",
"type": "ASCII text"
},
{
"filename": "blkid-pi.out",
"type": "ASCII text, with very long lines"
},
{
"filename": "cd_catalog.xml",
"type": "XML 1.0 document text, ASCII text, with CRLF line terminators"
},
{
"filename": "centosserial.sh",
"type": "Bourne-Again shell script text executable, UTF-8 Unicode text"
},
...
]
"""
import jc.utils
import jc.parsers.universal
class info():
version = '1.1'
description = 'file 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 = ['file']
__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:
[
{
"filename": string,
"type ": 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 = []
warned = False
for line in filter(None, data.splitlines()):
linedata = line.rsplit(': ', maxsplit=1)
try:
filename = linedata[0].strip()
filetype = linedata[1].strip()
raw_output.append(
{
'filename': filename,
'type': filetype
}
)
except IndexError:
if not warned:
jc.utils.warning_message('Filenames with newline characters detected. Some filenames may be truncated.')
warned = True
if raw:
return raw_output
else:
return process(raw_output)

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

@@ -0,0 +1,88 @@
"""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 = []
for line in filter(None, data.splitlines()):
# 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.1'
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().startswith('#'):
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)

190
jc/parsers/group.py Normal file
View File

@@ -0,0 +1,190 @@
"""jc - JSON CLI output utility /etc/group file Parser
Usage:
specify --group as the first argument if the piped input is coming from /etc/group
Compatibility:
'linux', 'darwin', 'aix', 'freebsd'
Examples:
$ cat /etc/group | jc --group -p
[
{
"group_name": "nobody",
"password": "*",
"gid": -2,
"members": []
},
{
"group_name": "nogroup",
"password": "*",
"gid": -1,
"members": []
},
{
"group_name": "wheel",
"password": "*",
"gid": 0,
"members": [
"root"
]
},
{
"group_name": "certusers",
"password": "*",
"gid": 29,
"members": [
"root",
"_jabber",
"_postfix",
"_cyrus",
"_calendar",
"_dovecot"
]
},
...
]
$ cat /etc/group | jc --group -p -r
[
{
"group_name": "nobody",
"password": "*",
"gid": "-2",
"members": [
""
]
},
{
"group_name": "nogroup",
"password": "*",
"gid": "-1",
"members": [
""
]
},
{
"group_name": "wheel",
"password": "*",
"gid": "0",
"members": [
"root"
]
},
{
"group_name": "certusers",
"password": "*",
"gid": "29",
"members": [
"root",
"_jabber",
"_postfix",
"_cyrus",
"_calendar",
"_dovecot"
]
},
...
]
"""
import jc.utils
class info():
version = '1.0'
description = '/etc/group 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']
__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:
[
{
"group_name": string,
"password": string,
"gid": integer,
"members": [
string
]
}
]
"""
for entry in proc_data:
int_list = ['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
if entry['members'] == ['']:
entry['members'] = []
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 entry in cleandata:
if entry.startswith('#'):
continue
output_line = {}
fields = entry.split(':')
output_line['group_name'] = fields[0]
output_line['password'] = fields[1]
output_line['gid'] = fields[2]
output_line['members'] = fields[3].split(',')
raw_output.append(output_line)
if raw:
return raw_output
else:
return process(raw_output)

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

@@ -0,0 +1,152 @@
"""jc - JSON CLI output utility /etc/gshadow file Parser
Usage:
specify --gshadow as the first argument if the piped input is coming from /etc/gshadow
Compatibility:
'linux', 'aix', 'freebsd'
Examples:
$ cat /etc/gshadow | jc --gshadow -p
[
{
"group_name": "root",
"password": "*",
"administrators": [],
"members": []
},
{
"group_name": "adm",
"password": "*",
"administrators": [],
"members": [
"syslog",
"joeuser"
]
},
...
]
$ cat /etc/gshadow | jc --gshadow -p -r
[
{
"group_name": "root",
"password": "*",
"administrators": [
""
],
"members": [
""
]
},
{
"group_name": "adm",
"password": "*",
"administrators": [
""
],
"members": [
"syslog",
"joeuser"
]
},
...
]
"""
import jc.utils
class info():
version = '1.0'
description = '/etc/gshadow 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', '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:
[
{
"group_name": string,
"password": string,
"administrators": [
string
],
"members": [
string
]
}
]
"""
for entry in proc_data:
if entry['administrators'] == ['']:
entry['administrators'] = []
if entry['members'] == ['']:
entry['members'] = []
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 entry in cleandata:
if entry.startswith('#'):
continue
output_line = {}
fields = entry.split(':')
output_line['group_name'] = fields[0]
output_line['password'] = fields[1]
output_line['administrators'] = fields[2].split(',')
output_line['members'] = fields[3].split(',')
raw_output.append(output_line)
if raw:
return raw_output
else:
return process(raw_output)

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

@@ -0,0 +1,126 @@
"""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.utils
class info():
version = '1.2'
description = 'history command parser'
author = 'Kelly Brazil'
author_email = 'kellyjonbrazil@gmail.com'
details = 'Optimizations by https://github.com/philippeitis'
# 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 = {
'line': int(k) if k.isdigit() else None,
'command': 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 = {}
# split lines and clear out any non-ascii chars
linedata = data.encode('ascii', errors='ignore').decode().splitlines()
# Skip any blank lines
for entry in filter(None, linedata):
try:
parsed_line = entry.split(maxsplit=1)
raw_output[parsed_line[0]] = parsed_line[1]
except IndexError:
# need to catch indexerror in case there is weird input from prior commands
pass
if raw:
return raw_output
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.1'
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().startswith('#'):
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 '#' in item:
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,457 @@
"""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
}
]
"""
import re
from collections import namedtuple
from ifconfigparser import IfconfigParser
import jc.utils
def parse(data):
output = []
class info():
version = '1.7'
description = 'ifconfig command parser'
author = 'Kelly Brazil'
author_email = 'kellyjonbrazil@gmail.com'
details = 'Using ifconfig-parser 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
class IfconfigParser(object):
# Author: threeheadedknight@protonmail.com
# Date created: 30.06.2018 17:03
# Python Version: 3.7
attributes = ['name', 'type', 'mac_addr', 'ipv4_addr', 'ipv4_bcast', 'ipv4_mask', 'ipv6_addr', 'ipv6_mask',
'ipv6_scope', 'state', 'mtu', 'metric', 'rx_packets', 'rx_errors', 'rx_dropped', 'rx_overruns',
'rx_frame', 'tx_packets', 'tx_errors', 'tx_dropped', 'tx_overruns', 'tx_carrier', 'tx_collisions',
'rx_bytes', 'tx_bytes']
def __init__(self, console_output):
"""
:param console_output:
"""
if isinstance(console_output, list):
source_data = " ".join(console_output)
else:
source_data = console_output.replace("\n", " ")
self.interfaces = self.parser(source_data=source_data)
def list_interfaces(self):
"""
:return:
"""
return sorted(self.interfaces.keys())
def count_interfaces(self):
"""
:return:
"""
return len(self.interfaces.keys())
def filter_interfaces(self, **kwargs):
"""
:param kwargs:
:return:
"""
for attr in kwargs.keys():
if attr not in IfconfigParser.attributes:
raise ValueError("Attribute [{}] not supported.".format(attr))
filtered_interfaces = []
for name, details in self.interfaces.items():
if all(getattr(details, attr) == kwargs[attr] for attr in kwargs.keys()):
filtered_interfaces.append(name)
return sorted(filtered_interfaces)
def get_interface(self, name):
"""
:param name:
:return:
"""
if name in self.list_interfaces():
return self.interfaces[name]
else:
raise InterfaceNotFound("Interface [{}] not found.".format(name))
def get_interfaces(self):
"""
:return:
"""
return self.interfaces
def is_available(self, name):
"""
:param name:
:return:
"""
return name in self.interfaces
def parser(self, source_data):
"""
:param source_data:
:return:
"""
# Linux syntax
re_linux_interface = re.compile(
r"(?P<name>[a-zA-Z0-9:._-]+)\s+Link encap:(?P<type>\S+\s?\S+)(\s+HWaddr\s+\b"
r"(?P<mac_addr>[0-9A-Fa-f:?]+))?",
re.I)
re_linux_ipv4 = re.compile(
r"inet addr:(?P<ipv4_addr>(?:[0-9]{1,3}\.){3}[0-9]{1,3})(\s+Bcast:"
r"(?P<ipv4_bcast>(?:[0-9]{1,3}\.){3}[0-9]{1,3}))?\s+Mask:(?P<ipv4_mask>(?:[0-9]{1,3}\.){3}[0-9]{1,3})",
re.I)
re_linux_ipv6 = re.compile(
r"inet6 addr:\s+(?P<ipv6_addr>\S+)/(?P<ipv6_mask>[0-9]+)\s+Scope:(?P<ipv6_scope>Link|Host)",
re.I)
re_linux_state = re.compile(
r"\W+(?P<state>(?:\w+\s)+)(?:\s+)?MTU:(?P<mtu>[0-9]+)\s+Metric:(?P<metric>[0-9]+)", re.I)
re_linux_rx = re.compile(
r"RX packets:(?P<rx_packets>[0-9]+)\s+errors:(?P<rx_errors>[0-9]+)\s+dropped:"
r"(?P<rx_dropped>[0-9]+)\s+overruns:(?P<rx_overruns>[0-9]+)\s+frame:(?P<rx_frame>[0-9]+)",
re.I)
re_linux_tx = re.compile(
r"TX packets:(?P<tx_packets>[0-9]+)\s+errors:(?P<tx_errors>[0-9]+)\s+dropped:"
r"(?P<tx_dropped>[0-9]+)\s+overruns:(?P<tx_overruns>[0-9]+)\s+carrier:(?P<tx_carrier>[0-9]+)",
re.I)
re_linux_bytes = re.compile(r"\W+RX bytes:(?P<rx_bytes>\d+)\s+\(.*\)\s+TX bytes:(?P<tx_bytes>\d+)\s+\(.*\)", re.I)
re_linux_tx_stats = re.compile(r"collisions:(?P<tx_collisions>[0-9]+)\s+txqueuelen:[0-9]+", re.I)
re_linux = [re_linux_interface, re_linux_ipv4, re_linux_ipv6, re_linux_state, re_linux_rx, re_linux_tx,
re_linux_bytes, re_linux_tx_stats]
# OpenBSD syntax
re_openbsd_interface = re.compile(
r"(?P<name>[a-zA-Z0-9:._-]+):\s+flags=(?P<flags>[0-9]+)<(?P<state>\S+)?>\s+mtu\s+(?P<mtu>[0-9]+)",
re.I)
re_openbsd_ipv4 = re.compile(
r"inet (?P<ipv4_addr>(?:[0-9]{1,3}\.){3}[0-9]{1,3})\s+netmask\s+"
r"(?P<ipv4_mask>(?:[0-9]{1,3}\.){3}[0-9]{1,3})(\s+broadcast\s+"
r"(?P<ipv4_bcast>(?:[0-9]{1,3}\.){3}[0-9]{1,3}))?",
re.I)
re_openbsd_ipv6 = re.compile(
r"inet6\s+(?P<ipv6_addr>\S+)\s+prefixlen\s+(?P<ipv6_mask>[0-9]+)\s+scopeid\s+(?P<ipv6_scope>\w+x\w+)<"
r"(?:link|host)>",
re.I)
re_openbsd_details = re.compile(
r"\S+\s+(?:(?P<mac_addr>[0-9A-Fa-f:?]+)\s+)?txqueuelen\s+[0-9]+\s+\((?P<type>\S+\s?\S+)\)", re.I)
re_openbsd_rx = re.compile(r"RX packets (?P<rx_packets>[0-9]+)\s+bytes\s+(?P<rx_bytes>\d+)\s+.*", re.I)
re_openbsd_rx_stats = re.compile(
r"RX errors (?P<rx_errors>[0-9]+)\s+dropped\s+(?P<rx_dropped>[0-9]+)\s+overruns\s+"
r"(?P<rx_overruns>[0-9]+)\s+frame\s+(?P<rx_frame>[0-9]+)",
re.I)
re_openbsd_tx = re.compile(r"TX packets (?P<tx_packets>[0-9]+)\s+bytes\s+(?P<tx_bytes>\d+)\s+.*", re.I)
re_openbsd_tx_stats = re.compile(
r"TX errors (?P<tx_errors>[0-9]+)\s+dropped\s+(?P<tx_dropped>[0-9]+)\s+overruns\s+"
r"(?P<tx_overruns>[0-9]+)\s+carrier\s+(?P<tx_carrier>[0-9]+)\s+collisions\s+(?P<tx_collisions>[0-9]+)",
re.I)
re_openbsd = [re_openbsd_interface, re_openbsd_ipv4, re_openbsd_ipv6, re_openbsd_details, re_openbsd_rx,
re_openbsd_rx_stats, re_openbsd_tx, re_openbsd_tx_stats]
# FreeBSD syntax
re_freebsd_interface = re.compile(
r"(?P<name>[a-zA-Z0-9:._-]+):\s+flags=(?P<flags>[0-9]+)<(?P<state>\S+)>\s+metric\s+"
r"(?P<metric>[0-9]+)\s+mtu\s+(?P<mtu>[0-9]+)",
re.I)
re_freebsd_ipv4 = re.compile(
r"inet (?P<ipv4_addr>(?:[0-9]{1,3}\.){3}[0-9]{1,3})\s+netmask\s+(?P<ipv4_mask>0x\S+)(\s+broadcast\s+"
r"(?P<ipv4_bcast>(?:[0-9]{1,3}\.){3}[0-9]{1,3}))?",
re.I)
re_freebsd_ipv6 = re.compile(r"\s?inet6\s(?P<ipv6_addr>.*)(?:\%\w+\d+)\sprefixlen\s(?P<ipv6_mask>\d+)(?:\s\w+)?\sscopeid\s(?P<ipv6_scope>\w+x\w+)", re.I)
re_freebsd_details = re.compile(r"ether\s+(?P<mac_addr>[0-9A-Fa-f:?]+)", re.I)
re_freebsd = [re_freebsd_interface, re_freebsd_ipv4, re_freebsd_ipv6, re_freebsd_details]
available_interfaces = dict()
for pattern in [re_linux_interface, re_openbsd_interface, re_freebsd_interface]:
network_interfaces = re.finditer(pattern, source_data)
positions = []
while True:
try:
pos = next(network_interfaces)
positions.append(max(pos.start() - 1, 0))
except StopIteration:
break
if positions:
positions.append(len(source_data))
break
if not positions:
return available_interfaces
for l, r in zip(positions, positions[1:]):
chunk = source_data[l:r]
_interface = dict()
for pattern in re_linux + re_openbsd + re_freebsd:
match = re.search(pattern, chunk.replace('\t', '\n'))
if match:
details = match.groupdict()
for k, v in details.items():
if isinstance(v, str): details[k] = v.strip()
_interface.update(details)
if _interface is not None:
available_interfaces[_interface['name']] = self.update_interface_details(_interface)
return available_interfaces
@staticmethod
def update_interface_details(interface):
for attr in IfconfigParser.attributes:
if attr not in interface:
interface[attr] = None
return namedtuple('Interface', interface.keys())(**interface)
class InterfaceNotFound(Exception):
"""
"""
pass
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'].startswith('0x'):
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()
@@ -24,6 +460,9 @@ def parse(data):
for iface in interfaces:
d = interfaces[iface]._asdict()
dct = dict(d)
output.append(dct)
raw_output.append(dct)
return output
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.2'
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.startswith('Chain'):
raw_output.append(chain)
chain = {}
headers = []
parsed_line = line.split()
chain['chain'] = parsed_line[1]
chain['rules'] = []
continue
elif line.startswith('target') or line.find('pkts') == 1 or line.startswith('num'):
headers = []
headers = [h for h in ' '.join(line.lower().strip().split()).split() if h]
headers.append("options")
continue
else:
rule = line.split(maxsplit=len(headers) - 1)
temp_rule = dict(zip(headers, rule))
if temp_rule:
chain['rules'].append(temp_rule)
raw_output = list(filter(None, raw_output))
if raw:
return raw_output
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.1'
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 '+' in parsed_line[0]:
job_history = 'current'
parsed_line[0] = parsed_line[0].rstrip('+')
if '-' in parsed_line[0]:
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)

181
jc/parsers/last.py Normal file
View File

@@ -0,0 +1,181 @@
"""jc - JSON CLI output utility last Parser
Usage:
specify --last as the first argument if the piped input is coming from last or lastb
Compatibility:
'linux', 'darwin', 'aix', 'freebsd'
Examples:
$ last | jc --last -p
[
{
"user": "kbrazil",
"tty": "ttys002",
"hostname": null,
"login": "Thu Feb 27 14:31",
"logout": "still logged in"
},
{
"user": "kbrazil",
"tty": "ttys003",
"hostname": null,
"login": "Thu Feb 27 10:38",
"logout": "10:38",
"duration": "00:00"
},
{
"user": "kbrazil",
"tty": "ttys003",
"hostname": null,
"login": "Thu Feb 27 10:18",
"logout": "10:18",
"duration": "00:00"
},
...
]
$ last | jc --last -p -r
[
{
"user": "kbrazil",
"tty": "ttys002",
"hostname": "-",
"login": "Thu Feb 27 14:31",
"logout": "still_logged_in"
},
{
"user": "kbrazil",
"tty": "ttys003",
"hostname": "-",
"login": "Thu Feb 27 10:38",
"logout": "10:38",
"duration": "00:00"
},
{
"user": "kbrazil",
"tty": "ttys003",
"hostname": "-",
"login": "Thu Feb 27 10:18",
"logout": "10:18",
"duration": "00:00"
},
...
]
"""
import re
import jc.utils
class info():
version = '1.0'
description = 'last and lastb 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 = ['last', 'lastb']
__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,
"tty": string,
"hostname": string,
"login": string,
"logout": string,
"duration": string
}
]
"""
for entry in proc_data:
if 'tty' in entry and entry['tty'] == '~':
entry['tty'] = None
if 'tty' in entry and entry['tty'] == 'system_boot':
entry['tty'] = 'system boot'
if 'hostname' in entry and entry['hostname'] == '-':
entry['hostname'] = None
if 'logout' in entry and entry['logout'] == 'still_logged_in':
entry['logout'] = 'still logged in'
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 entry in cleandata:
output_line = {}
if entry.startswith('wtmp begins ') or entry.startswith('btmp begins '):
continue
entry = entry.replace('system boot', 'system_boot')
entry = entry.replace(' still logged in', '- still_logged_in')
linedata = entry.split()
if re.match(r'[MTWFS][ouerha][nedritnu] [JFMASOND][aepuco][nbrynlgptvc]', ' '.join(linedata[2:4])):
linedata.insert(2, '-')
output_line['user'] = linedata[0]
output_line['tty'] = linedata[1]
output_line['hostname'] = linedata[2]
output_line['login'] = ' '.join(linedata[3:7])
if len(linedata) > 8:
output_line['logout'] = linedata[8]
if len(linedata) > 9:
output_line['duration'] = linedata[9].replace('(', '').replace(')', '')
raw_output.append(output_line)
if raw:
return raw_output
else:
return process(raw_output)

View File

@@ -1,114 +1,281 @@
"""jc - JSON CLI output utility ls Parser
Note: The -l or -b option of ls should be used to correctly parse filenames that include newline characters.
Since ls does not encode newlines in filenames when outputting to a pipe it will cause jc to see
multiple files instead of a single file if -l or -b is not used.
Usage:
specify --ls as the first argument if the piped input is coming from ls
ls options supported:
- None
- l
- a
-lbaR
--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 = []
class info():
version = '1.3'
description = 'ls 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 = ['ls']
__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:
[
{
"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 = []
warned = False
parent = ''
next_is_parent = False
new_section = False
linedata = data.splitlines()
# Delete first line if it starts with 'total'
# Delete first line if it starts with 'total 1234'
if linedata:
if linedata[0].find('total') == 0:
if re.match(r'total [0-9]+', linedata[0]):
linedata.pop(0)
# Clear any blank lines
cleandata = list(filter(None, linedata))
# Look for parent line if glob or -R is used
if not re.match(r'[-dclpsbDCMnP?]([-r][-w][-xsS]){2}([-r][-w][-xtT])[+]?', linedata[0]) \
and linedata[0].endswith(':'):
parent = linedata.pop(0)[:-1]
# Pop following total line
linedata.pop(0)
if cleandata:
if linedata:
# 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:
if re.match(r'[-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(r'[-dclpsbDCMnP?]([-r][-w][-xsS]){2}([-r][-w][-xtT])[+]?', entry) \
and entry.endswith(':'):
parent = entry[:-1]
new_section = True
# fixup to remove trailing \n in previous entry
raw_output[-1]['filename'] = raw_output[-1]['filename'][:-1]
continue
if re.match(r'total [0-9]+', entry):
new_section = False
continue
# fix for OSX - doesn't print 'total xx' line if empty directory
if new_section and entry == '':
new_section = False
continue
# fixup for filenames with newlines
if not new_section \
and not re.match(r'[-dclpsbDCMnP?]([-r][-w][-xsS]){2}([-r][-w][-xtT])[+]?', entry):
raw_output[-1]['filename'] = raw_output[-1]['filename'] + '\n' + entry
continue
# split filenames and links
filename_field = parsed_line[8].split(' -> ')
if len(parsed_line) == 9:
filename_field = parsed_line[8].split(' -> ')
else:
# in case of filenames starting with a newline character
filename_field = ['']
# create list of dictionaries
output_line['filename'] = filename_field[0]
@@ -116,17 +283,41 @@ def parse(data):
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'] = int(parsed_line[1])
output_line['links'] = parsed_line[1]
output_line['owner'] = parsed_line[2]
output_line['group'] = parsed_line[3]
output_line['bytes'] = int(parsed_line[4])
output_line['size'] = parsed_line[4]
output_line['date'] = ' '.join(parsed_line[5:8])
output.append(output_line)
raw_output.append(output_line)
else:
for entry in cleandata:
for entry in linedata:
output_line = {}
output_line['filename'] = entry
output.append(output_line)
return output
if entry == '':
next_is_parent = True
continue
if next_is_parent and entry.endswith(':'):
parent = entry[:-1]
next_is_parent = False
continue
if not quiet and next_is_parent and not entry.endswith(':') and not warned:
jc.utils.warning_message('Newline characters detected. Filenames probably corrupted. Use ls -l or -b instead.')
warned = True
output_line['filename'] = entry
if parent:
output_line['parent'] = parent
raw_output.append(output_line)
if raw:
return raw_output
else:
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)

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

@@ -0,0 +1,186 @@
"""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.1'
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)
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.2'
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 ' type ' not in cleandata[0]:
raw_output = osx_parse(cleandata)
else:
raw_output = linux_parse(cleandata)
if raw:
return raw_output
else:
return process(raw_output)

View File

@@ -1,197 +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
[
{
"transport_protocol": "tcp",
"network_protocol": "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
},
{
"transport_protocol": "tcp",
"network_protocol": "ipv4",
"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 -lpn | jc --netstat -p
[
{
"transport_protocol": "tcp",
"network_protocol": "ipv4",
"local_address": "127.0.0.1",
"local_port": "42351",
"foreign_address": "0.0.0.0",
"foreign_port": "*",
"state": "LISTEN",
"pid": 1112,
"program_name": "containerd",
"receive_q": 0,
"send_q": 0
},
{
"transport_protocol": "tcp",
"network_protocol": "ipv4",
"local_address": "127.0.0.53",
"local_port": "53",
"foreign_address": "0.0.0.0",
"foreign_port": "*",
"state": "LISTEN",
"pid": 885,
"program_name": "systemd-resolve",
"receive_q": 0,
"send_q": 0
},
{
"transport_protocol": "tcp",
"network_protocol": "ipv4",
"local_address": "0.0.0.0",
"local_port": "22",
"foreign_address": "0.0.0.0",
"foreign_port": "*",
"state": "LISTEN",
"pid": 1127,
"program_name": "sshd",
"receive_q": 0,
"send_q": 0
},
{
"transport_protocol": "tcp",
"network_protocol": "ipv6",
"local_address": "::",
"local_port": "22",
"foreign_address": "::",
"foreign_port": "*",
"state": "LISTEN",
"pid": 1127,
"program_name": "sshd",
"receive_q": 0,
"send_q": 0
},
{
"transport_protocol": "udp",
"network_protocol": "ipv4",
"local_address": "127.0.0.53",
"local_port": "53",
"foreign_address": "0.0.0.0",
"foreign_port": "*",
"pid": 885,
"program_name": "systemd-resolve",
"receive_q": 0,
"send_q": 0
},
{
"transport_protocol": "udp",
"network_protocol": "ipv4",
"local_address": "192.168.71.131",
"local_port": "68",
"foreign_address": "0.0.0.0",
"foreign_port": "*",
"pid": 867,
"program_name": "systemd-network",
"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
output = []
import jc.utils
def parse_line(entry):
output_line = {}
class info():
version = '1.3'
description = 'netstat command parser'
author = 'Kelly Brazil'
author_email = 'kellyjonbrazil@gmail.com'
if entry.find('tcp') == 0:
output_line['transport_protocol'] = 'tcp'
# compatible options: linux, darwin, cygwin, win32, aix, freebsd
compatible = ['linux']
magic_commands = ['netstat']
if entry.find('p6') == 2:
output_line['network_protocol'] = 'ipv6'
else:
output_line['network_protocol'] = 'ipv4'
__version__ = info.version
elif entry.find('udp') == 0:
output_line['transport_protocol'] = 'udp'
if entry.find('p6') == 2:
output_line['network_protocol'] = 'ipv6'
def process(proc_data):
"""
Final processing to conform to the schema.
else:
output_line['network_protocol'] = 'ipv4'
else:
return
Parameters:
parsed_line = entry.split()
proc_data: (dictionary) raw structured data to process
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]
Returns:
if len(parsed_line) > 5:
List of dictionaries. Structured data with the following schema:
if parsed_line[5][0] not in string.digits and parsed_line[5][0] != '-':
output_line['state'] = parsed_line[5]
[
{
"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 len(parsed_line) > 6 and parsed_line[6][0] in string.digits:
output_line['pid'] = int(parsed_line[6].split('/')[0])
output_line['program_name'] = parsed_line[6].split('/')[1]
else:
if parsed_line[5][0] in string.digits:
output_line['pid'] = int(parsed_line[5].split('/')[0])
output_line['program_name'] = parsed_line[5].split('/')[1]
if 'local_port' in entry:
try:
entry['local_port_num'] = int(entry['local_port'])
except (ValueError):
pass
output_line['receive_q'] = int(parsed_line[1])
output_line['send_q'] = int(parsed_line[2])
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 'tcp' in entry['proto']:
entry['transport_protocol'] = 'tcp'
elif 'udp' in entry['proto']:
entry['transport_protocol'] = 'udp'
else:
entry['transport_protocol'] = None
if '6' in entry['proto']:
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:
if line.startswith('Active Internet'):
network_list = []
network = True
socket = False
continue
if line.find('Active Internet connections (only servers)') == 0:
if line.startswith('Active UNIX'):
socket_list = []
network = False
socket = True
continue
if line.find('Proto') == 0:
if line.startswith('Proto'):
header_text = normalize_headers(line)
headers = header_text.split()
continue
if line.find('Active UNIX') == 0:
break
if network:
network_list.append(parse_network(headers, line))
continue
output.append(parse_line(line))
if socket:
socket_list.append(parse_socket(header_text, headers, line))
continue
clean_output = list(filter(None, output))
return clean_output
for item in [network_list, socket_list]:
for entry in item:
raw_output.append(entry)
raw_output = parse_post(raw_output)
if raw:
return raw_output
else:
return process(raw_output)

297
jc/parsers/ntpq.py Normal file
View File

@@ -0,0 +1,297 @@
"""jc - JSON CLI output utility ntpq Parser
Usage:
specify --ntpq as the first argument if the piped input is coming from ntpq -p
Compatibility:
'linux'
Examples:
$ ntpq -p | jc --ntpq -p
[
{
"remote": "44.190.6.254",
"refid": "127.67.113.92",
"st": 2,
"t": "u",
"when": 1,
"poll": 64,
"reach": 1,
"delay": 23.399,
"offset": -2.805,
"jitter": 2.131,
"state": null
},
{
"remote": "ntp.wdc1.us.lea",
"refid": "130.133.1.10",
"st": 2,
"t": "u",
"when": null,
"poll": 64,
"reach": 1,
"delay": 93.053,
"offset": -0.807,
"jitter": 2.839,
"state": null
},
{
"remote": "clock.team-cymr",
"refid": "204.9.54.119",
"st": 2,
"t": "u",
"when": null,
"poll": 64,
"reach": 1,
"delay": 70.337,
"offset": -2.909,
"jitter": 2.6,
"state": null
},
{
"remote": "mirror1.sjc02.s",
"refid": "216.218.254.202",
"st": 2,
"t": "u",
"when": 2,
"poll": 64,
"reach": 1,
"delay": 29.325,
"offset": 1.044,
"jitter": 4.069,
"state": null,
}
]
$ ntpq -pn| jc --ntpq -p
[
{
"remote": "44.190.6.254",
"refid": "127.67.113.92",
"st": 2,
"t": "u",
"when": 66,
"poll": 64,
"reach": 377,
"delay": 22.69,
"offset": -0.392,
"jitter": 2.085,
"state": "+"
},
{
"remote": "108.59.2.24",
"refid": "130.133.1.10",
"st": 2,
"t": "u",
"when": 63,
"poll": 64,
"reach": 377,
"delay": 90.805,
"offset": 2.84,
"jitter": 1.908,
"state": "-"
},
{
"remote": "38.229.71.1",
"refid": "204.9.54.119",
"st": 2,
"t": "u",
"when": 64,
"poll": 64,
"reach": 377,
"delay": 68.699,
"offset": -0.61,
"jitter": 2.576,
"state": "+"
},
{
"remote": "72.5.72.15",
"refid": "216.218.254.202",
"st": 2,
"t": "u",
"when": 63,
"poll": 64,
"reach": 377,
"delay": 22.654,
"offset": 0.231,
"jitter": 1.964,
"state": "*"
}
]
$ ntpq -pn| jc --ntpq -p -r
[
{
"s": "+",
"remote": "44.190.6.254",
"refid": "127.67.113.92",
"st": "2",
"t": "u",
"when": "66",
"poll": "64",
"reach": "377",
"delay": "22.690",
"offset": "-0.392",
"jitter": "2.085"
},
{
"s": "-",
"remote": "108.59.2.24",
"refid": "130.133.1.10",
"st": "2",
"t": "u",
"when": "63",
"poll": "64",
"reach": "377",
"delay": "90.805",
"offset": "2.840",
"jitter": "1.908"
},
{
"s": "+",
"remote": "38.229.71.1",
"refid": "204.9.54.119",
"st": "2",
"t": "u",
"when": "64",
"poll": "64",
"reach": "377",
"delay": "68.699",
"offset": "-0.610",
"jitter": "2.576"
},
{
"s": "*",
"remote": "72.5.72.15",
"refid": "216.218.254.202",
"st": "2",
"t": "u",
"when": "63",
"poll": "64",
"reach": "377",
"delay": "22.654",
"offset": "0.231",
"jitter": "1.964"
}
]
"""
import jc.utils
import jc.parsers.universal
class info():
version = '1.0'
description = 'ntpq -p command parser'
author = 'Kelly Brazil'
author_email = 'kellyjonbrazil@gmail.com'
# compatible options: linux, darwin, cygwin, win32, aix, freebsd
compatible = ['linux']
magic_commands = ['ntpq']
__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:
[
{
"state": string, # space/~ converted to null
"remote": string,
"refid": string,
"st": integer,
"t": string,
"when": integer, # - converted to null
"poll": integer,
"reach": integer,
"delay": float,
"offset": float,
"jitter": float
},
]
"""
for entry in proc_data:
if entry['s'] == '~':
entry['s'] = None
entry['state'] = entry.pop('s')
int_list = ['st', 'when', 'poll', 'reach']
for key in int_list:
if key in entry:
try:
entry[key] = int(entry[key])
except (ValueError):
entry[key] = None
float_list = ['delay', 'offset', 'jitter']
for key in float_list:
if key in entry:
try:
entry[key] = float(entry[key])
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()
cleandata[0] = 's ' + cleandata[0]
cleandata[0] = cleandata[0].lower()
# delete header delimiter
del cleandata[1]
# separate first character with a space for easier parsing
for i, line in list(enumerate(cleandata[1:])):
if line[0] == ' ':
# fixup for no-state
cleandata[i + 1] = '~ ' + line[1:]
else:
# fixup - realign columns since we added the 's' column
cleandata[i + 1] = line[:1] + ' ' + line[1:]
# fixup for occaisional ip/hostname fields with a space
cleandata[i + 1] = cleandata[i + 1].replace(' (', '_(')
raw_output = jc.parsers.universal.simple_table_parse(cleandata)
if raw:
return raw_output
else:
return process(raw_output)

175
jc/parsers/passwd.py Normal file
View File

@@ -0,0 +1,175 @@
"""jc - JSON CLI output utility /etc/passwd file Parser
Usage:
specify --passwd as the first argument if the piped input is coming from /etc/passwd
Compatibility:
'linux', 'darwin', 'aix', 'freebsd'
Examples:
$ cat /etc/passwd | jc --passwd -p
[
{
"username": "nobody",
"password": "*",
"uid": -2,
"gid": -2,
"comment": "Unprivileged User",
"home": "/var/empty",
"shell": "/usr/bin/false"
},
{
"username": "root",
"password": "*",
"uid": 0,
"gid": 0,
"comment": "System Administrator",
"home": "/var/root",
"shell": "/bin/sh"
},
{
"username": "daemon",
"password": "*",
"uid": 1,
"gid": 1,
"comment": "System Services",
"home": "/var/root",
"shell": "/usr/bin/false"
},
...
]
$ cat /etc/passwd | jc --passwd -p -r
[
{
"username": "nobody",
"password": "*",
"uid": "-2",
"gid": "-2",
"comment": "Unprivileged User",
"home": "/var/empty",
"shell": "/usr/bin/false"
},
{
"username": "root",
"password": "*",
"uid": "0",
"gid": "0",
"comment": "System Administrator",
"home": "/var/root",
"shell": "/bin/sh"
},
{
"username": "daemon",
"password": "*",
"uid": "1",
"gid": "1",
"comment": "System Services",
"home": "/var/root",
"shell": "/usr/bin/false"
},
...
]
"""
import jc.utils
class info():
version = '1.0'
description = '/etc/passwd 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']
__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:
[
{
"username": string,
"password": string,
"uid": integer,
"gid": integer,
"comment": string,
"home": string,
"shell": string
}
]
"""
for entry in proc_data:
int_list = ['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
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 entry in cleandata:
if entry.startswith('#'):
continue
output_line = {}
fields = entry.split(':')
output_line['username'] = fields[0]
output_line['password'] = fields[1]
output_line['uid'] = fields[2]
output_line['gid'] = fields[3]
output_line['comment'] = fields[4]
output_line['home'] = fields[5]
output_line['shell'] = fields[6]
raw_output.append(output_line)
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.1'
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 ' (' in cleandata[0]:
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 '---' in line:
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)

View File

@@ -1,67 +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
Example:
Compatibility:
$ ps -ef | jc --ps -p
[
{
"UID": "root",
"PID": "1",
"PPID": "0",
"C": "0",
"STIME": "13:58",
"TTY": "?",
"TIME": "00:00:05",
"CMD": "/lib/systemd/systemd --system --deserialize 35"
},
{
"UID": "root",
"PID": "2",
"PPID": "0",
"C": "0",
"STIME": "13:58",
"TTY": "?",
"TIME": "00:00:00",
"CMD": "[kthreadd]"
},
{
"UID": "root",
"PID": "4",
"PPID": "2",
"C": "0",
"STIME": "13:58",
"TTY": "?",
"TIME": "00:00:00",
"CMD": "[kworker/0:0H]"
},
{
"UID": "root",
"PID": "6",
"PPID": "2",
"C": "0",
"STIME": "13:58",
"TTY": "?",
"TIME": "00:00:00",
"CMD": "[mm_percpu_wq]"
},
...
]
'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
def parse(data):
class info():
version = '1.1'
description = 'ps command parser'
author = 'Kelly Brazil'
author_email = 'kellyjonbrazil@gmail.com'
# code adapted from Conor Heine at:
# https://gist.github.com/cahna/43a1a3ff4d075bcd71f9d7120037a501
# 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()
headers = [h for h in ' '.join(cleandata[0].strip().split()).split() if h]
raw_data = map(lambda s: s.strip().split(None, len(headers) - 1), cleandata[1:])
return [dict(zip(headers, r)) for r in raw_data]
cleandata[0] = cleandata[0].lower()
raw_output = jc.parsers.universal.simple_table_parse(cleandata)
if raw:
return raw_output
else:
return process(raw_output)

View File

@@ -1,63 +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:
Example:
'linux'
$ route -n | jc --route -p
[
{
"Destination": "0.0.0.0",
"Gateway": "192.168.71.2",
"Genmask": "0.0.0.0",
"Flags": "UG",
"Metric": "100",
"Ref": "0",
"Use": "0",
"Iface": "ens33"
},
{
"Destination": "172.17.0.0",
"Gateway": "0.0.0.0",
"Genmask": "255.255.0.0",
"Flags": "U",
"Metric": "0",
"Ref": "0",
"Use": "0",
"Iface": "docker0"
},
{
"Destination": "192.168.71.0",
"Gateway": "0.0.0.0",
"Genmask": "255.255.255.0",
"Flags": "U",
"Metric": "0",
"Ref": "0",
"Use": "0",
"Iface": "ens33"
},
{
"Destination": "192.168.71.2",
"Gateway": "0.0.0.0",
"Genmask": "255.255.255.255",
"Flags": "UH",
"Metric": "100",
"Ref": "0",
"Use": "0",
"Iface": "ens33"
}
]
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
def parse(data):
class info():
version = '1.0'
description = 'route command parser'
author = 'Kelly Brazil'
author_email = 'kellyjonbrazil@gmail.com'
# code adapted from Conor Heine at:
# https://gist.github.com/cahna/43a1a3ff4d075bcd71f9d7120037a501
# 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:]
headers = [h for h in ' '.join(cleandata[0].strip().split()).split() if h]
raw_data = map(lambda s: s.strip().split(None, len(headers) - 1), cleandata[1:])
return [dict(zip(headers, r)) for r in raw_data]
cleandata[0] = cleandata[0].lower()
raw_output = jc.parsers.universal.simple_table_parse(cleandata)
if raw:
return raw_output
else:
return process(raw_output)

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