mirror of
https://github.com/kellyjonbrazil/jc.git
synced 2025-07-13 01:20:24 +02:00
162
README.md
162
README.md
@ -65,8 +65,11 @@ jc [parser] [options]
|
|||||||
- `--free` enables the `free` parser
|
- `--free` enables the `free` parser
|
||||||
- `--ifconfig` enables the `ifconfig` parser
|
- `--ifconfig` enables the `ifconfig` parser
|
||||||
- `--iptables` enables the `iptables` parser
|
- `--iptables` enables the `iptables` parser
|
||||||
|
- `--jobs` enables the `jobs` parser
|
||||||
- `--ls` enables the `ls` parser
|
- `--ls` enables the `ls` parser
|
||||||
- `--lsblk` enables the `lsblk` parser
|
- `--lsblk` enables the `lsblk` parser
|
||||||
|
- `--lsmod` enables the `lsmod` parser
|
||||||
|
- `--lsof` enables the `lsof` parser
|
||||||
- `--mount` enables the `mount` parser
|
- `--mount` enables the `mount` parser
|
||||||
- `--netstat` enables the `netstat` parser
|
- `--netstat` enables the `netstat` parser
|
||||||
- `--ps` enables the `ps` parser
|
- `--ps` enables the `ps` parser
|
||||||
@ -549,6 +552,44 @@ $ sudo iptables -vnL -t filter | jc --iptables -p
|
|||||||
...
|
...
|
||||||
]
|
]
|
||||||
```
|
```
|
||||||
|
### jobs
|
||||||
|
```
|
||||||
|
$ jobs -l | jc --jobs -p
|
||||||
|
[
|
||||||
|
{
|
||||||
|
"job_number": 1,
|
||||||
|
"pid": 14798,
|
||||||
|
"status": "Running",
|
||||||
|
"command": "sleep 10000 &"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"job_number": 2,
|
||||||
|
"pid": 14799,
|
||||||
|
"status": "Running",
|
||||||
|
"command": "sleep 10001 &"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"job_number": 3,
|
||||||
|
"pid": 14800,
|
||||||
|
"status": "Running",
|
||||||
|
"command": "sleep 10002 &"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"job_number": 4,
|
||||||
|
"pid": 14814,
|
||||||
|
"history": "previous",
|
||||||
|
"status": "Running",
|
||||||
|
"command": "sleep 10003 &"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"job_number": 5,
|
||||||
|
"pid": 14815,
|
||||||
|
"history": "current",
|
||||||
|
"status": "Running",
|
||||||
|
"command": "sleep 10004 &"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
```
|
||||||
### ls
|
### ls
|
||||||
```
|
```
|
||||||
$ ls -l /bin | jc --ls -p
|
$ ls -l /bin | jc --ls -p
|
||||||
@ -631,6 +672,127 @@ $ lsblk | jc --lsblk -p
|
|||||||
}
|
}
|
||||||
]
|
]
|
||||||
```
|
```
|
||||||
|
### lsmod
|
||||||
|
```
|
||||||
|
$ lsmod | jc --lsmod -p
|
||||||
|
[
|
||||||
|
{
|
||||||
|
"Module": "nf_nat_ipv4",
|
||||||
|
"Size": "14115",
|
||||||
|
"Used": "1",
|
||||||
|
"By": [
|
||||||
|
"iptable_nat"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"Module": "nf_nat",
|
||||||
|
"Size": "26583",
|
||||||
|
"Used": "3",
|
||||||
|
"By": [
|
||||||
|
"nf_nat_ipv4",
|
||||||
|
"nf_nat_ipv6",
|
||||||
|
"nf_nat_masquerade_ipv4"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"Module": "iptable_mangle",
|
||||||
|
"Size": "12695",
|
||||||
|
"Used": "1"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"Module": "iptable_security",
|
||||||
|
"Size": "12705",
|
||||||
|
"Used": "1"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"Module": "iptable_raw",
|
||||||
|
"Size": "12678",
|
||||||
|
"Used": "1"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"Module": "nf_conntrack",
|
||||||
|
"Size": "139224",
|
||||||
|
"Used": "7",
|
||||||
|
"By": [
|
||||||
|
"nf_nat",
|
||||||
|
"nf_nat_ipv4",
|
||||||
|
"nf_nat_ipv6",
|
||||||
|
"xt_conntrack",
|
||||||
|
"nf_nat_masquerade_ipv4",
|
||||||
|
"nf_conntrack_ipv4",
|
||||||
|
"nf_conntrack_ipv6"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
...
|
||||||
|
]
|
||||||
|
```
|
||||||
|
### lsof
|
||||||
|
```
|
||||||
|
$ sudo lsof | jc --lsof -p
|
||||||
|
[
|
||||||
|
{
|
||||||
|
"COMMAND": "systemd",
|
||||||
|
"PID": "1",
|
||||||
|
"TID": null,
|
||||||
|
"USER": "root",
|
||||||
|
"FD": "cwd",
|
||||||
|
"TYPE": "DIR",
|
||||||
|
"DEVICE": "253,0",
|
||||||
|
"SIZE/OFF": "224",
|
||||||
|
"NODE": "64",
|
||||||
|
"NAME": "/"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"COMMAND": "systemd",
|
||||||
|
"PID": "1",
|
||||||
|
"TID": null,
|
||||||
|
"USER": "root",
|
||||||
|
"FD": "rtd",
|
||||||
|
"TYPE": "DIR",
|
||||||
|
"DEVICE": "253,0",
|
||||||
|
"SIZE/OFF": "224",
|
||||||
|
"NODE": "64",
|
||||||
|
"NAME": "/"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"COMMAND": "systemd",
|
||||||
|
"PID": "1",
|
||||||
|
"TID": null,
|
||||||
|
"USER": "root",
|
||||||
|
"FD": "txt",
|
||||||
|
"TYPE": "REG",
|
||||||
|
"DEVICE": "253,0",
|
||||||
|
"SIZE/OFF": "1624520",
|
||||||
|
"NODE": "50360451",
|
||||||
|
"NAME": "/usr/lib/systemd/systemd"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"COMMAND": "systemd",
|
||||||
|
"PID": "1",
|
||||||
|
"TID": null,
|
||||||
|
"USER": "root",
|
||||||
|
"FD": "mem",
|
||||||
|
"TYPE": "REG",
|
||||||
|
"DEVICE": "253,0",
|
||||||
|
"SIZE/OFF": "20064",
|
||||||
|
"NODE": "8146",
|
||||||
|
"NAME": "/usr/lib64/libuuid.so.1.3.0"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"COMMAND": "systemd",
|
||||||
|
"PID": "1",
|
||||||
|
"TID": null,
|
||||||
|
"USER": "root",
|
||||||
|
"FD": "mem",
|
||||||
|
"TYPE": "REG",
|
||||||
|
"DEVICE": "253,0",
|
||||||
|
"SIZE/OFF": "265600",
|
||||||
|
"NODE": "8147",
|
||||||
|
"NAME": "/usr/lib64/libblkid.so.1.1.0"
|
||||||
|
},
|
||||||
|
...
|
||||||
|
]
|
||||||
|
```
|
||||||
### mount
|
### mount
|
||||||
```
|
```
|
||||||
$ mount | jc --mount -p
|
$ mount | jc --mount -p
|
||||||
|
@ -1,5 +1,13 @@
|
|||||||
jc changelog
|
jc changelog
|
||||||
|
|
||||||
|
20191023 v0.9.1
|
||||||
|
- Add jobs parser
|
||||||
|
- Add lsof parser
|
||||||
|
- Add lsmod parser
|
||||||
|
- No blocking if no piped data
|
||||||
|
- Better help text
|
||||||
|
- Clean up iptables parser code
|
||||||
|
|
||||||
20191022 v0.8.1
|
20191022 v0.8.1
|
||||||
- Add env parser
|
- Add env parser
|
||||||
- Add df parser
|
- Add df parser
|
||||||
|
64
jc/jc.py
64
jc/jc.py
@ -11,8 +11,11 @@ import jc.parsers.env
|
|||||||
import jc.parsers.free
|
import jc.parsers.free
|
||||||
import jc.parsers.ifconfig
|
import jc.parsers.ifconfig
|
||||||
import jc.parsers.iptables
|
import jc.parsers.iptables
|
||||||
|
import jc.parsers.jobs
|
||||||
import jc.parsers.ls
|
import jc.parsers.ls
|
||||||
import jc.parsers.lsblk
|
import jc.parsers.lsblk
|
||||||
|
import jc.parsers.lsmod
|
||||||
|
import jc.parsers.lsof
|
||||||
import jc.parsers.mount
|
import jc.parsers.mount
|
||||||
import jc.parsers.netstat
|
import jc.parsers.netstat
|
||||||
import jc.parsers.ps
|
import jc.parsers.ps
|
||||||
@ -20,13 +23,44 @@ import jc.parsers.route
|
|||||||
import jc.parsers.uname
|
import jc.parsers.uname
|
||||||
|
|
||||||
|
|
||||||
|
def helptext():
|
||||||
|
print('Usage: jc [parser] [options]\n', file=sys.stderr)
|
||||||
|
print('Parsers:', file=sys.stderr)
|
||||||
|
print(' --df df parser', file=sys.stderr)
|
||||||
|
print(' --env env parser', file=sys.stderr)
|
||||||
|
print(' --free free parser', file=sys.stderr)
|
||||||
|
print(' --ifconfig iconfig parser', file=sys.stderr)
|
||||||
|
print(' --iptables iptables parser', file=sys.stderr)
|
||||||
|
print(' --jobs jobs parser', file=sys.stderr)
|
||||||
|
print(' --ls ls parser', file=sys.stderr)
|
||||||
|
print(' --lsblk lsblk parser', file=sys.stderr)
|
||||||
|
print(' --lsmod lsmod parser', file=sys.stderr)
|
||||||
|
print(' --lsof lsof parser', file=sys.stderr)
|
||||||
|
print(' --mount mount parser', file=sys.stderr)
|
||||||
|
print(' --netstat netstat parser', file=sys.stderr)
|
||||||
|
print(' --ps ps parser', file=sys.stderr)
|
||||||
|
print(' --route route parser', file=sys.stderr)
|
||||||
|
print(' --uname uname parser\n', file=sys.stderr)
|
||||||
|
print('Options:', file=sys.stderr)
|
||||||
|
print(' -p pretty print output\n', file=sys.stderr)
|
||||||
|
print('Example:', file=sys.stderr)
|
||||||
|
print(' ls -al | jc --ls -p\n', file=sys.stderr)
|
||||||
|
|
||||||
|
|
||||||
def main():
|
def main():
|
||||||
|
if sys.stdin.isatty():
|
||||||
|
print('jc: missing piped data\n', file=sys.stderr)
|
||||||
|
helptext()
|
||||||
|
exit()
|
||||||
|
|
||||||
data = sys.stdin.read()
|
data = sys.stdin.read()
|
||||||
pretty = False
|
pretty = False
|
||||||
|
|
||||||
|
# options
|
||||||
if '-p' in sys.argv:
|
if '-p' in sys.argv:
|
||||||
pretty = True
|
pretty = True
|
||||||
|
|
||||||
|
# parsers
|
||||||
if '--df' in sys.argv:
|
if '--df' in sys.argv:
|
||||||
result = jc.parsers.df.parse(data)
|
result = jc.parsers.df.parse(data)
|
||||||
|
|
||||||
@ -42,12 +76,21 @@ def main():
|
|||||||
elif '--iptables' in sys.argv:
|
elif '--iptables' in sys.argv:
|
||||||
result = jc.parsers.iptables.parse(data)
|
result = jc.parsers.iptables.parse(data)
|
||||||
|
|
||||||
|
elif '--jobs' in sys.argv:
|
||||||
|
result = jc.parsers.jobs.parse(data)
|
||||||
|
|
||||||
elif '--ls' in sys.argv:
|
elif '--ls' in sys.argv:
|
||||||
result = jc.parsers.ls.parse(data)
|
result = jc.parsers.ls.parse(data)
|
||||||
|
|
||||||
elif '--lsblk' in sys.argv:
|
elif '--lsblk' in sys.argv:
|
||||||
result = jc.parsers.lsblk.parse(data)
|
result = jc.parsers.lsblk.parse(data)
|
||||||
|
|
||||||
|
elif '--lsmod' in sys.argv:
|
||||||
|
result = jc.parsers.lsmod.parse(data)
|
||||||
|
|
||||||
|
elif '--lsof' in sys.argv:
|
||||||
|
result = jc.parsers.lsof.parse(data)
|
||||||
|
|
||||||
elif '--mount' in sys.argv:
|
elif '--mount' in sys.argv:
|
||||||
result = jc.parsers.mount.parse(data)
|
result = jc.parsers.mount.parse(data)
|
||||||
|
|
||||||
@ -64,25 +107,8 @@ def main():
|
|||||||
result = jc.parsers.uname.parse(data)
|
result = jc.parsers.uname.parse(data)
|
||||||
|
|
||||||
else:
|
else:
|
||||||
print('jc: missing arguments\n', file=sys.stderr)
|
print('jc: missing or incorrect arguments\n', file=sys.stderr)
|
||||||
print('Usage: jc [parser] [options]\n', file=sys.stderr)
|
helptext()
|
||||||
print('Parsers:', file=sys.stderr)
|
|
||||||
print(' --df df parser', file=sys.stderr)
|
|
||||||
print(' --env env parser', file=sys.stderr)
|
|
||||||
print(' --free free parser', file=sys.stderr)
|
|
||||||
print(' --ifconfig iconfig parser', file=sys.stderr)
|
|
||||||
print(' --iptables iptables parser', file=sys.stderr)
|
|
||||||
print(' --ls ls parser', file=sys.stderr)
|
|
||||||
print(' --lsblk lsblk parser', file=sys.stderr)
|
|
||||||
print(' --mount mount parser', file=sys.stderr)
|
|
||||||
print(' --netstat netstat parser', file=sys.stderr)
|
|
||||||
print(' --ps ps parser', file=sys.stderr)
|
|
||||||
print(' --route route parser', file=sys.stderr)
|
|
||||||
print(' --uname uname parser\n', file=sys.stderr)
|
|
||||||
print('Options:', file=sys.stderr)
|
|
||||||
print(' -p pretty print output\n', file=sys.stderr)
|
|
||||||
print('Example:', file=sys.stderr)
|
|
||||||
print(' ls -al | jc --ls -p\n', file=sys.stderr)
|
|
||||||
exit()
|
exit()
|
||||||
|
|
||||||
# output resulting dictionary as json
|
# output resulting dictionary as json
|
||||||
|
@ -325,42 +325,40 @@ $ sudo iptables -vnL -t filter | jc --iptables -p
|
|||||||
"""
|
"""
|
||||||
|
|
||||||
|
|
||||||
class state():
|
def parse(data):
|
||||||
output = []
|
output = []
|
||||||
chain = {}
|
chain = {}
|
||||||
headers = []
|
headers = []
|
||||||
|
|
||||||
|
|
||||||
def parse(data):
|
|
||||||
cleandata = data.splitlines()
|
cleandata = data.splitlines()
|
||||||
|
|
||||||
for line in cleandata:
|
for line in cleandata:
|
||||||
|
|
||||||
if line.find('Chain') == 0:
|
if line.find('Chain') == 0:
|
||||||
state.output.append(state.chain)
|
output.append(chain)
|
||||||
state.chain = {}
|
chain = {}
|
||||||
state.headers = []
|
headers = []
|
||||||
|
|
||||||
parsed_line = line.split()
|
parsed_line = line.split()
|
||||||
|
|
||||||
state.chain['chain'] = parsed_line[1]
|
chain['chain'] = parsed_line[1]
|
||||||
state.chain['rules'] = []
|
chain['rules'] = []
|
||||||
|
|
||||||
continue
|
continue
|
||||||
|
|
||||||
if line.find('target') == 0 or line.find('pkts') == 1:
|
elif line.find('target') == 0 or line.find('pkts') == 1:
|
||||||
state.headers = []
|
headers = []
|
||||||
state.headers = [h for h in ' '.join(line.strip().split()).split() if h]
|
headers = [h for h in ' '.join(line.strip().split()).split() if h]
|
||||||
state.headers.append("options")
|
headers.append("options")
|
||||||
|
|
||||||
continue
|
continue
|
||||||
|
|
||||||
else:
|
else:
|
||||||
rule = line.split(maxsplit=len(state.headers) - 1)
|
rule = line.split(maxsplit=len(headers) - 1)
|
||||||
temp_rule = dict(zip(state.headers, rule))
|
temp_rule = dict(zip(headers, rule))
|
||||||
if temp_rule:
|
if temp_rule:
|
||||||
state.chain['rules'].append(temp_rule)
|
chain['rules'].append(temp_rule)
|
||||||
|
|
||||||
state.output = list(filter(None, state.output))
|
output = list(filter(None, output))
|
||||||
|
|
||||||
return state.output
|
return output
|
||||||
|
108
jc/parsers/jobs.py
Normal file
108
jc/parsers/jobs.py
Normal file
@ -0,0 +1,108 @@
|
|||||||
|
"""jc - JSON CLI output utility jobs Parser
|
||||||
|
|
||||||
|
Usage:
|
||||||
|
specify --jobs as the first argument if the piped input is coming from jobs
|
||||||
|
|
||||||
|
Also supports the -l option
|
||||||
|
|
||||||
|
Example:
|
||||||
|
|
||||||
|
$ jobs -l | jc --jobs -p
|
||||||
|
[
|
||||||
|
{
|
||||||
|
"job_number": 1,
|
||||||
|
"pid": 14798,
|
||||||
|
"status": "Running",
|
||||||
|
"command": "sleep 10000 &"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"job_number": 2,
|
||||||
|
"pid": 14799,
|
||||||
|
"status": "Running",
|
||||||
|
"command": "sleep 10001 &"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"job_number": 3,
|
||||||
|
"pid": 14800,
|
||||||
|
"status": "Running",
|
||||||
|
"command": "sleep 10002 &"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"job_number": 4,
|
||||||
|
"pid": 14814,
|
||||||
|
"history": "previous",
|
||||||
|
"status": "Running",
|
||||||
|
"command": "sleep 10003 &"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"job_number": 5,
|
||||||
|
"pid": 14815,
|
||||||
|
"history": "current",
|
||||||
|
"status": "Running",
|
||||||
|
"command": "sleep 10004 &"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
"""
|
||||||
|
|
||||||
|
|
||||||
|
import string
|
||||||
|
|
||||||
|
|
||||||
|
def parse(data):
|
||||||
|
output = []
|
||||||
|
|
||||||
|
linedata = data.splitlines()
|
||||||
|
|
||||||
|
# Clear any blank lines
|
||||||
|
cleandata = list(filter(None, linedata))
|
||||||
|
|
||||||
|
if cleandata:
|
||||||
|
|
||||||
|
for entry in cleandata:
|
||||||
|
output_line = {}
|
||||||
|
remainder = []
|
||||||
|
job_number = ''
|
||||||
|
pid = ''
|
||||||
|
job_history = ''
|
||||||
|
|
||||||
|
parsed_line = entry.split(maxsplit=2)
|
||||||
|
|
||||||
|
# check if -l was used
|
||||||
|
if parsed_line[1][0] in string.digits:
|
||||||
|
pid = parsed_line.pop(1)
|
||||||
|
remainder = parsed_line.pop(1)
|
||||||
|
job_number = parsed_line.pop(0)
|
||||||
|
remainder = remainder.split(maxsplit=1)
|
||||||
|
|
||||||
|
# rebuild parsed_line
|
||||||
|
parsed_line = []
|
||||||
|
|
||||||
|
for r in remainder:
|
||||||
|
parsed_line.append(r)
|
||||||
|
|
||||||
|
parsed_line.insert(0, job_number)
|
||||||
|
|
||||||
|
# check for + or - in first field
|
||||||
|
if parsed_line[0].find('+') != -1:
|
||||||
|
job_history = 'current'
|
||||||
|
parsed_line[0] = parsed_line[0].rstrip('+')
|
||||||
|
|
||||||
|
if parsed_line[0].find('-') != -1:
|
||||||
|
job_history = 'previous'
|
||||||
|
parsed_line[0] = parsed_line[0].rstrip('-')
|
||||||
|
|
||||||
|
# clean up first field
|
||||||
|
parsed_line[0] = parsed_line[0].lstrip('[').rstrip(']')
|
||||||
|
|
||||||
|
# create list of dictionaries
|
||||||
|
output_line['job_number'] = int(parsed_line[0])
|
||||||
|
if pid:
|
||||||
|
output_line['pid'] = int(pid)
|
||||||
|
if job_history:
|
||||||
|
output_line['history'] = job_history
|
||||||
|
output_line['status'] = parsed_line[1]
|
||||||
|
output_line['command'] = parsed_line[2]
|
||||||
|
|
||||||
|
output.append(output_line)
|
||||||
|
|
||||||
|
return output
|
80
jc/parsers/lsmod.py
Normal file
80
jc/parsers/lsmod.py
Normal file
@ -0,0 +1,80 @@
|
|||||||
|
"""jc - JSON CLI output utility lsmod Parser
|
||||||
|
|
||||||
|
Usage:
|
||||||
|
specify --lsmod as the first argument if the piped input is coming from lsmod
|
||||||
|
|
||||||
|
Example:
|
||||||
|
|
||||||
|
$ lsmod | jc --lsmod -p
|
||||||
|
[
|
||||||
|
{
|
||||||
|
"Module": "nf_nat_ipv4",
|
||||||
|
"Size": "14115",
|
||||||
|
"Used": "1",
|
||||||
|
"By": [
|
||||||
|
"iptable_nat"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"Module": "nf_nat",
|
||||||
|
"Size": "26583",
|
||||||
|
"Used": "3",
|
||||||
|
"By": [
|
||||||
|
"nf_nat_ipv4",
|
||||||
|
"nf_nat_ipv6",
|
||||||
|
"nf_nat_masquerade_ipv4"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"Module": "iptable_mangle",
|
||||||
|
"Size": "12695",
|
||||||
|
"Used": "1"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"Module": "iptable_security",
|
||||||
|
"Size": "12705",
|
||||||
|
"Used": "1"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"Module": "iptable_raw",
|
||||||
|
"Size": "12678",
|
||||||
|
"Used": "1"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"Module": "nf_conntrack",
|
||||||
|
"Size": "139224",
|
||||||
|
"Used": "7",
|
||||||
|
"By": [
|
||||||
|
"nf_nat",
|
||||||
|
"nf_nat_ipv4",
|
||||||
|
"nf_nat_ipv6",
|
||||||
|
"xt_conntrack",
|
||||||
|
"nf_nat_masquerade_ipv4",
|
||||||
|
"nf_conntrack_ipv4",
|
||||||
|
"nf_conntrack_ipv6"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
...
|
||||||
|
]
|
||||||
|
"""
|
||||||
|
|
||||||
|
|
||||||
|
def parse(data):
|
||||||
|
|
||||||
|
# code adapted from Conor Heine at:
|
||||||
|
# https://gist.github.com/cahna/43a1a3ff4d075bcd71f9d7120037a501
|
||||||
|
|
||||||
|
cleandata = data.splitlines()
|
||||||
|
headers = [h for h in ' '.join(cleandata[0].strip().split()).split() if h]
|
||||||
|
|
||||||
|
headers.pop(-1)
|
||||||
|
headers.append('By')
|
||||||
|
|
||||||
|
raw_data = map(lambda s: s.strip().split(None, len(headers) - 1), cleandata[1:])
|
||||||
|
output = [dict(zip(headers, r)) for r in raw_data]
|
||||||
|
|
||||||
|
for mod in output:
|
||||||
|
if 'By' in mod:
|
||||||
|
mod['By'] = mod['By'].split(',')
|
||||||
|
|
||||||
|
return output
|
117
jc/parsers/lsof.py
Normal file
117
jc/parsers/lsof.py
Normal file
@ -0,0 +1,117 @@
|
|||||||
|
"""jc - JSON CLI output utility lsof Parser
|
||||||
|
|
||||||
|
Usage:
|
||||||
|
specify --lsof as the first argument if the piped input is coming from lsof
|
||||||
|
|
||||||
|
Limitations:
|
||||||
|
No additional columns are supported
|
||||||
|
|
||||||
|
Example:
|
||||||
|
|
||||||
|
$ sudo lsof | jc --lsof -p
|
||||||
|
[
|
||||||
|
{
|
||||||
|
"COMMAND": "systemd",
|
||||||
|
"PID": "1",
|
||||||
|
"TID": null,
|
||||||
|
"USER": "root",
|
||||||
|
"FD": "cwd",
|
||||||
|
"TYPE": "DIR",
|
||||||
|
"DEVICE": "253,0",
|
||||||
|
"SIZE/OFF": "224",
|
||||||
|
"NODE": "64",
|
||||||
|
"NAME": "/"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"COMMAND": "systemd",
|
||||||
|
"PID": "1",
|
||||||
|
"TID": null,
|
||||||
|
"USER": "root",
|
||||||
|
"FD": "rtd",
|
||||||
|
"TYPE": "DIR",
|
||||||
|
"DEVICE": "253,0",
|
||||||
|
"SIZE/OFF": "224",
|
||||||
|
"NODE": "64",
|
||||||
|
"NAME": "/"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"COMMAND": "systemd",
|
||||||
|
"PID": "1",
|
||||||
|
"TID": null,
|
||||||
|
"USER": "root",
|
||||||
|
"FD": "txt",
|
||||||
|
"TYPE": "REG",
|
||||||
|
"DEVICE": "253,0",
|
||||||
|
"SIZE/OFF": "1624520",
|
||||||
|
"NODE": "50360451",
|
||||||
|
"NAME": "/usr/lib/systemd/systemd"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"COMMAND": "systemd",
|
||||||
|
"PID": "1",
|
||||||
|
"TID": null,
|
||||||
|
"USER": "root",
|
||||||
|
"FD": "mem",
|
||||||
|
"TYPE": "REG",
|
||||||
|
"DEVICE": "253,0",
|
||||||
|
"SIZE/OFF": "20064",
|
||||||
|
"NODE": "8146",
|
||||||
|
"NAME": "/usr/lib64/libuuid.so.1.3.0"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"COMMAND": "systemd",
|
||||||
|
"PID": "1",
|
||||||
|
"TID": null,
|
||||||
|
"USER": "root",
|
||||||
|
"FD": "mem",
|
||||||
|
"TYPE": "REG",
|
||||||
|
"DEVICE": "253,0",
|
||||||
|
"SIZE/OFF": "265600",
|
||||||
|
"NODE": "8147",
|
||||||
|
"NAME": "/usr/lib64/libblkid.so.1.1.0"
|
||||||
|
},
|
||||||
|
...
|
||||||
|
]
|
||||||
|
"""
|
||||||
|
|
||||||
|
|
||||||
|
def parse(data):
|
||||||
|
output = []
|
||||||
|
|
||||||
|
linedata = data.splitlines()
|
||||||
|
|
||||||
|
# Clear any blank lines
|
||||||
|
cleandata = list(filter(None, linedata))
|
||||||
|
|
||||||
|
if cleandata:
|
||||||
|
|
||||||
|
# find column value of last character of each header
|
||||||
|
header_row = cleandata.pop(0)
|
||||||
|
headers = header_row.split()
|
||||||
|
header_spec = []
|
||||||
|
|
||||||
|
for i, h in enumerate(headers):
|
||||||
|
# header tuple is (index, header_name, col)
|
||||||
|
header_spec.append((i, h, header_row.find(h) + len(h)))
|
||||||
|
|
||||||
|
# parse lines
|
||||||
|
for entry in cleandata:
|
||||||
|
output_line = {}
|
||||||
|
|
||||||
|
# normalize data by inserting Null for missing data
|
||||||
|
temp_line = entry.split(maxsplit=len(headers) - 1)
|
||||||
|
|
||||||
|
for spec in header_spec:
|
||||||
|
if spec[1] == 'COMMAND' or spec[1] == 'NAME':
|
||||||
|
continue
|
||||||
|
if entry[spec[2] - 1] == ' ':
|
||||||
|
temp_line.insert(spec[0], None)
|
||||||
|
|
||||||
|
name = ' '.join(temp_line[9:])
|
||||||
|
fixed_line = temp_line[0:9]
|
||||||
|
fixed_line.append(name)
|
||||||
|
|
||||||
|
output_line = dict(zip(headers, fixed_line))
|
||||||
|
output.append(output_line)
|
||||||
|
|
||||||
|
return output
|
2
setup.py
2
setup.py
@ -5,7 +5,7 @@ with open('README.md', 'r') as f:
|
|||||||
|
|
||||||
setuptools.setup(
|
setuptools.setup(
|
||||||
name='jc',
|
name='jc',
|
||||||
version='0.8.1',
|
version='0.9.1',
|
||||||
author='Kelly Brazil',
|
author='Kelly Brazil',
|
||||||
author_email='kellyjonbrazil@gmail.com',
|
author_email='kellyjonbrazil@gmail.com',
|
||||||
description='This tool serializes the output of popular command line tools to structured JSON output.',
|
description='This tool serializes the output of popular command line tools to structured JSON output.',
|
||||||
|
Reference in New Issue
Block a user