我正在嘗試編寫一個python腳本,通過Arduino的命令行界面來並行編譯和上傳同一個hex文件給多個微控制器。Python子流程:用subprocess.Popen並行執行復制Tee?
我的腳本執行以下操作:
- 編譯鮑文件爲十六進制文件在一個特定的目錄中。例如,
- 將十六進制上傳到所有/dev/tty.usbXXXXXX。
這些要求:
- 我必須能夠上傳到多個/dev/tty.usb*並行。
- 我想打印全部來自我所有的subprocess.Popen的輸出和錯誤到我的主屏幕設備 - STDOUT/STDERR - 味精作爲格式
- 我想從每個POPEN標準輸出和標準錯誤保存到自己的tty.usb *日誌文件。
現在我得:
import errno
import os
import re
import subprocess
ARDUINO_EXECUTABLE = '/Applications/Arduino.app/Contents/MacOS/JavaApplicationStub'
HEX_FOLDER_DIR = '/tmp/oyoroi'
LOG_FOLDER_DIR = './logs'
def get_devices():
"""Returns a list of tty.usbXXXXXX
Make sure you use the USB hub. This will force an extra character in the /dev/tty.usbXXXXXX
"""
ret = []
for device in os.listdir('/dev'):
if re.match('tty.usbmodem[0-9]{6}', device):
ret.append(device)
return ret
class Wrapper(object):
"""Wrapper for file objects
"""
def __init__(self, name, fobject):
self.name = name
self.fobject = fobject
def fileno(self):
return self.fobject.fileno()
def flush(self):
self.fobject.flush()
def write(self, a_str):
print self.name, a_str
self.fobject.write(a_str)
def main(fname):
"""Build once, but upload in parallel
"""
try:
os.makedirs(HEX_FOLDER_DIR)
except OSError as exc:
if exc.errno == errno.EEXIST and os.path.isdir(HEX_FOLDER_DIR):
pass
fname = os.path.abspath(fname)
# Builds the hex
command = "%s --verify --pref build.path=%s %s" % (ARDUINO_EXECUTABLE, HEX_FOLDER_DIR, fname)
print "(Build Command)", command
proc = subprocess.call(command, shell=True)
# Make the log directory
try:
os.makedirs(LOG_FOLDER_DIR)
except OSError as exc:
if exc.errno == errno.EEXIST and os.path.isdir(LOG_FOLDER_DIR):
# delete folder
import shutil
shutil.rmtree(LOG_FOLDER_DIR)
# and recreate again
os.makedirs(LOG_FOLDER_DIR)
# Upload in parallel
devices = get_devices()
processes = []
for device in devices:
device_path = '/dev/' + device
log_file_path = os.path.join(LOG_FOLDER_DIR, device + '.log')
with open(log_file_path, 'a') as logfile:
command = "%s --upload --pref build.path=%s --port %s %s" % \
(ARDUINO_EXECUTABLE, HEX_FOLDER_DIR, device_path, fname)
print "(Upload Command)", command
wstdout = Wrapper('%_STDOUT', logfile)
wstderr = Wrapper('%_STDERR', logfile)
proc = subprocess.Popen(command, shell=True, stdout=wstdout, stderr=wstderr)
processes.append(proc)
if __name__ == "__main__":
import sys
if len(sys.argv) != 2:
print "python upload.py <.ino>"
exit(1)
main(sys.argv[1])
我能夠得到我想要在每個日誌文件,但我的終端不打印屏幕上的任何內容。在其他過程完成之前它也結束了。
我錯過了什麼?
'stdout = wstdout'不正確。 'subprocess.Popen()'不接受類似文件的對象(除了'.fileno()'以外的所有Wrapper方法在你的情況下被忽略,這就是爲什麼你什麼都看不到 - 沒有任何內容被打印出來('print self .name,a_str'不被調用))。它需要一個真實的文件(真實文件描述符)。請參閱[如何實現使用多線程的teed_call()](http://stackoverflow.com/a/4985080/4279)。這裏是[如何獨立收集stdout/stderr並將其打印到單個線程中的控制檯](http://stackoverflow.com/a/25960956/4279)。 – jfs 2014-10-29 16:07:28