14

Here's the code:

inputDomain = subprocess.Popen("cat /etc/localdomains", shell=True,  stdout=subprocess.PIPE)
domains = inputDomain.stdout.read().splitlines()

for domain in domains:
   cmd = "whmapi1 domainuserdata domain " + domain
   output = subprocess.Popen(cmd, shell=True, stdout=subprocess.PIPE)
   jsonS = json.dumps(output.communicate())
   print json.loads(jsonS)['data']

here's there error

root@server [~/testP]# python copie.py Traceback (most recent call last): File "copie.py", line 18, in print json.loads(jsonS)['data'] TypeError: list indices must be integers, not str

and this is an example of the json i need to parse:

{ 
   "data":{ 
      "userdata":{ 
      "phpopenbasedirprotect":1,
      "options":"ExecCGI Includes",
     "ip":"10.0.0.1",
     "hascgi":"1",
     "group":"user",
     "usecanonicalname":"Off",
     "scriptalias":[ 
        { 
           "url":"/cgi-bin/",
           "path":"/home/user/public_html/cgi-bin"
        },
        { 
           "url":"/cgi-bin/",
           "path":"/home/user/public_html/cgi-bin/"
        }
     ],
     "user":"user",
     "ifmodulemodsuphpc":{ 
        "group":"user"
     },
     "owner":"root",
     "documentroot":"/home/user/public_html",
     "userdirprotect":"",
     "serveralias":"parkeddomain.com www.parkeddomain.com www.example.com",
     "port":"80",
     "homedir":"/home/user",
     "ifmoduleconcurrentphpc":{ 

     },
     "customlog":[ 
        { 
           "target":"/usr/local/apache/domlogs/example.com",
           "format":"combined"
        },
        { 
           "target":"/usr/local/apache/domlogs/example.com-bytes_log",
           "format":"\"%{%s}t %I .\\n%{%s}t %O .\""
        }
     ],
     "servername":"example.com",
     "serveradmin":"[email protected]"
  }
}

So i need the user and the domaine, but python always answer that i need a int. Thanks for the help guys.

6
  • are you sure jsonS is not a list? in which case you'd have to do json.loads(jsonS)[0]['data'] Commented Feb 10, 2017 at 14:26
  • and what the hell with inputDomain = subprocess.Popen("cat /etc/localdomains", shell=True, stdout=subprocess.PIPE)? python can read text files without the need of calling cat !! Commented Feb 10, 2017 at 14:27
  • yes i already try this.. it give me the same error... Commented Feb 10, 2017 at 14:28
  • You'r right jf i can change that, but that is not the problem for now.. Commented Feb 10, 2017 at 14:31
  • just print(type(jsonS)) just to see the type Commented Feb 10, 2017 at 14:35

3 Answers 3

11

I had problems running the above under Python3, so here is a way to achieve what OP is asking in Python3

import subprocess
import json


def getProcessOutput(cmd):
    process = subprocess.Popen(
        cmd,
        shell=True,
        stdout=subprocess.PIPE)
    process.wait()
    data, err = process.communicate()
    if process.returncode is 0:
        return data.decode('utf-8')
    else:
        print("Error:", err)
    return ""


for domain in getProcessOutput("cat /etc/localdomains").splitlines():
    cmd = "whmapi1 domainuserdata domain " + domain
    print(json.loads(getProcessOutput(cmd))['data'])

It outputs Error: None because my machine doesn't have /etc/localdomains but otherwise it seems to work just fine.

Sign up to request clarification or add additional context in comments.

2 Comments

It should be noted that this is awful code. It seemed to work, but it lacks tests, and couples the success and error into a method, in a way I'm not comfortable with. Something like JavaScript style promises would make me a lot happier for this.
Works for any code, no need for a "data" key in your output of the run CLI command, any command you run can be mapped to the data, err. The data, err = process.communicate() runs the CLI command, the output then is in data, which you then can check as a json object. For example, to get the message content of the chatbot answer from curl, run print(json.loads(data)['choices'][0]['message']['content']). see How can I open a licensed GPT chat like on https://chat.openai.com/ on my own user if I have an API key that is not from my user?.
8

since your process returns a json string, there's no need to dump it to load it again.

# stdout, stderr
jsonS,_ = output.communicate()

now you have a string, that you can load using json

d = json.loads(jsonS)

now d['data'] yields the info you want

Aside: as I said:

inputDomain = subprocess.Popen("cat /etc/localdomains", shell=True,  stdout=subprocess.PIPE)
domains = inputDomain.stdout.read().splitlines()

could be replaced by native python:

with open("/etc/localdomains") as f: domains = f.read().splitlines()

14 Comments

Hi thanks but i already try tho, this is the error i got when i do this..TypeError: expected string or buffer So its not a string.. its kinda strange
can you type jsonS,_ = output.communicate(), then print(jsonS)
just did output = subprocess.Popen(cmd, shell=True, stdout=subprocess.PIPE) jsonS,_ = output.communicate() print json.loads(jsonS) --> ValueError: No JSON object could be decoded
just print(jsonS) don't try to loads.
ican print it i see the value its like a tuple
|
2

communicate() returns a tuple: (stdoutdata, stderrdata). when you loads() it back you get a list, and then trying to index it with 'data' will fail. Example:

import json
import subprocess

cmd = "/bin/date"
output = subprocess.Popen(cmd, shell=True, stdout=subprocess.PIPE)
jsonS = json.dumps(output.communicate())
print jsonS # ["Fri Feb 10 14:33:42 GMT 2017\n", null]
print json.loads(jsonS)['data'] # TypeError: list indices must be integers, not str

It might be enough to do

jsonS = output.communicate()[0]

6 Comments

it give me back ValueError: No JSON object could be decoded
Ok. Stick a print on the jsonS to see whether the data actually is a JSON.
it says that jsonS is a tuple
I meant, after you make the change Jean and I suggested, to take the first element of the return value of communicate().
'data' = output.communicate()[0]
|

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.