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

Compare commits

..

126 Commits

Author SHA1 Message Date
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
196 changed files with 65146 additions and 190 deletions

1
MANIFEST.in Normal file
View File

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

552
README.md
View File

@@ -1,10 +1,9 @@
# JC
JSON CLI output utility
`jc` is used to JSONify the output of many standard linux cli tools and file types for easier parsing in scripts. See the **Parsers** section for supported commands.
`jc` is used to JSONify the output of many standard linux cli tools and file types for easier parsing in scripts. See the [**Parsers**](#parsers) section for supported commands and file types.
This allows further command line processing of output with tools like `jq` simply by piping commands:
```
$ ls -l /usr/bin | jc --ls | jq '.[] | select(.size > 50000000)'
{
@@ -17,9 +16,20 @@ $ ls -l /usr/bin | jc --ls | jq '.[] | select(.size > 50000000)'
"date": "Aug 14 19:41"
}
```
For more information on the motivations for this project, please see my blog post at https://blog.kellybrazil.com/2019/11/26/bringing-the-unix-philosophy-to-the-21st-century/.
The `jc` parsers can also be used as python modules. In this case the output will be a python dictionary instead of JSON:
or using the alternative "magic" syntax:
```
$ jc ls -l /usr/bin | jq '.[] | select(.size > 50000000)'
{
"filename": "docker",
"flags": "-rwxr-xr-x",
"links": 1,
"owner": "root",
"group": "root",
"size": 68677120,
"date": "Aug 14 19:41"
}
```
The `jc` parsers can also be used as python modules. In this case the output will be a python dictionary, or list of dictionaries, instead of JSON:
```
>>> import jc.parsers.ls
>>>
@@ -49,7 +59,11 @@ Two representations of the data are possible. The default representation uses a
To access the raw, pre-processed JSON, use the `-r` cli option or the `raw=True` function parameter in `parse()`.
Schemas for each parser can be found in the `docs/parsers` folder.
Schemas for each parser can be found in the [`docs/parsers`](https://github.com/kellyjonbrazil/jc/tree/master/docs/parsers) folder.
Release notes can be found [here](https://blog.kellybrazil.com/category/jc-news/).
For more information on the motivations for this project, please see my [blog post](https://blog.kellybrazil.com/2019/11/26/bringing-the-unix-philosophy-to-the-21st-century/).
## Installation
```
@@ -57,48 +71,60 @@ $ pip3 install --upgrade jc
```
## Usage
`jc` accepts piped input from `STDIN` and outputs a JSON representation of the previous command's output to `STDOUT`.
```
jc PARSER [OPTIONS]
COMMAND | jc PARSER [OPTIONS]
```
`jc` accepts piped input from `STDIN` and outputs a JSON representation of the previous command's output to `STDOUT`. The JSON output can be compact or pretty formatted.
Alternatively, the "magic" syntax can be used by prepending `jc` to the command to be converted. Options can be passed to `jc` immediately before the command is given. (Note: command aliases are not supported)
```
jc [OPTIONS] COMMAND
```
The JSON output can be compact (default) or pretty formatted with the `-p` option.
### Parsers
- `--arp` enables the `arp` parser
- `--crontab` enables the `crontab` file parser
- `--arp` enables the `arp` command parser
- `--blkid` enables the `blkid` command parser
- `--crontab` enables the `crontab` command and file parser
- `--crontab-u` enables the `crontab` file parser with user support
- `--df` enables the `df` parser
- `--dig` enables the `dig` parser
- `--du` enables the `du` parser
- `--env` enables the `env` parser
- `--free` enables the `free` parser
- `--csv` enables the CSV file parser
- `--df` enables the `df` command parser
- `--dig` enables the `dig` command parser
- `--du` enables the `du` command parser
- `--env` enables the `env` command parser
- `--free` enables the `free` command parser
- `--fstab` enables the `/etc/fstab` file parser
- `--history` enables the `history` parser
- `--group` enables the `/etc/group` file parser
- `--gshadow` enables the `/etc/gshadow` file parser
- `--history` enables the `history` command parser
- `--hosts` enables the `/etc/hosts` file parser
- `--id` enables the `id` parser
- `--ifconfig` enables the `ifconfig` parser
- `--id` enables the `id` command parser
- `--ifconfig` enables the `ifconfig` command parser
- `--ini` enables the `INI` file parser
- `--iptables` enables the `iptables` parser
- `--jobs` enables the `jobs` parser
- `--ls` enables the `ls` parser
- `--lsblk` enables the `lsblk` parser
- `--lsmod` enables the `lsmod` parser
- `--lsof` enables the `lsof` parser
- `--mount` enables the `mount` parser
- `--netstat` enables the `netstat` parser
- `--pip-list` enables the `pip list` parser
- `--pip-show` enables the `pip show` parser
- `--ps` enables the `ps` parser
- `--route` enables the `route` parser
- `--ss` enables the `ss` parser
- `--stat` enables the `stat` parser
- `--systemctl` enables the `systemctl` parser
- `--systemctl-lj` enables the `systemctl list-jobs` parser
- `--systemctl-ls` enables the `systemctl list-sockets` parser
- `--systemctl-luf` enables the `systemctl list-unit-files` parser
- `--uname` enables the `uname -a` parser
- `--uptime` enables the `uptime` parser
- `--w` enables the `w` parser
- `--iptables` enables the `iptables` command parser
- `--jobs` enables the `jobs` command parser
- `--last` enables the `last` and `lastb` command parser
- `--ls` enables the `ls` command parser
- `--lsblk` enables the `lsblk` command parser
- `--lsmod` enables the `lsmod` command parser
- `--lsof` enables the `lsof` command parser
- `--mount` enables the `mount` command parser
- `--netstat` enables the `netstat` command parser
- `--passwd` enables the `/etc/passwd` file parser
- `--pip-list` enables the `pip list` command parser
- `--pip-show` enables the `pip show` command parser
- `--ps` enables the `ps` command parser
- `--route` enables the `route` command parser
- `--shadow` enables the `/etc/shadow` file parser
- `--ss` enables the `ss` command parser
- `--stat` enables the `stat` command parser
- `--systemctl` enables the `systemctl` command parser
- `--systemctl-lj` enables the `systemctl list-jobs` command parser
- `--systemctl-ls` enables the `systemctl list-sockets` command parser
- `--systemctl-luf` enables the `systemctl list-unit-files` command parser
- `--uname` enables the `uname -a` command parser
- `--uptime` enables the `uptime` command parser
- `--w` enables the `w` command parser
- `--who` enables the `who` command parser
- `--xml` enables the `XML` file parser
- `--yaml` enables the `YAML` file parser
@@ -109,10 +135,36 @@ jc PARSER [OPTIONS]
- `-q` quiet mode. Suppresses warning messages
- `-r` raw output. Provides a more literal JSON output with all values as text and no additional sematic processing
## Contributions
Feel free to add/improve code or parsers! You can use the [`jc/parsers/foo.py`](https://github.com/kellyjonbrazil/jc/blob/master/jc/parsers/foo.py) parser as a template and submit your parser with a pull request.
## Compatibility
Some parsers like `ls`, `ps`, `dig`, etc. will work on any platform. Other parsers that are platform-specific will generate a warning message if they are used on an unsupported platform. To see all parser information, including compatibility, run `jc -ap`.
You may still use a parser on an unsupported platform - for example, you may want to parse a file with linux `lsof` output on an OSX laptop. In that case you can suppress the warning message with the `-q` cli option or the `quiet=True` function parameter in `parse()`:
```
$ cat lsof.out | jc --lsof -q
```
Tested on:
- Centos 7.7
- Ubuntu 18.4
- OSX 10.11.6
- OSX 10.14.6
## Acknowledgments
- `ifconfig-parser` module from https://github.com/KnightWhoSayNi/ifconfig-parser
- `xmltodict` module from https://github.com/martinblech/xmltodict by Martín Blech
- `ruamel.yaml` library from https://pypi.org/project/ruamel.yaml by Anthon van der Neut
- Parsing code from Conor Heine at https://gist.github.com/cahna/43a1a3ff4d075bcd71f9d7120037a501 adapted for some parsers
- Excellent constructive feedback from Ilya Sher (https://github.com/ilyash-b)
## Examples
### arp
```
$ arp | jc --arp -p
$ arp | jc --arp -p # or: jc -p arp
[
{
"address": "gateway",
@@ -138,7 +190,7 @@ $ arp | jc --arp -p
]
```
```
$ arp -a | jc --arp -p
$ arp -a | jc --arp -p # or: jc -p arp -a
[
{
"name": null,
@@ -163,9 +215,56 @@ $ arp -a | jc --arp -p
}
]
```
### blkid
```
$ blkid | jc --blkid -p # or: jc -p blkid
[
{
"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 # or: sudo jc -p blkid -o udev -ip /dev/sda2
[
{
"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"
}
]
```
### crontab
```
$ cat /etc/crontab | jc --crontab -p
$ cat /etc/crontab | jc --crontab -p # or: jc -p crontab -l
{
"variables": [
{
@@ -310,9 +409,56 @@ $ cat /etc/crontab | jc --crontab-u -p
]
}
```
### CSV files
```
$ 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"
},
...
]
```
### df
```
$ df | jc --df -p
$ df | jc --df -p # or: jc -p df
[
{
"filesystem": "devtmpfs",
@@ -335,7 +481,7 @@ $ df | jc --df -p
```
### dig
```
$ dig cnn.com www.cnn.com @205.251.194.64 | jc --dig -p
$ dig cnn.com www.cnn.com @205.251.194.64 | jc --dig -p # or: jc -p dig cnn.com www.cnn.com @205.251.194.64
[
{
"id": 5509,
@@ -455,7 +601,7 @@ $ dig cnn.com www.cnn.com @205.251.194.64 | jc --dig -p
]
```
```
$ dig -x 1.1.1.1 | jc --dig -p
$ dig -x 1.1.1.1 | jc --dig -p # or: jc -p dig -x 1.1.1.1
[
{
"id": 50324,
@@ -493,7 +639,7 @@ $ dig -x 1.1.1.1 | jc --dig -p
```
### du
```
$ du /usr | jc --du -p
$ du /usr | jc --du -p # or: jc -p du /usr
[
{
"size": 104608,
@@ -524,7 +670,7 @@ $ du /usr | jc --du -p
```
### env
```
$ env | jc --env -p
$ env | jc --env -p # or: jc -p env
[
{
"name": "XDG_SESSION_ID",
@@ -551,7 +697,7 @@ $ env | jc --env -p
```
### free
```
$ free | jc --free -p
$ free | jc --free -p # or: jc -p free
[
{
"type": "Mem",
@@ -600,6 +746,68 @@ $ cat /etc/fstab | jc --fstab -p
}
]
```
### /etc/group file
```
$ 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"
]
},
...
]
```
### /etc/gshadow file
```
$ cat /etc/gshadow | jc --gshadow -p
[
{
"group_name": "root",
"password": "*",
"administrators": [],
"members": []
},
{
"group_name": "adm",
"password": "*",
"administrators": [],
"members": [
"syslog",
"joeuser"
]
},
...
]
```
### history
```
$ history | jc --history -p
@@ -674,7 +882,7 @@ $ cat /etc/hosts | jc --hosts -p
```
### id
```
$ id | jc --id -p
$ id | jc --id -p # or: jc -p id
{
"uid": {
"id": 1000,
@@ -704,7 +912,7 @@ $ id | jc --id -p
```
### ifconfig
```
$ ifconfig | jc --ifconfig -p
$ ifconfig | jc --ifconfig -p # or: jc -p ifconfig
[
{
"name": "ens33",
@@ -809,7 +1017,7 @@ $ cat example.ini | jc --ini -p
```
### iptables
```
$ sudo iptables --line-numbers -v -L -t nat | jc --iptables -p
$ sudo iptables --line-numbers -v -L -t nat | jc --iptables -p # or: sudo jc -p iptables --line-numbers -v -L -t nat
[
{
"chain": "PREROUTING",
@@ -870,7 +1078,7 @@ $ sudo iptables --line-numbers -v -L -t nat | jc --iptables -p
```
### jobs
```
$ jobs -l | jc --jobs -p
$ jobs -l | jc --jobs -p # or: jc -p jobs
[
{
"job_number": 1,
@@ -900,9 +1108,39 @@ $ jobs -l | jc --jobs -p
}
]
```
### last and lastb
```
$ last | jc --last -p # or: jc -p last
[
{
"user": "joeuser",
"tty": "ttys002",
"hostname": null,
"login": "Thu Feb 27 14:31",
"logout": "still logged in"
},
{
"user": "joeuser",
"tty": "ttys003",
"hostname": null,
"login": "Thu Feb 27 10:38",
"logout": "10:38",
"duration": "00:00"
},
{
"user": "joeuser",
"tty": "ttys003",
"hostname": null,
"login": "Thu Feb 27 10:18",
"logout": "10:18",
"duration": "00:00"
},
...
]
```
### ls
```
$ ls -l /usr/bin | jc --ls -p
$ ls -l /usr/bin | jc --ls -p # or: jc -p ls -l /usr/bin
[
{
"filename": "apropos",
@@ -937,7 +1175,7 @@ $ ls -l /usr/bin | jc --ls -p
```
### lsblk
```
$ lsblk | jc --lsblk -p
$ lsblk | jc --lsblk -p # or: jc -p lsblk
[
{
"name": "sda",
@@ -962,7 +1200,7 @@ $ lsblk | jc --lsblk -p
```
### lsmod
```
$ lsmod | jc --lsmod -p
$ lsmod | jc --lsmod -p # or: jc -p lsmod
[
...
{
@@ -1009,7 +1247,7 @@ $ lsmod | jc --lsmod -p
```
### lsof
```
$ sudo lsof | jc --lsof -p
$ sudo lsof | jc --lsof -p # or: sudo jc -p lsof
[
{
"command": "systemd",
@@ -1052,7 +1290,7 @@ $ sudo lsof | jc --lsof -p
```
### mount
```
$ mount | jc --mount -p
$ mount | jc --mount -p # or: jc -p mount
[
{
"filesystem": "sysfs",
@@ -1096,7 +1334,7 @@ $ mount | jc --mount -p
```
### netstat
```
$ sudo netstat -apee | jc --netstat -p
$ sudo netstat -apee | jc --netstat -p # or: sudo jc -p netstat -apee
[
{
"proto": "tcp",
@@ -1246,9 +1484,43 @@ $ sudo netstat -apee | jc --netstat -p
...
]
```
### /etc/passwd file
```
$ 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"
},
...
]
```
### pip list
```
$ pip list | jc --pip-list -p
$ pip list | jc --pip-list -p # or: jc -p pip list # or: jc -p pip3 list
[
{
"package": "ansible",
@@ -1268,7 +1540,7 @@ $ pip list | jc --pip-list -p
```
### pip show
```
$ pip show wrapt wheel | jc --pip-show -p
$ pip show wrapt wheel | jc --pip-show -p # or: jc -p pip show wrapt wheel # or: jc -p pip3 show wrapt wheel
[
{
"name": "wrapt",
@@ -1298,7 +1570,7 @@ $ pip show wrapt wheel | jc --pip-show -p
```
### ps
```
$ ps -ef | jc --ps -p
$ ps -ef | jc --ps -p # or: jc -p ps -ef
[
{
"uid": "root",
@@ -1334,7 +1606,7 @@ $ ps -ef | jc --ps -p
]
```
```
$ ps axu | jc --ps -p
$ ps axu | jc --ps -p # or: jc -p ps axu
[
{
"user": "root",
@@ -1380,7 +1652,7 @@ $ ps axu | jc --ps -p
```
### route
```
$ route -ee | jc --route -p
$ route -ee | jc --route -p # or: jc -p route -ee
[
{
"destination": "default",
@@ -1423,9 +1695,46 @@ $ route -ee | jc --route -p
}
]
```
### /etc/shadow file
```
$ 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
},
...
]
```
### ss
```
$ sudo ss -a | jc --ss -p
$ sudo ss -a | jc --ss -p # or: sudo jc -p ss -a
[
{
"netid": "nl",
@@ -1544,7 +1853,7 @@ $ sudo ss -a | jc --ss -p
```
### stat
```
$ stat /bin/* | jc --stat -p
$ stat /bin/* | jc --stat -p # or: jc -p stat /bin/*
[
{
"file": "/bin/bash",
@@ -1591,7 +1900,7 @@ $ stat /bin/* | jc --stat -p
```
### systemctl
```
$ systemctl -a | jc --systemctl -p
$ systemctl -a | jc --systemctl -p # or: jc -p systemctl -a
[
{
"unit": "proc-sys-fs-binfmt_misc.automount",
@@ -1619,7 +1928,7 @@ $ systemctl -a | jc --systemctl -p
```
### systemctl list-jobs
```
$ systemctl list-jobs| jc --systemctl-lj -p
$ systemctl list-jobs | jc --systemctl-lj -p # or: jc -p systemctl list-jobs
[
{
"job": 3543,
@@ -1643,7 +1952,7 @@ $ systemctl list-jobs| jc --systemctl-lj -p
```
### systemctl list-sockets
```
$ systemctl list-sockets | jc --systemctl-ls -p
$ systemctl list-sockets | jc --systemctl-ls -p # or: jc -p systemctl list-sockets
[
{
"listen": "/dev/log",
@@ -1665,7 +1974,7 @@ $ systemctl list-sockets | jc --systemctl-ls -p
```
### systemctl list-unit-files
```
$ systemctl list-unit-files | jc --systemctl-luf -p
$ systemctl list-unit-files | jc --systemctl-luf -p # or: jc -p systemctl list-unit-files
[
{
"unit_file": "proc-sys-fs-binfmt_misc.automount",
@@ -1684,7 +1993,7 @@ $ systemctl list-unit-files | jc --systemctl-luf -p
```
### uname -a
```
$ uname -a | jc --uname -p
$ uname -a | jc --uname -p # or: jc -p uname -a
{
"kernel_name": "Linux",
"node_name": "user-ubuntu",
@@ -1698,7 +2007,7 @@ $ uname -a | jc --uname -p
```
### uptime
```
$ uptime | jc --uptime -p
$ uptime | jc --uptime -p # or: jc -p uptime
{
"time": "11:30:44",
"uptime": "1 day, 21:17",
@@ -1710,7 +2019,7 @@ $ uptime | jc --uptime -p
```
### w
```
$ w | jc --w -p
$ w | jc --w -p # or: jc -p w
[
{
"user": "root",
@@ -1744,6 +2053,67 @@ $ w | jc --w -p
}
]
```
### who
```
$ who | jc --who -p # or: jc -p who
[
{
"user": "joeuser",
"tty": "ttyS0",
"time": "2020-03-02 02:52"
},
{
"user": "joeuser",
"tty": "pts/0",
"time": "2020-03-02 05:15",
"from": "192.168.71.1"
}
]
```
```
$ who -a | jc --who -p # or: jc -p who -a
[
{
"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"
}
]
```
### XML files
```
$ cat cd_catalog.xml
@@ -1792,7 +2162,7 @@ $ cat cd_catalog.xml | jc --xml -p
```
### YAML files
```
$ cat istio-mtls-permissive.yaml
$ cat istio.yaml
apiVersion: "authentication.istio.io/v1alpha1"
kind: "Policy"
metadata:
@@ -1813,7 +2183,7 @@ spec:
tls:
mode: ISTIO_MUTUAL
$ cat istio-mtls-permissive.yaml | jc --yaml -p
$ cat istio.yaml | jc --yaml -p
[
{
"apiVersion": "authentication.istio.io/v1alpha1",
@@ -1847,34 +2217,4 @@ $ cat istio-mtls-permissive.yaml | jc --yaml -p
}
}
]
```
## TODO
Future parsers:
- /proc files
- /sys files
## Contributions
Feel free to add/improve code or parsers! You can use the `jc/parsers/foo.py` parser as a template and submit your parser with a pull request.
## Compatibility
Some parsers like `ls`, `ps`, `dig`, etc. will work on any platform. Other parsers that are platform-specific will generate a warning message if they are used on an unsupported platform. To see all parser information, including compatibility, run `jc -a -p`.
You may still use a parser on an unsupported platform - for example, you may want to parse a file with linux `lsof` output on an OSX laptop. In that case you can suppress the warning message with the `-q` cli option or the `quiet=True` function parameter in `parse()`:
```
$ cat lsof.out | jc --lsof -q
```
Tested on:
- Centos 7.7
- Ubuntu 18.4
- OSX 10.11.6
- OSX 10.14.6
## Acknowledgments
- `ifconfig-parser` module from https://github.com/KnightWhoSayNi/ifconfig-parser
- `xmltodict` module from https://github.com/martinblech/xmltodict by Martín Blech
- `ruamel.yaml` library from https://pypi.org/project/ruamel.yaml by Anthon van der Neut
- Parsing code from Conor Heine at https://gist.github.com/cahna/43a1a3ff4d075bcd71f9d7120037a501 adapted for some parsers
- Excellent constructive feedback from Ilya Sher (https://github.com/ilyash-b)
```

View File

@@ -1,5 +1,28 @@
jc changelog
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

View File

@@ -5,14 +5,18 @@ cd jc
pydocmd simple jc+ > ../docs/readme.md
pydocmd simple utils+ > ../docs/utils.md
pydocmd simple jc.parsers.arp+ > ../docs/parsers/arp.md
pydocmd simple jc.parsers.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.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
@@ -20,16 +24,19 @@ 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.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
@@ -39,5 +46,6 @@ pydocmd simple jc.parsers.systemctl_luf+ > ../docs/parsers/systemctl_luf.md
pydocmd simple jc.parsers.uname+ > ../docs/parsers/uname.md
pydocmd simple jc.parsers.uptime+ > ../docs/parsers/uptime.md
pydocmd simple jc.parsers.w+ > ../docs/parsers/w.md
pydocmd simple jc.parsers.who+ > ../docs/parsers/who.md
pydocmd simple jc.parsers.xml+ > ../docs/parsers/xml.md
pydocmd simple jc.parsers.yaml+ > ../docs/parsers/yaml.md

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.

View File

@@ -1,9 +1,9 @@
# jc.parsers.crontab
jc - JSON CLI output utility crontab file Parser
jc - JSON CLI output utility crontab command and file Parser
Usage:
specify --crontab as the first argument if the piped input is coming from a crontab file
specify --crontab as the first argument if the piped input is coming from crontab -l or a crontab file
Compatibility:
@@ -11,7 +11,7 @@ Compatibility:
Examples:
$ cat /etc/crontab | jc --crontab -p
$ crontab -l | jc --crontab -p
{
"variables": [
{

View File

@@ -11,7 +11,7 @@ Compatibility:
Examples:
$ cat /etc/crontab | jc --crontab -p
$ cat /etc/crontab | jc --crontab-u -p
{
"variables": [
{

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.

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.

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.

View File

@@ -1,16 +1,21 @@
# 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:
- None
- la
- 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.
-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:
@@ -165,6 +170,7 @@ Returns:
"filename": string,
"flags": string,
"links": integer,
"parent": string,
"owner": string,
"group": string,
"size": integer,

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.

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.

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.

140
jc/cli.py
View File

@@ -3,22 +3,38 @@
JC cli module
"""
import sys
import os
import shlex
import importlib
import textwrap
import signal
import json
import jc.utils
class info():
version = '1.8.0'
description = 'jc cli output JSON conversion tool'
author = 'Kelly Brazil'
author_email = 'kellyjonbrazil@gmail.com'
__version__ = info.version
parsers = [
'arp',
'blkid',
'crontab',
'crontab-u',
'csv',
'df',
'dig',
'du',
'env',
'free',
'fstab',
'group',
'gshadow',
'history',
'hosts',
'id',
@@ -26,16 +42,19 @@ parsers = [
'ini',
'iptables',
'jobs',
'last',
'ls',
'lsblk',
'lsmod',
'lsof',
'mount',
'netstat',
'passwd',
'pip-list',
'pip-show',
'ps',
'route',
'shadow',
'ss',
'stat',
'systemctl',
@@ -45,11 +64,17 @@ parsers = [
'uname',
'uptime',
'w',
'who',
'xml',
'yaml'
]
def ctrlc(signum, frame):
"""exit with error on SIGINT"""
sys.exit(1)
def parser_shortname(parser_argument):
"""short name of the parser with dashes and no -- prefix"""
return parser_argument[2:]
@@ -66,26 +91,13 @@ def parser_mod_shortname(parser):
def parser_module(parser):
"""import the module just in time and present the module object"""
"""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))
class info():
version = '1.7.1'
description = 'jc cli output JSON conversion tool'
author = 'Kelly Brazil'
author_email = 'kellyjonbrazil@gmail.com'
__version__ = info.version
def ctrlc(signum, frame):
sys.exit(1)
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)
@@ -103,6 +115,7 @@ def parsers_text(indent=0, pad=0):
def about_jc():
"""return jc info and the contents of each parser.info as a dictionary"""
parser_list = []
for parser in parsers:
@@ -132,12 +145,17 @@ def about_jc():
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: jc PARSER [OPTIONS]
Usage: COMMAND | jc PARSER [OPTIONS]
or magic syntax:
jc [OPTIONS] COMMAND
Parsers:
{parsers_string}
@@ -150,6 +168,10 @@ def helptext(message):
Example:
ls -al | jc --ls -p
or using the magic syntax:
jc -p ls -al
'''
print(textwrap.dedent(helptext_string), file=sys.stderr)
@@ -161,28 +183,102 @@ def json_out(data, pretty=False):
print(json.dumps(data))
def magic():
"""Parse with magic syntax: jc -p ls -al"""
if len(sys.argv) > 1 and not sys.argv[1].startswith('--'):
parser_info = about_jc()['parsers']
# correctly parse escape characters and spaces with shlex
args_given = " ".join(map(shlex.quote, sys.argv[1:])).split()
options = []
found_parser = None
# find the options
if args_given[0].startswith('-'):
p = 0
for i, arg in list(enumerate(args_given)):
# parser found - use standard syntax
if arg.startswith('--'):
return
# option found - populate option list
elif arg.startswith('-'):
options.append(args_given.pop(i - p)[1:])
p = p + 1
# command found if iterator didn't already stop - stop iterating
else:
break
# find the command and parser
for parser in parser_info:
if 'magic_commands' in parser:
# first pass for two word commands: e.g. 'pip list'
for magic_command in parser['magic_commands']:
try:
if ' '.join(args_given[0:2]) == magic_command:
found_parser = parser['argument']
break
# No command found - go to next loop (for cases like 'jc -a')
except Exception:
break
# second pass for one word commands: e.g. 'ls'
if not found_parser:
for magic_command in parser['magic_commands']:
try:
if args_given[0] == magic_command:
found_parser = parser['argument']
break
# No command found - use standard syntax (for cases like 'jc -a')
except Exception:
return
# construct a new command line using the standard syntax: COMMAND | jc --PARSER -OPTIONS
run_command = ' '.join(args_given)
if found_parser:
if options:
cmd_options = '-' + ''.join(options)
else:
cmd_options = ''
whole_command = ' '.join([run_command, '|', 'jc', found_parser, cmd_options])
os.system(whole_command)
exit()
else:
helptext(f'parser not found for "{run_command}"')
sys.exit(1)
def main():
# break on ctrl-c keyboard interrupt
signal.signal(signal.SIGINT, ctrlc)
# try magic syntax first: e.g. jc -p ls -al
magic()
options = []
debug = False
pretty = False
quiet = False
raw = False
# options
if '-d' in sys.argv:
for opt in sys.argv:
if opt.startswith('-') and not opt.startswith('--'):
for flag in opt[1:]:
options.append(flag)
if 'd' in options:
debug = True
if '-p' in sys.argv:
if 'p' in options:
pretty = True
if '-q' in sys.argv:
if 'q' in options:
quiet = True
if '-r' in sys.argv:
if 'r' in options:
raw = True
if '-a' in sys.argv:
if 'a' in options:
json_out(about_jc(), pretty=pretty)
exit()
@@ -215,7 +311,7 @@ def main():
result = parser.parse(data, raw=raw, quiet=quiet)
found = True
break
except:
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)

View File

@@ -92,12 +92,13 @@ import jc.parsers.universal
class info():
version = '1.1'
description = 'arp parser'
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

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

@@ -0,0 +1,219 @@
"""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:
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 = []
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)

View File

@@ -1,8 +1,8 @@
"""jc - JSON CLI output utility crontab file Parser
"""jc - JSON CLI output utility crontab command and file Parser
Usage:
specify --crontab as the first argument if the piped input is coming from a crontab file
specify --crontab as the first argument if the piped input is coming from crontab -l or a crontab file
Compatibility:
@@ -10,7 +10,7 @@ Compatibility:
Examples:
$ cat /etc/crontab | jc --crontab -p
$ crontab -l | jc --crontab -p
{
"variables": [
{
@@ -133,13 +133,14 @@ import jc.parsers.universal
class info():
version = '1.1'
description = 'crontab file parser'
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

View File

@@ -10,7 +10,7 @@ Compatibility:
Examples:
$ cat /etc/crontab | jc --crontab -p
$ cat /etc/crontab | jc --crontab-u -p
{
"variables": [
{

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)

View File

@@ -74,12 +74,13 @@ import jc.parsers.universal
class info():
version = '1.1'
description = 'df parser'
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

View File

@@ -325,12 +325,13 @@ import jc.utils
class info():
version = '1.0'
description = 'dig parser'
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

View File

@@ -74,13 +74,14 @@ import jc.parsers.universal
class info():
version = '1.1'
description = 'du parser'
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

View File

@@ -53,12 +53,13 @@ import jc.utils
class info():
version = '1.1'
description = 'env parser'
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

View File

@@ -21,13 +21,14 @@ import jc.utils
class info():
version = '1.0'
description = 'foo parser'
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

View File

@@ -54,12 +54,13 @@ import jc.parsers.universal
class info():
version = '1.0'
description = 'free parser'
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

View File

@@ -71,7 +71,7 @@ import jc.utils
class info():
version = '1.0'
description = '/etc/fstab file parser'
description = 'fstab file parser'
author = 'Kelly Brazil'
author_email = 'kellyjonbrazil@gmail.com'

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)

View File

@@ -45,7 +45,7 @@ import jc
class info():
version = '1.1'
description = 'history parser'
description = 'history command parser'
author = 'Kelly Brazil'
author_email = 'kellyjonbrazil@gmail.com'

View File

@@ -71,13 +71,14 @@ import jc.utils
class info():
version = '1.0'
description = 'id parser'
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

View File

@@ -147,13 +147,14 @@ from ifconfigparser import IfconfigParser
class info():
version = '1.5'
description = 'ifconfig parser'
description = 'ifconfig command parser'
author = 'Kelly Brazil'
author_email = 'kellyjonbrazil@gmail.com'
details = 'Using ifconfig-parser package from https://github.com/KnightWhoSayNi/ifconfig-parser'
# compatible options: linux, darwin, cygwin, win32, aix, freebsd
compatible = ['linux', 'aix', 'freebsd', 'darwin']
magic_commands = ['ifconfig']
__version__ = info.version

View File

@@ -135,12 +135,13 @@ import jc.utils
class info():
version = '1.1'
description = 'iptables parser'
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

View File

@@ -78,12 +78,13 @@ import jc.utils
class info():
version = '1.0'
description = 'jobs parser'
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

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,15 +1,20 @@
"""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
- la
- 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.
-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:
@@ -144,13 +149,14 @@ import jc.utils
class info():
version = '1.0'
description = 'ls parser'
version = '1.2'
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
@@ -173,6 +179,7 @@ def process(proc_data):
"filename": string,
"flags": string,
"links": integer,
"parent": string,
"owner": string,
"group": string,
"size": integer,
@@ -212,27 +219,58 @@ def parse(data, raw=False, quiet=False):
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
# 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]
@@ -240,6 +278,9 @@ def parse(data, raw=False, quiet=False):
if len(filename_field) > 1:
output_line['link_to'] = filename_field[1]
if parent:
output_line['parent'] = parent
output_line['flags'] = parsed_line[0]
output_line['links'] = parsed_line[1]
output_line['owner'] = parsed_line[2]
@@ -248,9 +289,27 @@ def parse(data, raw=False, quiet=False):
output_line['date'] = ' '.join(parsed_line[5:8])
raw_output.append(output_line)
else:
for entry in cleandata:
for entry in linedata:
output_line = {}
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:

View File

@@ -217,12 +217,13 @@ import jc.parsers.universal
class info():
version = '1.3'
description = 'lsblk parser'
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

View File

@@ -108,12 +108,13 @@ import jc.parsers.universal
class info():
version = '1.1'
description = 'lsmod parser'
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

View File

@@ -98,12 +98,13 @@ import jc.parsers.universal
class info():
version = '1.0'
description = 'lsof parser'
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

View File

@@ -57,12 +57,13 @@ import jc.utils
class info():
version = '1.1'
description = 'mount parser'
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

View File

@@ -314,12 +314,13 @@ import jc.utils
class info():
version = '1.2'
description = 'netstat parser'
description = 'netstat command parser'
author = 'Kelly Brazil'
author_email = 'kellyjonbrazil@gmail.com'
# compatible options: linux, darwin, cygwin, win32, aix, freebsd
compatible = ['linux']
magic_commands = ['netstat']
__version__ = info.version

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)

View File

@@ -33,12 +33,13 @@ import jc.parsers.universal
class info():
version = '1.0'
description = 'pip list parser'
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

View File

@@ -43,12 +43,13 @@ import jc.utils
class info():
version = '1.0'
description = 'pip show parser'
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

View File

@@ -178,12 +178,13 @@ import jc.parsers.universal
class info():
version = '1.1'
description = 'ps parser'
description = 'ps command parser'
author = 'Kelly Brazil'
author_email = 'kellyjonbrazil@gmail.com'
# compatible options: linux, darwin, cygwin, win32, aix, freebsd
compatible = ['linux', 'darwin', 'cygwin', 'aix', 'freebsd']
magic_commands = ['ps']
__version__ = info.version

View File

@@ -102,12 +102,13 @@ import jc.parsers.universal
class info():
version = '1.0'
description = 'route parser'
description = 'route command parser'
author = 'Kelly Brazil'
author_email = 'kellyjonbrazil@gmail.com'
# compatible options: linux, darwin, cygwin, win32, aix, freebsd
compatible = ['linux']
magic_commands = ['route']
__version__ = info.version

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

@@ -0,0 +1,183 @@
"""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": ""
},
...
]
"""
import jc.utils
class info():
version = '1.0'
description = '/etc/shadow 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,
"last_changed": integer,
"minimum": integer,
"maximum": integer,
"warn": integer,
"inactive": integer,
"expire": integer
}
]
"""
for entry in proc_data:
int_list = ['last_changed', 'minimum', 'maximum', 'warn', 'inactive', 'expire']
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['last_changed'] = fields[2]
output_line['minimum'] = fields[3]
output_line['maximum'] = fields[4]
output_line['warn'] = fields[5]
output_line['inactive'] = fields[6]
output_line['expire'] = fields[7]
raw_output.append(output_line)
if raw:
return raw_output
else:
return process(raw_output)

View File

@@ -252,12 +252,13 @@ import jc.utils
class info():
version = '1.0'
description = 'ss parser'
description = 'ss command parser'
author = 'Kelly Brazil'
author_email = 'kellyjonbrazil@gmail.com'
# compatible options: linux, darwin, cygwin, win32, aix, freebsd
compatible = ['linux']
magic_commands = ['ss']
__version__ = info.version

View File

@@ -105,12 +105,13 @@ import jc.utils
class info():
version = '1.0'
description = 'stat parser'
description = 'stat command parser'
author = 'Kelly Brazil'
author_email = 'kellyjonbrazil@gmail.com'
# compatible options: linux, darwin, cygwin, win32, aix, freebsd
compatible = ['linux']
magic_commands = ['stat']
__version__ = info.version

View File

@@ -41,12 +41,13 @@ import jc.utils
class info():
version = '1.0'
description = 'systemctl parser'
description = 'systemctl command parser'
author = 'Kelly Brazil'
author_email = 'kellyjonbrazil@gmail.com'
# compatible options: linux, darwin, cygwin, win32, aix, freebsd
compatible = ['linux']
magic_commands = ['systemctl']
__version__ = info.version

View File

@@ -60,12 +60,13 @@ import jc.utils
class info():
version = '1.0'
description = 'systemctl list-jobs parser'
description = 'systemctl list-jobs command parser'
author = 'Kelly Brazil'
author_email = 'kellyjonbrazil@gmail.com'
# compatible options: linux, darwin, cygwin, win32, aix, freebsd
compatible = ['linux']
magic_commands = ['systemctl list-jobs']
__version__ = info.version

View File

@@ -35,12 +35,13 @@ import jc.utils
class info():
version = '1.0'
description = 'systemctl list-sockets parser'
description = 'systemctl list-sockets command parser'
author = 'Kelly Brazil'
author_email = 'kellyjonbrazil@gmail.com'
# compatible options: linux, darwin, cygwin, win32, aix, freebsd
compatible = ['linux']
magic_commands = ['systemctl list-sockets']
__version__ = info.version

View File

@@ -32,12 +32,13 @@ import jc.utils
class info():
version = '1.0'
description = 'systemctl list-unit-files parser'
description = 'systemctl list-unit-files command parser'
author = 'Kelly Brazil'
author_email = 'kellyjonbrazil@gmail.com'
# compatible options: linux, darwin, cygwin, win32, aix, freebsd
compatible = ['linux']
magic_commands = ['systemctl list-unit-files']
__version__ = info.version

View File

@@ -31,12 +31,13 @@ import jc.utils
class info():
version = '1.1'
description = 'uname -a parser'
description = 'uname -a command parser'
author = 'Kelly Brazil'
author_email = 'kellyjonbrazil@gmail.com'
# compatible options: linux, darwin, cygwin, win32, aix, freebsd
compatible = ['linux', 'darwin']
magic_commands = ['uname']
__version__ = info.version

View File

@@ -35,12 +35,13 @@ import jc.utils
class info():
version = '1.0'
description = 'uptime parser'
description = 'uptime command parser'
author = 'Kelly Brazil'
author_email = 'kellyjonbrazil@gmail.com'
# compatible options: linux, darwin, cygwin, win32, aix, freebsd
compatible = ['linux', 'darwin', 'cygwin', 'aix', 'freebsd']
magic_commands = ['uptime']
__version__ = info.version

View File

@@ -84,12 +84,13 @@ import jc.utils
class info():
version = '1.0'
description = 'w parser'
description = 'w command parser'
author = 'Kelly Brazil'
author_email = 'kellyjonbrazil@gmail.com'
# compatible options: linux, darwin, cygwin, win32, aix, freebsd
compatible = ['linux', 'darwin', 'cygwin', 'aix', 'freebsd']
magic_commands = ['w']
__version__ = info.version

284
jc/parsers/who.py Normal file
View File

@@ -0,0 +1,284 @@
"""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"
}
]
"""
import re
import jc.utils
class info():
version = '1.0'
description = 'who 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', 'cygwin', 'aix', 'freebsd']
magic_commands = ['who']
__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,
"event": string,
"writeable_tty": string,
"tty": string,
"time": string,
"idle": string,
"pid": integer,
"from": string,
"comment": string
}
]
"""
for entry in proc_data:
int_list = ['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 = []
cleandata = data.splitlines()
# Clear any blank lines
cleandata = list(filter(None, cleandata))
if cleandata:
for line in cleandata:
output_line = {}
linedata = line.split()
# clear headers, if they exist
if ''.join(linedata[0:3]) == 'NAMELINETIME' \
or ''.join(linedata[0:3]) == 'USERLINEWHEN':
linedata.pop(0)
continue
# mac reboot line
if linedata[0] == 'reboot':
output_line['event'] = 'reboot'
output_line['time'] = ' '.join(linedata[2:5])
output_line['pid'] = linedata[6]
raw_output.append(output_line)
continue
# linux reboot line
if ''.join(linedata[0:2]) == 'systemboot':
output_line['event'] = 'reboot'
output_line['time'] = ' '.join(linedata[2:4])
raw_output.append(output_line)
continue
# linux login line
if linedata[0] == 'LOGIN':
output_line['event'] = 'login'
output_line['tty'] = linedata[1]
output_line['time'] = ' '.join(linedata[2:4])
output_line['pid'] = linedata[4]
if len(linedata) > 5:
output_line['comment'] = ' '.join(linedata[5:])
raw_output.append(output_line)
continue
# linux run-level
if linedata[0] == 'run-level':
output_line['event'] = ' '.join(linedata[0:2])
output_line['time'] = ' '.join(linedata[2:4])
raw_output.append(output_line)
continue
# mac run-level (ignore because not enough useful info)
if linedata[1] == 'run-level':
continue
# pts lines with no user information
if linedata[0].startswith('pts/'):
output_line['tty'] = linedata[0]
output_line['time'] = ' '.join(linedata[1:3])
output_line['pid'] = linedata[3]
output_line['comment'] = ' '.join(linedata[4:])
raw_output.append(output_line)
continue
# user logins
output_line['user'] = linedata.pop(0)
if linedata[0] in '+-?':
output_line['writeable_tty'] = linedata.pop(0)
output_line['tty'] = linedata.pop(0)
# mac
if re.match(r'[JFMASOND][aepuco][nbrynlgptvc]', linedata[0]):
output_line['time'] = ' '.join([linedata.pop(0),
linedata.pop(0),
linedata.pop(0)])
# linux
else:
output_line['time'] = ' '.join([linedata.pop(0),
linedata.pop(0)])
# if just one more field, then it's the remote IP
if len(linedata) == 1:
output_line['from'] = linedata[0].replace('(', '').replace(')', '')
raw_output.append(output_line)
continue
# extended info: idle
if len(linedata) > 0:
output_line['idle'] = linedata.pop(0)
# extended info: pid
if len(linedata) > 0:
output_line['pid'] = linedata.pop(0)
# extended info is from
if len(linedata) > 0 and linedata[0].startswith('('):
output_line['from'] = linedata[0].replace('(', '').replace(')', '')
# else, extended info is comment
elif len(linedata) > 0:
output_line['comment'] = ' '.join(linedata)
raw_output.append(output_line)
if raw:
return raw_output
else:
return process(raw_output)

View File

@@ -5,7 +5,7 @@ with open('README.md', 'r') as f:
setuptools.setup(
name='jc',
version='1.7.1',
version='1.8.0',
author='Kelly Brazil',
author_email='kellyjonbrazil@gmail.com',
description='This tool serializes the output of popular command line tools and filetypes to structured JSON output.',
@@ -20,6 +20,7 @@ setuptools.setup(
python_requires='>=3.6',
url='https://github.com/kellyjonbrazil/jc',
packages=setuptools.find_packages(),
include_package_data=True,
entry_points={
'console_scripts': [
'jc=jc.cli:main'

View File

@@ -0,0 +1 @@
[{"uuid": "3klkIj-w1qk-DkJi-0XBJ-y3o7-i2Ac-vHqWBM", "version": "LVM2 001", "type": "LVM2_member", "usage": "raid", "minimum_io_size": 512, "physical_sector_size": 512, "logical_sector_size": 512, "part_entry_scheme": "dos", "part_entry_type": "0x8e", "part_entry_number": 2, "part_entry_offset": 2099200, "part_entry_size": 39843840, "part_entry_disk": "8:0", "device": "/dev/sda2"}, {"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", "device": "/dev/sda1"}]

View File

@@ -0,0 +1,29 @@
DEVNAME=/dev/sda2
UUID=3klkIj-w1qk-DkJi-0XBJ-y3o7-i2Ac-vHqWBM
VERSION=LVM2 001
TYPE=LVM2_member
USAGE=raid
MINIMUM_IO_SIZE=512
PHYSICAL_SECTOR_SIZE=512
LOGICAL_SECTOR_SIZE=512
PART_ENTRY_SCHEME=dos
PART_ENTRY_TYPE=0x8e
PART_ENTRY_NUMBER=2
PART_ENTRY_OFFSET=2099200
PART_ENTRY_SIZE=39843840
PART_ENTRY_DISK=8:0
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

View File

@@ -0,0 +1 @@
[{"id_fs_uuid": "3klkIj-w1qk-DkJi-0XBJ-y3o7-i2Ac-vHqWBM", "id_fs_uuid_enc": "3klkIj-w1qk-DkJi-0XBJ-y3o7-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"}, {"id_fs_uuid": "05d927bb-5875-49e3-ada1-7f46cb31c932", "id_fs_uuid_enc": "05d927bb-5875-49e3-ada1-7f46cb31c932", "id_fs_type": "xfs", "id_fs_usage": "filesystem", "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": "0x83", "id_part_entry_flags": "0x80", "id_part_entry_number": 1, "id_part_entry_offset": 2048, "id_part_entry_size": 2097152, "id_part_entry_disk": "8:0"}]

View File

@@ -0,0 +1,29 @@
ID_FS_UUID=3klkIj-w1qk-DkJi-0XBJ-y3o7-i2Ac-vHqWBM
ID_FS_UUID_ENC=3klkIj-w1qk-DkJi-0XBJ-y3o7-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
ID_FS_UUID=05d927bb-5875-49e3-ada1-7f46cb31c932
ID_FS_UUID_ENC=05d927bb-5875-49e3-ada1-7f46cb31c932
ID_FS_TYPE=xfs
ID_FS_USAGE=filesystem
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=0x83
ID_PART_ENTRY_FLAGS=0x80
ID_PART_ENTRY_NUMBER=1
ID_PART_ENTRY_OFFSET=2048
ID_PART_ENTRY_SIZE=2097152
ID_PART_ENTRY_DISK=8:0

View File

@@ -0,0 +1 @@
[{"id_fs_uuid": "05d927bb-5875-49e3-ada1-7f46cb31c932", "id_fs_uuid_enc": "05d927bb-5875-49e3-ada1-7f46cb31c932", "id_fs_type": "xfs", "id_fs_usage": "filesystem", "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": "0x83", "id_part_entry_flags": "0x80", "id_part_entry_number": 1, "id_part_entry_offset": 2048, "id_part_entry_size": 2097152, "id_part_entry_disk": "8:0"}]

View File

@@ -0,0 +1,14 @@
ID_FS_UUID=05d927bb-5875-49e3-ada1-7f46cb31c932
ID_FS_UUID_ENC=05d927bb-5875-49e3-ada1-7f46cb31c932
ID_FS_TYPE=xfs
ID_FS_USAGE=filesystem
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=0x83
ID_PART_ENTRY_FLAGS=0x80
ID_PART_ENTRY_NUMBER=1
ID_PART_ENTRY_OFFSET=2048
ID_PART_ENTRY_SIZE=2097152
ID_PART_ENTRY_DISK=8:0

View File

@@ -0,0 +1 @@
[{"device": "/dev/sda2", "uuid": "3klkIj-w1qk-DkJi-0XBJ-y3o7-i2Ac-vHqWBM", "type": "LVM2_member"}]

View File

@@ -0,0 +1 @@
/dev/sda2: UUID="3klkIj-w1qk-DkJi-0XBJ-y3o7-i2Ac-vHqWBM" TYPE="LVM2_member"

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

@@ -0,0 +1 @@
[{"device": "/dev/sda1", "uuid": "05d927bb-5875-49e3-ada1-7f46cb31c932", "type": "xfs"}, {"device": "/dev/sda2", "uuid": "3klkIj-w1qk-DkJi-0XBJ-y3o7-i2Ac-vHqWBM", "type": "LVM2_member"}, {"device": "/dev/mapper/centos-root", "uuid": "07d718ef-950c-4e5b-98e0-42a1147b77d9", "type": "xfs"}, {"device": "/dev/mapper/centos-swap", "uuid": "615eb89d-bcbf-46ad-80e3-c483ef5c931f", "type": "swap"}]

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

@@ -0,0 +1,4 @@
/dev/sda1: UUID="05d927bb-5875-49e3-ada1-7f46cb31c932" TYPE="xfs"
/dev/sda2: UUID="3klkIj-w1qk-DkJi-0XBJ-y3o7-i2Ac-vHqWBM" TYPE="LVM2_member"
/dev/mapper/centos-root: UUID="07d718ef-950c-4e5b-98e0-42a1147b77d9" TYPE="xfs"
/dev/mapper/centos-swap: UUID="615eb89d-bcbf-46ad-80e3-c483ef5c931f" TYPE="swap"

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

@@ -0,0 +1 @@
[{"group_name": "root", "password": "x", "gid": 0, "members": []}, {"group_name": "bin", "password": "x", "gid": 1, "members": []}, {"group_name": "daemon", "password": "x", "gid": 2, "members": []}, {"group_name": "sys", "password": "x", "gid": 3, "members": []}, {"group_name": "adm", "password": "x", "gid": 4, "members": []}, {"group_name": "tty", "password": "x", "gid": 5, "members": []}, {"group_name": "disk", "password": "x", "gid": 6, "members": []}, {"group_name": "lp", "password": "x", "gid": 7, "members": []}, {"group_name": "mem", "password": "x", "gid": 8, "members": []}, {"group_name": "kmem", "password": "x", "gid": 9, "members": []}, {"group_name": "wheel", "password": "x", "gid": 10, "members": ["joeuser"]}, {"group_name": "cdrom", "password": "x", "gid": 11, "members": []}, {"group_name": "mail", "password": "x", "gid": 12, "members": ["postfix"]}, {"group_name": "man", "password": "x", "gid": 15, "members": []}, {"group_name": "dialout", "password": "x", "gid": 18, "members": []}, {"group_name": "floppy", "password": "x", "gid": 19, "members": []}, {"group_name": "games", "password": "x", "gid": 20, "members": []}, {"group_name": "tape", "password": "x", "gid": 33, "members": []}, {"group_name": "video", "password": "x", "gid": 39, "members": []}, {"group_name": "ftp", "password": "x", "gid": 50, "members": []}, {"group_name": "lock", "password": "x", "gid": 54, "members": []}, {"group_name": "audio", "password": "x", "gid": 63, "members": []}, {"group_name": "nobody", "password": "x", "gid": 99, "members": []}, {"group_name": "users", "password": "x", "gid": 100, "members": []}, {"group_name": "utmp", "password": "x", "gid": 22, "members": []}, {"group_name": "utempter", "password": "x", "gid": 35, "members": []}, {"group_name": "input", "password": "x", "gid": 999, "members": []}, {"group_name": "systemd-journal", "password": "x", "gid": 190, "members": []}, {"group_name": "systemd-network", "password": "x", "gid": 192, "members": []}, {"group_name": "dbus", "password": "x", "gid": 81, "members": []}, {"group_name": "polkitd", "password": "x", "gid": 998, "members": []}, {"group_name": "ssh_keys", "password": "x", "gid": 997, "members": []}, {"group_name": "sshd", "password": "x", "gid": 74, "members": []}, {"group_name": "postdrop", "password": "x", "gid": 90, "members": []}, {"group_name": "postfix", "password": "x", "gid": 89, "members": []}, {"group_name": "chrony", "password": "x", "gid": 996, "members": []}, {"group_name": "joeuser", "password": "x", "gid": 1000, "members": ["joeuser"]}, {"group_name": "cgred", "password": "x", "gid": 995, "members": []}, {"group_name": "dockerroot", "password": "x", "gid": 994, "members": []}]

39
tests/fixtures/centos-7.7/group.out vendored Normal file
View File

@@ -0,0 +1,39 @@
root:x:0:
bin:x:1:
daemon:x:2:
sys:x:3:
adm:x:4:
tty:x:5:
disk:x:6:
lp:x:7:
mem:x:8:
kmem:x:9:
wheel:x:10:joeuser
cdrom:x:11:
mail:x:12:postfix
man:x:15:
dialout:x:18:
floppy:x:19:
games:x:20:
tape:x:33:
video:x:39:
ftp:x:50:
lock:x:54:
audio:x:63:
nobody:x:99:
users:x:100:
utmp:x:22:
utempter:x:35:
input:x:999:
systemd-journal:x:190:
systemd-network:x:192:
dbus:x:81:
polkitd:x:998:
ssh_keys:x:997:
sshd:x:74:
postdrop:x:90:
postfix:x:89:
chrony:x:996:
joeuser:x:1000:joeuser
cgred:x:995:
dockerroot:x:994:

View File

@@ -0,0 +1 @@
[{"group_name": "root", "password": "", "administrators": [], "members": []}, {"group_name": "bin", "password": "", "administrators": [], "members": []}, {"group_name": "daemon", "password": "", "administrators": [], "members": []}, {"group_name": "sys", "password": "", "administrators": [], "members": []}, {"group_name": "adm", "password": "", "administrators": [], "members": []}, {"group_name": "tty", "password": "", "administrators": [], "members": []}, {"group_name": "disk", "password": "", "administrators": [], "members": []}, {"group_name": "lp", "password": "", "administrators": [], "members": []}, {"group_name": "mem", "password": "", "administrators": [], "members": []}, {"group_name": "kmem", "password": "", "administrators": [], "members": []}, {"group_name": "wheel", "password": "", "administrators": [], "members": ["joeuser"]}, {"group_name": "cdrom", "password": "", "administrators": [], "members": []}, {"group_name": "mail", "password": "", "administrators": [], "members": ["postfix"]}, {"group_name": "man", "password": "", "administrators": [], "members": []}, {"group_name": "dialout", "password": "", "administrators": [], "members": []}, {"group_name": "floppy", "password": "", "administrators": [], "members": []}, {"group_name": "games", "password": "", "administrators": [], "members": []}, {"group_name": "tape", "password": "", "administrators": [], "members": []}, {"group_name": "video", "password": "", "administrators": [], "members": []}, {"group_name": "ftp", "password": "", "administrators": [], "members": []}, {"group_name": "lock", "password": "", "administrators": [], "members": []}, {"group_name": "audio", "password": "", "administrators": [], "members": []}, {"group_name": "nobody", "password": "", "administrators": [], "members": []}, {"group_name": "users", "password": "", "administrators": [], "members": []}, {"group_name": "utmp", "password": "!", "administrators": [], "members": []}, {"group_name": "utempter", "password": "!", "administrators": [], "members": []}, {"group_name": "input", "password": "!", "administrators": [], "members": []}, {"group_name": "systemd-journal", "password": "!", "administrators": [], "members": []}, {"group_name": "systemd-network", "password": "!", "administrators": [], "members": []}, {"group_name": "dbus", "password": "!", "administrators": [], "members": []}, {"group_name": "polkitd", "password": "!", "administrators": [], "members": []}, {"group_name": "ssh_keys", "password": "!", "administrators": [], "members": []}, {"group_name": "sshd", "password": "!", "administrators": [], "members": []}, {"group_name": "postdrop", "password": "!", "administrators": [], "members": []}, {"group_name": "postfix", "password": "!", "administrators": [], "members": []}, {"group_name": "chrony", "password": "!", "administrators": [], "members": []}, {"group_name": "joeuser", "password": "!!", "administrators": [], "members": ["joeuser"]}, {"group_name": "cgred", "password": "!", "administrators": [], "members": []}, {"group_name": "dockerroot", "password": "!", "administrators": [], "members": []}]

39
tests/fixtures/centos-7.7/gshadow.out vendored Normal file
View File

@@ -0,0 +1,39 @@
root:::
bin:::
daemon:::
sys:::
adm:::
tty:::
disk:::
lp:::
mem:::
kmem:::
wheel:::joeuser
cdrom:::
mail:::postfix
man:::
dialout:::
floppy:::
games:::
tape:::
video:::
ftp:::
lock:::
audio:::
nobody:::
users:::
utmp:!::
utempter:!::
input:!::
systemd-journal:!::
systemd-network:!::
dbus:!::
polkitd:!::
ssh_keys:!::
sshd:!::
postdrop:!::
postfix:!::
chrony:!::
joeuser:!!::joeuser
cgred:!::
dockerroot:!::

1
tests/fixtures/centos-7.7/last-w.json vendored Normal file

File diff suppressed because one or more lines are too long

69
tests/fixtures/centos-7.7/last-w.out vendored Normal file
View File

@@ -0,0 +1,69 @@
kbrazil ttyS0 Fri Feb 28 13:49 still logged in
reboot system boot 3.10.0-1062.1.2.el7.x86_64 Fri Feb 28 12:56 - 14:54 (01:58)
kbrazil ttyS0 Thu Feb 27 16:01 - crash (20:54)
reboot system boot 3.10.0-1062.1.2.el7.x86_64 Thu Feb 27 15:51 - 14:54 (23:02)
kbrazil ttyS0 Thu Feb 27 10:50 - crash (05:01)
reboot system boot 3.10.0-1062.1.2.el7.x86_64 Wed Feb 26 20:05 - 14:54 (1+18:49)
kbrazil ttyS0 Thu Feb 20 14:42 - crash (6+05:23)
reboot system boot 3.10.0-1062.1.2.el7.x86_64 Thu Feb 20 14:41 - 14:54 (8+00:12)
kbrazil ttyS0 Mon Feb 17 17:48 - crash (2+20:52)
reboot system boot 3.10.0-1062.1.2.el7.x86_64 Mon Feb 17 17:48 - 14:54 (10+21:06)
kbrazil ttyS0 Thu Feb 13 16:44 - crash (4+01:03)
reboot system boot 3.10.0-1062.1.2.el7.x86_64 Thu Feb 13 16:44 - 14:54 (14+22:10)
kbrazil ttyS0 Wed Feb 5 14:23 - crash (8+02:20)
reboot system boot 3.10.0-1062.1.2.el7.x86_64 Wed Feb 5 11:43 - 14:54 (23+03:11)
kbrazil ttyS0 Tue Feb 4 14:28 - crash (21:15)
reboot system boot 3.10.0-1062.1.2.el7.x86_64 Tue Feb 4 01:28 - 14:54 (24+13:26)
kbrazil ttyS0 Mon Jan 13 17:28 - crash (21+07:59)
reboot system boot 3.10.0-1062.1.2.el7.x86_64 Mon Jan 13 16:16 - 14:54 (45+22:38)
kbrazil ttyS0 Mon Dec 16 11:15 - crash (28+05:01)
reboot system boot 3.10.0-1062.1.2.el7.x86_64 Mon Dec 16 11:14 - 14:54 (74+03:40)
kbrazil ttyS0 Wed Dec 4 21:41 - crash (11+13:33)
reboot system boot 3.10.0-1062.1.2.el7.x86_64 Wed Dec 4 21:40 - 14:54 (85+17:13)
kbrazil pts/1 Sat Nov 16 14:40 - 14:40 (00:00)
kbrazil pts/1 Sat Nov 16 14:39 - 14:39 (00:00)
kbrazil pts/0 localhost Tue Nov 12 07:19 - crash (22+14:21)
kbrazil ttyS0 Tue Nov 12 07:18 - crash (22+14:22)
kbrazil pts/0 localhost Sun Nov 10 08:21 - 15:22 (1+07:01)
kbrazil ttyS0 Sat Nov 9 10:34 - 07:16 (2+20:42)
reboot system boot 3.10.0-1062.1.2.el7.x86_64 Sat Nov 9 10:34 - 14:54 (111+04:20)
kbrazil tty1 Fri Nov 8 07:49 - crash (1+02:45)
kbrazil pts/0 192.168.71.1 Fri Nov 8 06:29 - crash (1+04:04)
kbrazil ttyS0 Fri Nov 8 06:24 - crash (1+04:09)
reboot system boot 3.10.0-1062.1.2.el7.x86_64 Fri Nov 8 06:14 - 14:54 (112+08:40)
kbrazil tty1 Sun Nov 3 12:20 - crash (4+17:54)
kbrazil ttyS0 Sun Nov 3 11:04 - 11:05 (00:01)
kbrazil pts/0 192.168.71.1 Sat Nov 2 19:26 - crash (5+11:47)
kbrazil ttyS0 Fri Nov 1 15:14 - 11:03 (1+20:49)
reboot system boot 3.10.0-1062.1.2.el7.x86_64 Fri Nov 1 15:13 - 14:54 (119+00:41)
kbrazil ttyS0 Fri Nov 1 11:16 - 11:36 (00:20)
reboot system boot 3.10.0-1062.1.2.el7.x86_64 Fri Nov 1 06:00 - 11:36 (05:36)
kbrazil ttyS0 Tue Oct 29 18:17 - crash (2+11:43)
reboot system boot 3.10.0-1062.1.2.el7.x86_64 Tue Oct 29 18:16 - 11:36 (2+17:19)
kbrazil pts/0 192.168.71.1 Sat Oct 26 09:53 - 15:13 (05:19)
kbrazil ttyS0 Fri Oct 25 18:22 - crash (3+23:54)
reboot system boot 3.10.0-1062.1.2.el7.x86_64 Fri Oct 25 18:21 - 11:36 (6+17:14)
kbrazil ttyS0 Fri Oct 25 17:14 - 18:21 (01:06)
reboot system boot 3.10.0-1062.1.2.el7.x86_64 Fri Oct 25 17:13 - 11:36 (6+18:22)
kbrazil ttyS0 Fri Oct 25 15:43 - 17:13 (01:29)
reboot system boot 3.10.0-1062.1.2.el7.x86_64 Fri Oct 25 13:29 - 17:13 (03:44)
kbrazil ttyS0 Mon Oct 21 13:19 - 19:22 (2+06:03)
reboot system boot 3.10.0-1062.1.2.el7.x86_64 Mon Oct 21 13:17 - 19:22 (2+06:05)
kbrazil ttyS0 Wed Oct 16 03:23 - crash (5+09:54)
kbrazil ttyS0 Tue Oct 15 16:49 - 03:23 (10:34)
kbrazil ttyS0 Tue Oct 15 10:39 - 16:48 (06:09)
reboot system boot 3.10.0-957.27.2.el7.x86_64 Tue Oct 15 10:39 - 19:22 (8+08:43)
kbrazil ttyS0 Thu Aug 15 16:05 - 16:05 (00:00)
reboot system boot 3.10.0-957.27.2.el7.x86_64 Thu Aug 15 16:05 - 16:05 (00:00)
reboot system boot 3.10.0-957.27.2.el7.x86_64 Thu Aug 15 16:00 - 16:05 (00:05)
kbrazil ttyS0 Thu Aug 15 14:25 - crash (01:35)
reboot system boot 3.10.0-957.27.2.el7.x86_64 Thu Aug 15 14:24 - 16:05 (01:41)
kbrazil ttyS0 Thu Aug 15 11:58 - crash (02:25)
reboot system boot 3.10.0-957.el7.x86_64 Thu Aug 15 11:58 - 16:05 (04:07)
kbrazil ttyS0 Thu Aug 15 11:57 - 11:57 (00:00)
reboot system boot 3.10.0-957.el7.x86_64 Thu Aug 15 11:57 - 16:05 (04:08)
kbrazil pts/0 192.168.71.1 Thu Aug 15 10:58 - 11:56 (00:58)
root tty1 Thu Aug 15 10:57 - 11:56 (00:59)
reboot system boot 3.10.0-957.el7.x86_64 Thu Aug 15 10:57 - 11:56 (00:59)
wtmp begins Thu Aug 15 10:57:06 2019

1
tests/fixtures/centos-7.7/last.json vendored Normal file

File diff suppressed because one or more lines are too long

69
tests/fixtures/centos-7.7/last.out vendored Normal file
View File

@@ -0,0 +1,69 @@
kbrazil ttyS0 Fri Feb 28 13:49 still logged in
reboot system boot 3.10.0-1062.1.2. Fri Feb 28 12:56 - 14:52 (01:56)
kbrazil ttyS0 Thu Feb 27 16:01 - crash (20:54)
reboot system boot 3.10.0-1062.1.2. Thu Feb 27 15:51 - 14:52 (23:01)
kbrazil ttyS0 Thu Feb 27 10:50 - crash (05:01)
reboot system boot 3.10.0-1062.1.2. Wed Feb 26 20:05 - 14:52 (1+18:47)
kbrazil ttyS0 Thu Feb 20 14:42 - crash (6+05:23)
reboot system boot 3.10.0-1062.1.2. Thu Feb 20 14:41 - 14:52 (8+00:11)
kbrazil ttyS0 Mon Feb 17 17:48 - crash (2+20:52)
reboot system boot 3.10.0-1062.1.2. Mon Feb 17 17:48 - 14:52 (10+21:04)
kbrazil ttyS0 Thu Feb 13 16:44 - crash (4+01:03)
reboot system boot 3.10.0-1062.1.2. Thu Feb 13 16:44 - 14:52 (14+22:08)
kbrazil ttyS0 Wed Feb 5 14:23 - crash (8+02:20)
reboot system boot 3.10.0-1062.1.2. Wed Feb 5 11:43 - 14:52 (23+03:09)
kbrazil ttyS0 Tue Feb 4 14:28 - crash (21:15)
reboot system boot 3.10.0-1062.1.2. Tue Feb 4 01:28 - 14:52 (24+13:24)
kbrazil ttyS0 Mon Jan 13 17:28 - crash (21+07:59)
reboot system boot 3.10.0-1062.1.2. Mon Jan 13 16:16 - 14:52 (45+22:36)
kbrazil ttyS0 Mon Dec 16 11:15 - crash (28+05:01)
reboot system boot 3.10.0-1062.1.2. Mon Dec 16 11:14 - 14:52 (74+03:38)
kbrazil ttyS0 Wed Dec 4 21:41 - crash (11+13:33)
reboot system boot 3.10.0-1062.1.2. Wed Dec 4 21:40 - 14:52 (85+17:12)
kbrazil pts/1 Sat Nov 16 14:40 - 14:40 (00:00)
kbrazil pts/1 Sat Nov 16 14:39 - 14:39 (00:00)
kbrazil pts/0 localhost Tue Nov 12 07:19 - crash (22+14:21)
kbrazil ttyS0 Tue Nov 12 07:18 - crash (22+14:22)
kbrazil pts/0 localhost Sun Nov 10 08:21 - 15:22 (1+07:01)
kbrazil ttyS0 Sat Nov 9 10:34 - 07:16 (2+20:42)
reboot system boot 3.10.0-1062.1.2. Sat Nov 9 10:34 - 14:52 (111+04:18)
kbrazil tty1 Fri Nov 8 07:49 - crash (1+02:45)
kbrazil pts/0 192.168.71.1 Fri Nov 8 06:29 - crash (1+04:04)
kbrazil ttyS0 Fri Nov 8 06:24 - crash (1+04:09)
reboot system boot 3.10.0-1062.1.2. Fri Nov 8 06:14 - 14:52 (112+08:38)
kbrazil tty1 Sun Nov 3 12:20 - crash (4+17:54)
kbrazil ttyS0 Sun Nov 3 11:04 - 11:05 (00:01)
kbrazil pts/0 192.168.71.1 Sat Nov 2 19:26 - crash (5+11:47)
kbrazil ttyS0 Fri Nov 1 15:14 - 11:03 (1+20:49)
reboot system boot 3.10.0-1062.1.2. Fri Nov 1 15:13 - 14:52 (119+00:39)
kbrazil ttyS0 Fri Nov 1 11:16 - 11:36 (00:20)
reboot system boot 3.10.0-1062.1.2. Fri Nov 1 06:00 - 11:36 (05:36)
kbrazil ttyS0 Tue Oct 29 18:17 - crash (2+11:43)
reboot system boot 3.10.0-1062.1.2. Tue Oct 29 18:16 - 11:36 (2+17:19)
kbrazil pts/0 192.168.71.1 Sat Oct 26 09:53 - 15:13 (05:19)
kbrazil ttyS0 Fri Oct 25 18:22 - crash (3+23:54)
reboot system boot 3.10.0-1062.1.2. Fri Oct 25 18:21 - 11:36 (6+17:14)
kbrazil ttyS0 Fri Oct 25 17:14 - 18:21 (01:06)
reboot system boot 3.10.0-1062.1.2. Fri Oct 25 17:13 - 11:36 (6+18:22)
kbrazil ttyS0 Fri Oct 25 15:43 - 17:13 (01:29)
reboot system boot 3.10.0-1062.1.2. Fri Oct 25 13:29 - 17:13 (03:44)
kbrazil ttyS0 Mon Oct 21 13:19 - 19:22 (2+06:03)
reboot system boot 3.10.0-1062.1.2. Mon Oct 21 13:17 - 19:22 (2+06:05)
kbrazil ttyS0 Wed Oct 16 03:23 - crash (5+09:54)
kbrazil ttyS0 Tue Oct 15 16:49 - 03:23 (10:34)
kbrazil ttyS0 Tue Oct 15 10:39 - 16:48 (06:09)
reboot system boot 3.10.0-957.27.2. Tue Oct 15 10:39 - 19:22 (8+08:43)
kbrazil ttyS0 Thu Aug 15 16:05 - 16:05 (00:00)
reboot system boot 3.10.0-957.27.2. Thu Aug 15 16:05 - 16:05 (00:00)
reboot system boot 3.10.0-957.27.2. Thu Aug 15 16:00 - 16:05 (00:05)
kbrazil ttyS0 Thu Aug 15 14:25 - crash (01:35)
reboot system boot 3.10.0-957.27.2. Thu Aug 15 14:24 - 16:05 (01:41)
kbrazil ttyS0 Thu Aug 15 11:58 - crash (02:25)
reboot system boot 3.10.0-957.el7.x Thu Aug 15 11:58 - 16:05 (04:07)
kbrazil ttyS0 Thu Aug 15 11:57 - 11:57 (00:00)
reboot system boot 3.10.0-957.el7.x Thu Aug 15 11:57 - 16:05 (04:08)
kbrazil pts/0 192.168.71.1 Thu Aug 15 10:58 - 11:56 (00:58)
root tty1 Thu Aug 15 10:57 - 11:56 (00:59)
reboot system boot 3.10.0-957.el7.x Thu Aug 15 10:57 - 11:56 (00:59)
wtmp begins Thu Aug 15 10:57:06 2019

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

@@ -0,0 +1 @@
[{"user": "kbrazil", "tty": "ttyS0", "hostname": null, "login": "Fri Feb 28 13:49", "logout": "13:49", "duration": "00:00"}, {"user": "kbrazil", "tty": "ssh:notty", "hostname": "192.168.71.1", "login": "Thu Feb 27 10:13", "logout": "10:13", "duration": "00:00"}, {"user": "kbrazil", "tty": "ttyS0", "hostname": null, "login": "Thu Feb 20 14:41", "logout": "14:41", "duration": "00:00"}, {"user": "kbrazil", "tty": "ttyS0", "hostname": null, "login": "Mon Feb 17 17:48", "logout": "17:48", "duration": "00:00"}]

6
tests/fixtures/centos-7.7/lastb.out vendored Normal file
View File

@@ -0,0 +1,6 @@
kbrazil ttyS0 Fri Feb 28 13:49 - 13:49 (00:00)
kbrazil ssh:notty 192.168.71.1 Thu Feb 27 10:13 - 10:13 (00:00)
kbrazil ttyS0 Thu Feb 20 14:41 - 14:41 (00:00)
kbrazil ttyS0 Mon Feb 17 17:48 - 17:48 (00:00)
btmp begins Mon Feb 17 17:48:53 2020

View File

@@ -0,0 +1 @@
[{"filename": "systemd-private-016de60725a3426792b93fc9f120b8f0-chronyd.service-oZqq4u", "parent": "."}, {"filename": "systemd-private-a30a5a178daa4042b42dfaf5ff9e5f68-chronyd.service-a1tpxv", "parent": "."}, {"filename": "systemd-private-af69d7360f3e40cfa947358c0fb5a6f8-chronyd.service-T3MQ4j", "parent": "."}, {"filename": "tmp.CvALl2jE6u", "parent": "."}, {"filename": "tmp.e7AlxSxY5a", "parent": "."}, {"filename": "tmp.uXm9yegjwj", "parent": "."}, {"filename": "a regular filename", "parent": "./lstest"}, {"filename": "this file has", "parent": "./lstest"}, {"filename": "a combination", "parent": "./lstest"}, {"filename": "of everything", "parent": "./lstest"}, {"filename": "this file has", "parent": "./lstest"}, {"filename": "a newline inside", "parent": "./lstest"}, {"filename": "this file has", "parent": "./lstest"}, {"filename": "four contiguous newlines inside", "parent": "./lstest"}, {"filename": "this file", "parent": "./lstest"}, {"filename": "has", "parent": "./lstest"}, {"filename": "six", "parent": "./lstest"}, {"filename": "newlines", "parent": "./lstest"}, {"filename": "within", "parent": "./lstest"}, {"filename": "this file starts with four newlines", "parent": "./lstest"}, {"filename": "this file starts with one newline", "parent": "./lstest"}]

View File

@@ -0,0 +1,43 @@
.:
lstest
systemd-private-016de60725a3426792b93fc9f120b8f0-chronyd.service-oZqq4u
systemd-private-a30a5a178daa4042b42dfaf5ff9e5f68-chronyd.service-a1tpxv
systemd-private-af69d7360f3e40cfa947358c0fb5a6f8-chronyd.service-T3MQ4j
tmp.CvALl2jE6u
tmp.e7AlxSxY5a
tmp.uXm9yegjwj
./lstest:
a regular filename
this file has
a combination
of everything
this file has
a newline inside
this file has
four contiguous newlines inside
this file
has
six
newlines
within
this file starts with four newlines
this file starts with one newline

1
tests/fixtures/centos-7.7/ls-R.json vendored Normal file

File diff suppressed because one or more lines are too long

5089
tests/fixtures/centos-7.7/ls-R.out vendored Normal file

File diff suppressed because it is too large Load Diff

1
tests/fixtures/centos-7.7/ls-alR.json vendored Normal file

File diff suppressed because one or more lines are too long

4997
tests/fixtures/centos-7.7/ls-alR.out vendored Normal file

File diff suppressed because it is too large Load Diff

File diff suppressed because one or more lines are too long

1919
tests/fixtures/centos-7.7/ls-glob.out vendored Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1 @@
[{"filename": "a regular filename", "flags": "-rw-rw-r--.", "links": 1, "owner": "kbrazil", "group": "kbrazil", "size": 0, "date": "Feb 22 00:12"}, {"filename": "\n\nthis file has\na combination\n\n\nof everything\n\n\n\n", "flags": "-rw-rw-r--.", "links": 1, "owner": "kbrazil", "group": "kbrazil", "size": 0, "date": "Feb 22 00:17"}, {"filename": "this file has\na newline inside", "flags": "-rw-rw-r--.", "links": 1, "owner": "kbrazil", "group": "kbrazil", "size": 0, "date": "Feb 22 00:14"}, {"filename": "this file has\n\n\n\nfour contiguous newlines inside", "flags": "-rw-rw-r--.", "links": 1, "owner": "kbrazil", "group": "kbrazil", "size": 0, "date": "Feb 22 00:14"}, {"filename": "this file\nhas\nsix\n\nnewlines\n\nwithin", "flags": "-rw-rw-r--.", "links": 1, "owner": "kbrazil", "group": "kbrazil", "size": 0, "date": "Feb 22 00:16"}, {"filename": "\n\n\n\nthis file starts with four newlines", "flags": "-rw-rw-r--.", "links": 1, "owner": "kbrazil", "group": "kbrazil", "size": 0, "date": "Feb 22 00:40"}, {"filename": "\nthis file starts with one newline", "flags": "-rw-rw-r--.", "links": 1, "owner": "kbrazil", "group": "kbrazil", "size": 0, "date": "Feb 22 00:13"}]

View File

@@ -0,0 +1,34 @@
total 0
-rw-rw-r--. 1 kbrazil kbrazil 0 Feb 22 00:12 a regular filename
-rw-rw-r--. 1 kbrazil kbrazil 0 Feb 22 00:17
this file has
a combination
of everything
-rw-rw-r--. 1 kbrazil kbrazil 0 Feb 22 00:14 this file has
a newline inside
-rw-rw-r--. 1 kbrazil kbrazil 0 Feb 22 00:14 this file has
four contiguous newlines inside
-rw-rw-r--. 1 kbrazil kbrazil 0 Feb 22 00:16 this file
has
six
newlines
within
-rw-rw-r--. 1 kbrazil kbrazil 0 Feb 22 00:40
this file starts with four newlines
-rw-rw-r--. 1 kbrazil kbrazil 0 Feb 22 00:13
this file starts with one newline

View File

@@ -0,0 +1 @@
[{"filename": "lstest", "parent": ".", "flags": "drwxrwxr-x.", "links": 2, "owner": "kbrazil", "group": "kbrazil", "size": 4096, "date": "Feb 22 00:40"}, {"filename": "systemd-private-016de60725a3426792b93fc9f120b8f0-chronyd.service-oZqq4u", "parent": ".", "flags": "drwx------.", "links": 3, "owner": "root", "group": "root", "size": 17, "date": "Feb 13 16:44"}, {"filename": "systemd-private-a30a5a178daa4042b42dfaf5ff9e5f68-chronyd.service-a1tpxv", "parent": ".", "flags": "drwx------.", "links": 3, "owner": "root", "group": "root", "size": 17, "date": "Feb 17 17:48"}, {"filename": "systemd-private-af69d7360f3e40cfa947358c0fb5a6f8-chronyd.service-T3MQ4j", "parent": ".", "flags": "drwx------.", "links": 3, "owner": "root", "group": "root", "size": 17, "date": "Feb 20 14:41"}, {"filename": "tmp.CvALl2jE6u", "parent": ".", "flags": "drwx------.", "links": 2, "owner": "root", "group": "root", "size": 6, "date": "Feb 13 16:44"}, {"filename": "tmp.e7AlxSxY5a", "parent": ".", "flags": "drwx------.", "links": 2, "owner": "root", "group": "root", "size": 6, "date": "Feb 20 14:41"}, {"filename": "tmp.uXm9yegjwj", "parent": ".", "flags": "drwx------.", "links": 2, "owner": "root", "group": "root", "size": 6, "date": "Feb 17 17:48"}, {"filename": "a regular filename", "parent": "./lstest", "flags": "-rw-rw-r--.", "links": 1, "owner": "kbrazil", "group": "kbrazil", "size": 0, "date": "Feb 22 00:12"}, {"filename": "\n\nthis file has\na combination\n\n\nof everything\n\n\n\n", "parent": "./lstest", "flags": "-rw-rw-r--.", "links": 1, "owner": "kbrazil", "group": "kbrazil", "size": 0, "date": "Feb 22 00:17"}, {"filename": "this file has\na newline inside", "parent": "./lstest", "flags": "-rw-rw-r--.", "links": 1, "owner": "kbrazil", "group": "kbrazil", "size": 0, "date": "Feb 22 00:14"}, {"filename": "this file has\n\n\n\nfour contiguous newlines inside", "parent": "./lstest", "flags": "-rw-rw-r--.", "links": 1, "owner": "kbrazil", "group": "kbrazil", "size": 0, "date": "Feb 22 00:14"}, {"filename": "this file\nhas\nsix\n\nnewlines\n\nwithin", "parent": "./lstest", "flags": "-rw-rw-r--.", "links": 1, "owner": "kbrazil", "group": "kbrazil", "size": 0, "date": "Feb 22 00:16"}, {"filename": "\n\n\n\nthis file starts with four newlines", "parent": "./lstest", "flags": "-rw-rw-r--.", "links": 1, "owner": "kbrazil", "group": "kbrazil", "size": 0, "date": "Feb 22 00:40"}, {"filename": "\nthis file starts with one newline", "parent": "./lstest", "flags": "-rw-rw-r--.", "links": 1, "owner": "kbrazil", "group": "kbrazil", "size": 0, "date": "Feb 22 00:13"}]

View File

@@ -0,0 +1,45 @@
.:
total 4
drwxrwxr-x. 2 kbrazil kbrazil 4096 Feb 22 00:40 lstest
drwx------. 3 root root 17 Feb 13 16:44 systemd-private-016de60725a3426792b93fc9f120b8f0-chronyd.service-oZqq4u
drwx------. 3 root root 17 Feb 17 17:48 systemd-private-a30a5a178daa4042b42dfaf5ff9e5f68-chronyd.service-a1tpxv
drwx------. 3 root root 17 Feb 20 14:41 systemd-private-af69d7360f3e40cfa947358c0fb5a6f8-chronyd.service-T3MQ4j
drwx------. 2 root root 6 Feb 13 16:44 tmp.CvALl2jE6u
drwx------. 2 root root 6 Feb 20 14:41 tmp.e7AlxSxY5a
drwx------. 2 root root 6 Feb 17 17:48 tmp.uXm9yegjwj
./lstest:
total 0
-rw-rw-r--. 1 kbrazil kbrazil 0 Feb 22 00:12 a regular filename
-rw-rw-r--. 1 kbrazil kbrazil 0 Feb 22 00:17
this file has
a combination
of everything
-rw-rw-r--. 1 kbrazil kbrazil 0 Feb 22 00:14 this file has
a newline inside
-rw-rw-r--. 1 kbrazil kbrazil 0 Feb 22 00:14 this file has
four contiguous newlines inside
-rw-rw-r--. 1 kbrazil kbrazil 0 Feb 22 00:16 this file
has
six
newlines
within
-rw-rw-r--. 1 kbrazil kbrazil 0 Feb 22 00:40
this file starts with four newlines
-rw-rw-r--. 1 kbrazil kbrazil 0 Feb 22 00:13
this file starts with one newline

View File

@@ -0,0 +1 @@
[{"filename": "a regular filename"}, {"filename": "this file has"}, {"filename": "a combination"}, {"filename": "of everything"}, {"filename": "this file has"}, {"filename": "a newline inside"}, {"filename": "this file has"}, {"filename": "four contiguous newlines inside"}, {"filename": "this file"}, {"filename": "has"}, {"filename": "six"}, {"filename": "newlines"}, {"filename": "within"}, {"filename": "this file starts with four newlines"}, {"filename": "this file starts with one newline"}]

View File

@@ -0,0 +1,33 @@
a regular filename
this file has
a combination
of everything
this file has
a newline inside
this file has
four contiguous newlines inside
this file
has
six
newlines
within
this file starts with four newlines
this file starts with one newline

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

@@ -0,0 +1 @@
[{"username": "root", "password": "x", "uid": 0, "gid": 0, "comment": "root", "home": "/root", "shell": "/bin/bash"}, {"username": "bin", "password": "x", "uid": 1, "gid": 1, "comment": "bin", "home": "/bin", "shell": "/sbin/nologin"}, {"username": "daemon", "password": "x", "uid": 2, "gid": 2, "comment": "daemon", "home": "/sbin", "shell": "/sbin/nologin"}, {"username": "adm", "password": "x", "uid": 3, "gid": 4, "comment": "adm", "home": "/var/adm", "shell": "/sbin/nologin"}, {"username": "lp", "password": "x", "uid": 4, "gid": 7, "comment": "lp", "home": "/var/spool/lpd", "shell": "/sbin/nologin"}, {"username": "sync", "password": "x", "uid": 5, "gid": 0, "comment": "sync", "home": "/sbin", "shell": "/bin/sync"}, {"username": "shutdown", "password": "x", "uid": 6, "gid": 0, "comment": "shutdown", "home": "/sbin", "shell": "/sbin/shutdown"}, {"username": "halt", "password": "x", "uid": 7, "gid": 0, "comment": "halt", "home": "/sbin", "shell": "/sbin/halt"}, {"username": "mail", "password": "x", "uid": 8, "gid": 12, "comment": "mail", "home": "/var/spool/mail", "shell": "/sbin/nologin"}, {"username": "operator", "password": "x", "uid": 11, "gid": 0, "comment": "operator", "home": "/root", "shell": "/sbin/nologin"}, {"username": "games", "password": "x", "uid": 12, "gid": 100, "comment": "games", "home": "/usr/games", "shell": "/sbin/nologin"}, {"username": "ftp", "password": "x", "uid": 14, "gid": 50, "comment": "FTP User", "home": "/var/ftp", "shell": "/sbin/nologin"}, {"username": "nobody", "password": "x", "uid": 99, "gid": 99, "comment": "Nobody", "home": "/", "shell": "/sbin/nologin"}, {"username": "systemd-network", "password": "x", "uid": 192, "gid": 192, "comment": "systemd Network Management", "home": "/", "shell": "/sbin/nologin"}, {"username": "dbus", "password": "x", "uid": 81, "gid": 81, "comment": "System message bus", "home": "/", "shell": "/sbin/nologin"}, {"username": "polkitd", "password": "x", "uid": 999, "gid": 998, "comment": "User for polkitd", "home": "/", "shell": "/sbin/nologin"}, {"username": "sshd", "password": "x", "uid": 74, "gid": 74, "comment": "Privilege-separated SSH", "home": "/var/empty/sshd", "shell": "/sbin/nologin"}, {"username": "postfix", "password": "x", "uid": 89, "gid": 89, "comment": "", "home": "/var/spool/postfix", "shell": "/sbin/nologin"}, {"username": "chrony", "password": "x", "uid": 998, "gid": 996, "comment": "", "home": "/var/lib/chrony", "shell": "/sbin/nologin"}, {"username": "joeuser", "password": "x", "uid": 1000, "gid": 1000, "comment": "joeuser", "home": "/home/joeuser", "shell": "/bin/bash"}, {"username": "dockerroot", "password": "x", "uid": 997, "gid": 994, "comment": "Docker User", "home": "/var/lib/docker", "shell": "/sbin/nologin"}]

21
tests/fixtures/centos-7.7/passwd.out vendored Normal file
View File

@@ -0,0 +1,21 @@
root:x:0:0:root:/root:/bin/bash
bin:x:1:1:bin:/bin:/sbin/nologin
daemon:x:2:2:daemon:/sbin:/sbin/nologin
adm:x:3:4:adm:/var/adm:/sbin/nologin
lp:x:4:7:lp:/var/spool/lpd:/sbin/nologin
sync:x:5:0:sync:/sbin:/bin/sync
shutdown:x:6:0:shutdown:/sbin:/sbin/shutdown
halt:x:7:0:halt:/sbin:/sbin/halt
mail:x:8:12:mail:/var/spool/mail:/sbin/nologin
operator:x:11:0:operator:/root:/sbin/nologin
games:x:12:100:games:/usr/games:/sbin/nologin
ftp:x:14:50:FTP User:/var/ftp:/sbin/nologin
nobody:x:99:99:Nobody:/:/sbin/nologin
systemd-network:x:192:192:systemd Network Management:/:/sbin/nologin
dbus:x:81:81:System message bus:/:/sbin/nologin
polkitd:x:999:998:User for polkitd:/:/sbin/nologin
sshd:x:74:74:Privilege-separated SSH:/var/empty/sshd:/sbin/nologin
postfix:x:89:89::/var/spool/postfix:/sbin/nologin
chrony:x:998:996::/var/lib/chrony:/sbin/nologin
joeuser:x:1000:1000:joeuser:/home/joeuser:/bin/bash
dockerroot:x:997:994:Docker User:/var/lib/docker:/sbin/nologin

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

@@ -0,0 +1 @@
[{"username": "root", "password": "$6$27lBiByDWdiM7lvJ$ulWkJyfKNbqDnrIKPLhUCGanKcS5TdY3ZasKMR/v2dl0mHn0s28LcxTXMqqOV0d6tww0U4gmgYZezgAf/F8Pz.", "last_changed": null, "minimum": 0, "maximum": 99999, "warn": 7, "inactive": null, "expire": null}, {"username": "bin", "password": "*", "last_changed": 17834, "minimum": 0, "maximum": 99999, "warn": 7, "inactive": null, "expire": null}, {"username": "daemon", "password": "*", "last_changed": 17834, "minimum": 0, "maximum": 99999, "warn": 7, "inactive": null, "expire": null}, {"username": "adm", "password": "*", "last_changed": 17834, "minimum": 0, "maximum": 99999, "warn": 7, "inactive": null, "expire": null}, {"username": "lp", "password": "*", "last_changed": 17834, "minimum": 0, "maximum": 99999, "warn": 7, "inactive": null, "expire": null}, {"username": "sync", "password": "*", "last_changed": 17834, "minimum": 0, "maximum": 99999, "warn": 7, "inactive": null, "expire": null}, {"username": "shutdown", "password": "*", "last_changed": 17834, "minimum": 0, "maximum": 99999, "warn": 7, "inactive": null, "expire": null}, {"username": "halt", "password": "*", "last_changed": 17834, "minimum": 0, "maximum": 99999, "warn": 7, "inactive": null, "expire": null}, {"username": "mail", "password": "*", "last_changed": 17834, "minimum": 0, "maximum": 99999, "warn": 7, "inactive": null, "expire": null}, {"username": "operator", "password": "*", "last_changed": 17834, "minimum": 0, "maximum": 99999, "warn": 7, "inactive": null, "expire": null}, {"username": "games", "password": "*", "last_changed": 17834, "minimum": 0, "maximum": 99999, "warn": 7, "inactive": null, "expire": null}, {"username": "ftp", "password": "*", "last_changed": 17834, "minimum": 0, "maximum": 99999, "warn": 7, "inactive": null, "expire": null}, {"username": "nobody", "password": "*", "last_changed": 17834, "minimum": 0, "maximum": 99999, "warn": 7, "inactive": null, "expire": null}, {"username": "systemd-network", "password": "!!", "last_changed": 18123, "minimum": null, "maximum": null, "warn": null, "inactive": null, "expire": null}, {"username": "dbus", "password": "!!", "last_changed": 18123, "minimum": null, "maximum": null, "warn": null, "inactive": null, "expire": null}, {"username": "polkitd", "password": "!!", "last_changed": 18123, "minimum": null, "maximum": null, "warn": null, "inactive": null, "expire": null}, {"username": "sshd", "password": "!!", "last_changed": 18123, "minimum": null, "maximum": null, "warn": null, "inactive": null, "expire": null}, {"username": "postfix", "password": "!!", "last_changed": 18123, "minimum": null, "maximum": null, "warn": null, "inactive": null, "expire": null}, {"username": "chrony", "password": "!!", "last_changed": 18123, "minimum": null, "maximum": null, "warn": null, "inactive": null, "expire": null}, {"username": "joeuser", "password": "$6$sR1OEFM1KVuMeBUt$NhanSmm91.BspCYlMtrjYhc71FElgaCP7uSUAwhtQVFGcYa7.8VPMmRce77yS8FLy6XSYBtcCeZCJhnLOicc/.", "last_changed": null, "minimum": 0, "maximum": 99999, "warn": 7, "inactive": null, "expire": null}, {"username": "dockerroot", "password": "!!", "last_changed": 18123, "minimum": null, "maximum": null, "warn": null, "inactive": null, "expire": null}]

21
tests/fixtures/centos-7.7/shadow.out vendored Normal file
View File

@@ -0,0 +1,21 @@
root:$6$27lBiByDWdiM7lvJ$ulWkJyfKNbqDnrIKPLhUCGanKcS5TdY3ZasKMR/v2dl0mHn0s28LcxTXMqqOV0d6tww0U4gmgYZezgAf/F8Pz.::0:99999:7:::
bin:*:17834:0:99999:7:::
daemon:*:17834:0:99999:7:::
adm:*:17834:0:99999:7:::
lp:*:17834:0:99999:7:::
sync:*:17834:0:99999:7:::
shutdown:*:17834:0:99999:7:::
halt:*:17834:0:99999:7:::
mail:*:17834:0:99999:7:::
operator:*:17834:0:99999:7:::
games:*:17834:0:99999:7:::
ftp:*:17834:0:99999:7:::
nobody:*:17834:0:99999:7:::
systemd-network:!!:18123::::::
dbus:!!:18123::::::
polkitd:!!:18123::::::
sshd:!!:18123::::::
postfix:!!:18123::::::
chrony:!!:18123::::::
joeuser:$6$sR1OEFM1KVuMeBUt$NhanSmm91.BspCYlMtrjYhc71FElgaCP7uSUAwhtQVFGcYa7.8VPMmRce77yS8FLy6XSYBtcCeZCJhnLOicc/.::0:99999:7:::
dockerroot:!!:18123::::::

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

@@ -0,0 +1 @@
[{"event": "reboot", "time": "2020-02-29 12:13"}, {"event": "login", "tty": "tty1", "time": "2020-02-29 12:13", "pid": 841, "comment": "id=tty1"}, {"user": "kbrazil", "writeable_tty": "+", "tty": "ttyS0", "time": "2020-02-29 12:14", "idle": ".", "pid": 840}, {"event": "run-level 3", "time": "2020-02-29 12:13"}, {"user": "kbrazil", "writeable_tty": "+", "tty": "pts/0", "time": "2020-02-29 18:43", "idle": "00:11", "pid": 3709, "from": "192.168.71.1"}, {"tty": "pts/1", "time": "2020-02-29 18:28", "pid": 3381, "comment": "id=ts/1 term=0 exit=0"}]

6
tests/fixtures/centos-7.7/who-a.out vendored Normal file
View File

@@ -0,0 +1,6 @@
system boot 2020-02-29 12:13
LOGIN tty1 2020-02-29 12:13 841 id=tty1
kbrazil + ttyS0 2020-02-29 12:14 . 840
run-level 3 2020-02-29 12:13
kbrazil + pts/0 2020-02-29 18:43 00:11 3709 (192.168.71.1)
pts/1 2020-02-29 18:28 3381 id=ts/1 term=0 exit=0

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

@@ -0,0 +1 @@
[{"user": "kbrazil", "tty": "ttyS0", "time": "2020-02-29 12:14"}, {"user": "kbrazil", "tty": "pts/0", "time": "2020-02-29 18:43", "from": "192.168.71.1"}]

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