私は次のようにサブプロセスのラッパーを実装しようとしている:バッファなしのPython Subrocess PIPE
def ans_cmd_stream_color(inputcmd):
"""Driver function for local ansible commands.
Stream stdout to stdout and log file with color.
Runs <inputcmd> via subprocess.
Returns return code, stdout, stderr as dict.
"""
fullcmd = inputcmd
create_debug('Enabling colorful ansible output.', LOGGER)
create_info('Running command: ' + fullcmd, LOGGER, True)
p = subprocess.Popen('export ANSIBLE_FORCE_COLOR=true; ' + fullcmd,
stdout=subprocess.PIPE,
stderr=subprocess.PIPE,
shell=True)
stdout_l = []
stderr_l = []
rcode = 0
# Regex black magic
ansi_escape = re.compile(r'\x1b[^m]*m')
# Get the unbuffered IO action going.
try:
# Non blocking
reads = [p.stdout.fileno(), p.stderr.fileno()]
ret = select.select(reads, [], [])
# Print line by line
while True:
for fd in ret[0]:
if fd == p.stdout.fileno():
line = p.stdout.readline()
sys.stdout.write(line.encode('utf-8'))
stdout_l.append(ansi_escape.sub('',
line.encode('utf-8'))
)
if fd == p.stderr.fileno():
line = p.stdout.readline()
sys.stderr.write(line.encode('utf-8'))
stderr_l.append(ansi_escape.sub('',
line.encode('utf-8'))
)
# Break when the process is done.
if p.poll() is not None:
rcode = p.returncode
break
except BaseException as e:
raise e
outstr = ''.join(stdout_l)
errstr = ''.join(stderr_l)
outstr, errstr = str(outstr).rstrip('\n'), str(errstr).rstrip('\n')
expstr = errstr.strip('ERROR: ')
if len(expstr) >= 1:
create_info('Command: ' + str(fullcmd) + ': ' + expstr + '\n', LOGGER,
True)
if rcode == 0:
rcode = 1
else:
create_info(outstr + '\n', LOGGER)
if rcode == 0:
create_info('Command: ' + fullcmd + ' ran successfully.', LOGGER,
True)
expstr = False
ret_dict = {inputcmd: {}}
ret_dict[inputcmd]['rcode'] = rcode
ret_dict[inputcmd]['stdout'] = outstr
ret_dict[inputcmd]['stderr'] = expstr
return copy.deepcopy(ret_dict)
アイデアは、サブプロセスコマンドのストリーミング出力を印刷して、関数、ユーザーに情報を返すことです。問題は、私は設定しない限りさえ直接io.openを使用して、サブプロセスのPIPがまだバッファリングされていることである。
理想的ではありませんos.environ["PYTHONUNBUFFERED"] = "1"
。任意のアイデアや誰かがこの問題に遭遇しましたか?
UPDATEは:ansibleを使用すると、バッファリング設定を称えるためにサブプロセスのためのバッファリングを無効にする必要があります:あなたはおそらく、直接サブプロセスのパイプから読むべき
def ans_cmd_stream_color(inputcmd):
"""Driver function for local ansible commands.
Stream stdout to stdout and log file with color.
Runs <inputcmd> via subprocess.
Returns return code, stdout, stderr as dict.
"""
fullcmd = inputcmd
create_debug('Enabling colorful ansible output.', LOGGER)
create_info('Running command: ' + fullcmd, LOGGER, True)
p = subprocess.Popen('export ANSIBLE_FORCE_COLOR=true; ' +
'export PYTHONUNBUFFERED=1; ' + fullcmd,
stdout=subprocess.PIPE,
stderr=subprocess.PIPE,
shell=True)
stdout_l = []
stderr_l = []
rcode = 0
# Regex black magic
ansi_escape = re.compile(r'\x1b[^m]*m')
# Get the unbuffered IO action going.
try:
# Non blocking
reads = [p.stdout.fileno(), p.stderr.fileno()]
ret = select.select(reads, [], [])
# Print line by line
while True:
for fd in ret[0]:
if fd == p.stdout.fileno():
line = p.stdout.readline()
sys.stdout.write(line.encode('utf-8'))
stdout_l.append(ansi_escape.sub('',
line.encode('utf-8'))
)
if fd == p.stderr.fileno():
line = p.stdout.readline()
sys.stderr.write(line.encode('utf-8'))
stderr_l.append(ansi_escape.sub('',
line.encode('utf-8'))
)
# Break when the process is done.
if p.poll() is not None:
rcode = p.returncode
break
except BaseException as e:
raise e
outstr = ''.join(stdout_l)
errstr = ''.join(stderr_l)
outstr, errstr = str(outstr).rstrip('\n'), str(errstr).rstrip('\n')
expstr = errstr.strip('ERROR: ')
if len(expstr) >= 1:
create_info('Command: ' + str(fullcmd) + ': ' + expstr + '\n', LOGGER,
True)
if rcode == 0:
rcode = 1
else:
create_info(outstr + '\n', LOGGER)
if rcode == 0:
create_info('Command: ' + fullcmd + ' ran successfully.', LOGGER,
True)
expstr = False
ret_dict = {inputcmd: {}}
ret_dict[inputcmd]['rcode'] = rcode
ret_dict[inputcmd]['stdout'] = outstr
ret_dict[inputcmd]['stderr'] = expstr
return copy.deepcopy(ret_dict)
1解決策を質問に入れないで、代わりに回答として投稿する(コメントを付けることができ、解決策に投票する)。コード内の '' select() '呼び出しがブロックされています。 'select()'ループは簡単です[コマンドを実行して、端末のようにほぼリアルタイムでstdout、stderrを別々に取得する](http://stackoverflow.com/a/31953436/4279)。 stdout/stderrをマージしても問題が解決しない場合は、[コードはさらに簡単になります](http://stackoverflow.com/a/17698359/4279)。 3-任意のサブプロセスで*内部バッファ*のバッファを解除する方法を尋ねていますか? (普通の場合は不可能ですが、 '-u'は' python'のために働きますが) – jfs
は関係ありません:子にenvvarを渡すには 'Popen(...、env = dict(os.environ、ANSIBLE_FORCE_COLOR = ' true '、PYTHONUNBUFFERED =' 1 '))' – jfs