我正在尝试编写一个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