Reputation: 8031
I have a subprocess executing:
lshw -json -C network
If i receive the following back:
{
"id" : "network",
"class" : "network",
"claimed" : true,
"handle" : "PCI:0000:00:05.0",
"description" : "Ethernet interface",
"product" : "82545EM Gigabit Ethernet Controller (Copper)",
"vendor" : "Intel Corporation",
"physid" : "5",
"businfo" : "pci@0000:00:05.0",
"logicalname" : "eth0",
"version" : "00",
"serial" : "00:8c:42:77:58:49",
"units" : "bit/s",
"size" : 1000000000,
"capacity" : 1000000000,
"width" : 32,
"clock" : 66000000,
"configuration" : {
"autonegotiation" : "on",
"broadcast" : "yes",
"driver" : "e1000",
"driverversion" : "7.3.21-k8-NAPI",
"duplex" : "full",
"firmware" : "N/A",
"ip" : "10.211.55.10",
"latency" : "0",
"link" : "yes",
"multicast" : "yes",
"port" : "twisted pair",
"speed" : "1Gbit/s"
},
"capabilities" : {
"msi" : "Message Signalled Interrupts",
"bus_master" : "bus mastering",
"cap_list" : "PCI capabilities listing",
"ethernet" : true,
"physical" : "Physical interface",
"logical" : "Logical interface",
"tp" : "twisted pair",
"10bt" : "10Mbit/s",
"10bt-fd" : "10Mbit/s (full duplex)",
"100bt" : "100Mbit/s",
"100bt-fd" : "100Mbit/s (full duplex)",
"1000bt-fd" : "1Gbit/s (full duplex)",
"autonegotiation" : "Auto-negotiation"
}
},
Can i possibly iterate over this to ensure i capture all network interfaces (in the case that there's more than one) which is not the case with my system.. Also, how can i pick 1 or two from this output, i don't need the entire data.
I had the following in mind:
def get_nic_data():
lshw_cmd = "lshw -json -C network"
proc = subprocess.Popen(lshw_cmd, shell=True, stdout=subprocess.PIPE,
stdin=subprocess.PIPE)
return proc.stdout
def read_data(proc_output):
import simplejason as json
json_obj = json
json_obj.loads(proc_output)
#Obtain Vendor,Description,Product
#...
#...
json_obj.dumps(obtained_data_here)
#Not sure if this would work this way.
read_data(get_nic_data())
Upvotes: 3
Views: 6067
Reputation: 1123410
Unfortunately, you cannot combine -C
class filtering with -json
output; even in the latest version JSON output is severely broken. Instead, filter the full JSON output yourself. Note that you should avoid using shell=True
when using subprocess
, pass in a list instead; no need to pipe stdin either, but do capture (silence) stderr.
Then we can recurse over the 'children' structures, picking out anything that has a matching 'class'
key:
def get_nic_data():
lshw_cmd = ['lshw', '-json']
proc = subprocess.Popen(lshw_cmd, stdout=subprocess.PIPE,
stderr=subprocess.PIPE)
return proc.communicate()[0]
def find_class(data, class_):
for entry in data.get('children', []):
if entry.get('class') == class_:
yield entry
for child in find_class(entry, class_):
yield child
def read_data(proc_output, class_='network'):
import json
for entry in find_class(json.loads(proc_output), class_):
yield entry['vendor'], entry['description'], entry['product']
then loop over read_data(get_nic_data())
:
for vendor, description, product in read_data(get_nic_data()):
print vendor, description, product
Upvotes: 8
Reputation: 414585
If there are multiple network cards lshw
doesn't return a valid json text. It could be fixed by adding [
/ ]
before / after the output and adding ,
in between objects:
import json
import re
from subprocess import STDOUT, check_output as qx
# get command output
output = qx("lshw -json -C network".split(), stderr=STDOUT)
# get json parts
_, sep, json_parts = output.rpartition(b"\r")
if not sep: # no \r in the output
json_parts = output
# convert it to valid json list
jbytes = b"[" + re.sub(b"}( *){", b"}, {", json_parts) + b"]"
L = json.loads(jbytes.decode())
# pretty print
import sys
json.dump(L, sys.stdout, indent=4)
A cleaner solution would use lshw -xml
that produces output that could be easily converted to a well-formed xml by wrapping it in a root element: '<root>'
+ output + '</root>'
.
Upvotes: 0