Dee
Dee

Reputation: 61

'Popen' object not Iterable

I am trying to fetch some Ids into a list via the subprocess command. Below is my code:

list1=[]
list2=[]
list1 = subprocess.Popen("pgrep -u root",stdout=subprocess.PIPE, shell = True)
for i in list1:
    file1 = open(os.path.join('/proc',i,'status')).readlines()
    for line in file1:
        if line.startswith("Mem: "):
             id = int(line.split()[5])
        if line.startswith("Cpu: "):
             toC = int(line.split()[8])
list2 = (id,toC)
for k in list2:
    self.text.insert(INSERT,k[0])
    self.text.insert(INSERT,k[1])

The error that i get is: 'Popen'object not iterable. I am creating a list and fetching the IDs into a list and then for every ID in the list, I am trying to get the mem and cpu information. this information is again input into another empty list(list2). I am iterating over list2 to display these information. Where am I going wrong?

Upvotes: 1

Views: 11734

Answers (3)

Ryan Haining
Ryan Haining

Reputation: 36822

If you want the result of the call you'll need to communicate with the subprocess object

proc = subprocess.Popen(['pgrep', '-u', 'root'], stdout=subprocess.PIPE)
text = proc.communicate()[0].decode('utf-8')

for i in text.splitlines():
    ...

The Popen object is not the output of the process, it is an object that represents the running subprocess.

Also avoid shell=True if you can as it is widely considered a security concern, and you don't need it here.

Upvotes: 6

ShadowRanger
ShadowRanger

Reputation: 155438

For this scenario (where you're only reading stdout and stdin/stderr are untouched), you probably don't want .communicate or .run. It's easier to process the lines as they're produced, which those APIs don't do (they buffer everything into memory before returning).

To process the output line by line, just change:

for i in list1:

to:

for i in list1.stdout:

In addition, you've got a problem with types on Python 3; to fix that (and avoid the problems with shell=True) change the Popen line to:

list1 = subprocess.Popen(['pgrep', '-u', 'root'], stdout=subprocess.PIPE, universal_newlines=True)

where universal_newlines=True makes reads from list1.stdout return str, not bytes.

Upvotes: 1

gerrit
gerrit

Reputation: 26505

Calling subprocess.Popen yields a Popen object. It does not give you a list and it does not give you something you can iterate over, because the Popen object is not iterable.

It is easier to use a higher level function from the same library to get the output as a string, then parse this and loop accordingly. In Python 3.5, you can simply call subprocess.run:

res = subprocess.run(["pgrep", "-u", "root"], stdout=subprocess.PIPE)

which will give you a CompletedProcess object from where you can inspect the output.

In Python 3.4 or earlier, you can instead use check_output.

Upvotes: 0

Related Questions