0

I have a problem with sub-process code. The subprocess.Popen() works fine but when I try to read its output through stdout.read() there is no value to read.

**import os
import signal
import subprocess
import threading
import sys
import commands

print commands.getoutput("hcitool dev")
print 'down'
commands.getoutput('hciconfig hci1 down')
print 'up'
commands.getoutput('hciconfig hci1 up')
commands.getoutput('killall hcitool')
stop = False
ping = subprocess.call('hcitool lescan', shell = False,
stdout=subprocess.PIPE,executable='/bin/bash')
for i in ping.stdout:
    print i

def kill():
    global stop
    stop = True
    os.kill(ping.pid, signal.SIGTERM)

threading.Timer(5, kill).start()

#while not stop:
#   print 'now in while not loop'
#   sys.stdout.write(ping.stdout.read(1))

print 'trying to print stdout'
out, err = ping.communicate()
print "out",out

#result = out.decode()

print "Result : ",result**

This code works fine when I change hcitool lescan to ping www.google.com, and produces output but when I try with hcitool lescan it either hangs forever or produces no output. Help is appreciated!

Vivek Jain
  • 3,811
  • 6
  • 30
  • 47
  • related: [Stop reading process output in Python without hang?](http://stackoverflow.com/q/4417962/4279) – jfs Sep 05 '13 at 12:21

4 Answers4

5

Any of the above answers didn't work for me. Was hung up in the forever scan of hcitool. So finally i wrote a shell script and called it by my python code. This is working fine for me and i am reading the output from the file "result.txt".

hcitool lescan>result.txt &  
sleep 5  
pkill --signal SIGINT hcitool
Piyush Verma
  • 200
  • 2
  • 8
0

There are multiple errors in your code e.g., subprocess.call() returns an integer (exit status of the program) and an integer has no .stdout attribute; also the combination of shell=False and non-None executable is very rarely useful (and it is probably used incorrectly in this case).

The simplest way to fix the code is to use check_output():

from subprocess import check_output as qx

output = qx(["hcitool", "lescan"]) # get all output at once
print output,

As an alternative, you could print program's output line by line as soon as its stdout is flushed:

from subprocess import Popen, PIPE

proc = Popen(["hcitool", "lescan"], stdout=PIPE, bufsize=1) # start process
for line in iter(proc.stdout.readline, b''): # read output line-by-line
    print line,
# reached EOF, nothing more to read
proc.communicate() # close `proc.stdout`, wait for child process to terminate
print "Exit status", proc.returncode

To kill a subprocess, you could use its .kill() method e.g.:

from threading import Timer

def kill(process):
    try:
        process.kill()
        process.wait() # to avoid zombies
    except OSError: # ignore errors
        pass 

Timer(5, kill, [proc]).start() # kill in 5 seconds
jfs
  • 399,953
  • 195
  • 994
  • 1,670
  • thank you for ans,your first method do not work,because [hcitool lescan] has never-lasting output,i.e it's a infinite loop and first line produces error:as hcitool lescan returned exit status 1: – Moinakhtar Salman Sep 05 '13 at 10:41
  • @MoinakhtarSalman: Only one of the two can be true at the same time: either "hcitool lescan" has never-lasting output or it ends with the exit status `1`. What results do you get with the second code example if you add `Timer(5, kill, [proc]).start()` before `for line in iter(proc.stdout.readline, b''):` line? – jfs Sep 05 '13 at 12:20
  • @sebastian.second code work's perfect.as i mentioned,check out my ans below. – Moinakhtar Salman Sep 08 '13 at 12:34
  • @MoinakhtarSalman: if you want the first 30 lines of child's output instead of killing it on timeout then you could use `first30lines = list(islice(iter(proc.stdout.readline, b''), 30)); kill(proc)` – jfs Sep 08 '13 at 16:18
0

thank you very much..but the problem is hcitool lescan never stops,and hence hangs out in the very next line of your code., and i found similar solution here it is.this works fine and i dont have to kill subprocess,this code takes some extra time to pour output,but this following code works preciesly,

from os import kill
import signal
import subprocess
import threading
import tempfile
import sys
import time
from tempfile import TemporaryFile
import commands
t = TemporaryFile()
global pipe_output
print commands.getoutput("hcitool dev")
print 'down'
commands.getoutput('hciconfig hci0 down')
print 'up'
commands.getoutput('hciconfig hci0 up')
print commands.getoutput("hcitool dev")
commands.getoutput('killall hcitool')
p = subprocess.Popen('hcitool lescan', bufsize = 0,shell = True, stdout =subprocess.PIPE,stderr = subprocess.STDOUT)
time.sleep(10)
#os.kill(p.pid,signal.SIGTERM)
for i in range(0,30,1):
    print 'for'
    inchar = p.stdout.readline()
    i+=1
    if inchar:
        print 'loop num:',i
        print str(inchar)
        t.write(str(inchar))
print 'out of loop'
t.seek(0)
print t.read()

any help how to reduce waiting time,other than just changing time.sleep() ,is appreciated thank you all

  • don't ask additional questions in the answer; you could update your question, ask a new one instead. See [Python subprocess readlines() hangs](http://stackoverflow.com/q/12419198) to fix the delay in the output. Note: `time.sleep(10)` is useless here; `p.stdout.readline()` blocks until something is available by default. – jfs Sep 08 '13 at 16:25
0

Use Popen class instead of the call class. hcitool lescan will run forever. subprocess.call waits for the call to be finished to return. Popen does not wait.

peteey
  • 420
  • 4
  • 14