0

I have a program that generates constant output (hcitool lescan):

CC:41:00:4D:AA:AA Name1
CC:41:00:4D:AA:BB Name2
CC:41:00:4D:AA:CC Name3

I would like to parse this output in Python constantly, but after few seconds I want to kill the process. As it has to be terminated manually (by pressing CTRL-C), I cannot use subprocess.check_value(["prog"]). Also calling p = subprocess.Popen(["prog"], stdout=subprocess.PIPE) isn't good, as it orders Popen to read this to the EOF. Also, such call hangs the Python script.

My question is: How can I start a program in Python (can be limited to Linux environment) and terminate it after few seconds while gathering it's output (from stdout)?

Melon
  • 527
  • 1
  • 5
  • 26
  • can you check for special "control word" something like "quit"? – Vor Dec 16 '14 at 14:08
  • 1
    related: [Stop reading process output in Python without hang?](http://stackoverflow.com/a/4418891/4279) – jfs Dec 16 '14 at 15:29
  • calling `p = Popen(["prog"], stdout=PIPE)` DOES NOT order `Popen` to read until `EOF`. – jfs Dec 16 '14 at 15:31
  • @J.F.Sebastian Your link works like a charm. Could lock down this question and add reference to: http://stackoverflow.com/questions/4417962/stop-reading-process-output-in-python-without-hang – Melon Dec 17 '14 at 08:08

2 Answers2

0

Depending on what your program is doing, you could use a couple of methods.

The first one would be to put the process in a while loop and check for the MAC address in the lescan output file.

import os

tag = 0
while tag != "00:11:22:33:44:55":
    open("file.txt","w").close()
    os.system("hcitool lescan> file.txt"+" & pkill --signal SIGINT hcitool")
    f = open("file.txt","r")
    read = f.read()
    if "00:11:22:33:44:55" in read:
        print "found"
        tag = "00:11:22:33:44:55"
print "program finished"
os._exit(0)

The second solution would be if you are using lescan and hcidump at the same time.

import time
import os
import subprocess

d = subprocess.Popen(["sudo hcitool lescan --duplicates & sudo hcidump -w dump.txt"], stdout=subprocess.PIPE, stderr=subprocess.STDOUT, shell=True)
time.sleep(3)
dump = os.system("sudo hcidump -r dump.txt>scan.txt")
#read the file like the previous solution I shown you
print "program finished"
os._exit(0)

The best way I found to do this was to output your readings to a file and the scan the file for any specific thing your are looking for.

Comment back if you need anything specific, though I think I have covered your question.

Jonathan Davies
  • 853
  • 2
  • 12
  • 23
  • 1. your 1st solution with `os.system()` call kills `hcitool` *immediately*. It is not very useful. 2. I don't know what are you trying to achieve by using `hcidump` here but don't use `stdout=PIPE` unless you read from the pipe 3. Don't use `shell=True` unless you need it. 4. Remove `os._exit(0)`, it does the wrong thing here e.g., it doesn't flush stdout and it is unnecessary here. 5. [here're possible alternative solutions](http://stackoverflow.com/a/4418891/4279). – jfs Dec 16 '14 at 15:56
0

This should work as long as the subprocess you are running are continuously producing output. You can end it anytime with Ctrl-C.

(Incorporated J.F. Sebastian's sensible suggestions)

import subprocess

p = subprocess.Popen(['hcitool', 'lescan'],stdout=subprocess.PIPE,bufsize=1)

try:
    for line in iter(p.stdout.readline, ""):
        print line, # Do watever processing you want to do here
except KeyboardInterrupt:
    p.kill()

p.wait()
p.stdout.close()
Moose
  • 148
  • 1
  • 7
  • This is bad coding practice, @Melon clearly stated he wanted to have a timer and then for the program to stop, after a certain amount of seconds. MEANING, that the program should be AUTOMATED with NO keyboard input. – Jonathan Davies Dec 16 '14 at 15:10
  • That is not how I read his questions. I interpreted it as he wanted to be able to stop it after a few seconds. Maybe I misunderstood. Either way, I don't see what that has to do with coding practices. – Moose Dec 16 '14 at 15:17
  • Killing a program with CTRL-C is bad practice, all programs should be self-efficient and terminate at the right time. `os._exit(0)` quits any program after it has finished its processes, without the use of CTRL-C. @Moose – Jonathan Davies Dec 16 '14 at 15:21
  • You are not killing the Python program. It can happily continue to run. You are sending an interrupt, telling it to kill the subprocess. I can see lots of use for that. – Moose Dec 16 '14 at 15:31
  • @JonathanDavies: OP mistakenly thinks that `Ctrl-C` is mandatory to kill the child process in a few seconds. Therefore @Moose answer is (incorrect but) possible interpretation of the question – jfs Dec 16 '14 at 15:33
  • @Moose: 1. don't use `shell=True` and the list argument (drop `shell=True`). 2. use `print line,` (note: the trailing comma) to avoid doubling newlines. 3. Add `p.wait()` at the end, to avoid zombies. 4. Add `bufsize=1` -- [it might make a difference sometimes](http://stackoverflow.com/a/17698359/4279). 5. Add `p.stdout.close()` after the loop for proper cleanup. – jfs Dec 16 '14 at 15:36