pythonからシェルスクリプトを呼び出し、ロギングを使用してstdoutとstderrをファイルに書き込む方法を探しています。以下にコードを示します。
import logging
import tempfile
import shlex
import os
def run_Shell_command(command_line):
command_line_args = shlex.split(command_line)
logging.info('Subprocess: \"' + command_line + '\"')
process_succeeded = True
try:
process_output_filename = tempfile.mktemp(suffix = 'subprocess_tmp_file_')
process_output = open(process_output_filename, 'w')
command_line_process = subprocess.Popen(command_line_args,\
stdout = process_output,\
stderr = process_output)
command_line_process.wait()
process_output.close()
process_output = open(process_output_filename, 'r')
log_subprocess_output(process_output)
process_output.close()
os.remove(process_output_filename)
except:
exception = sys.exc_info()[1]
logging.info('Exception occured: ' + str(exception))
process_succeeded = False
if process_succeeded:
logging.info('Subprocess finished')
else:
logging.info('Subprocess failed')
return process_succeeded
そして、プロセス出力を保存する一時ファイルを作成せずにそれを行う方法があると確信しています。何か案は?
プロセス出力を保存する一時ファイルを作成せずにそれを行う方法があると確信しています
Popen
のドキュメント、特にstdout
とstderr
について確認するだけです。
stdin
、stdout
、およびstderr
は、実行されたプログラムの標準入力、標準出力、および標準エラーファイルハンドルをそれぞれ指定します。有効な値は、PIPE
、既存のファイル記述子(正の整数)、既存のファイルオブジェクト、およびNone
です。PIPE
は、子への新しいパイプを作成する必要があることを示します。None
のデフォルト設定では、リダイレクトは発生しません。子のファイルハンドルは親から継承されます。さらに、stderr
にはSTDOUT
を指定できます。これは、子プロセスからのstderr
データを、stdout
と同じファイルハンドルにキャプチャする必要があることを示します。
したがって、ファイルオブジェクトまたはPIPE
値を使用できることがわかります。これにより、 communicate()
メソッドを使用して出力を取得できます。
from StringIO import StringIO
process = subprocess.Popen(arguments, stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
output, error = process.communicate()
log_subprocess_output(StringIO(output))
コードを次のように書き直します。
import shlex
import logging
import subprocess
from StringIO import StringIO
def run_Shell_command(command_line):
command_line_args = shlex.split(command_line)
logging.info('Subprocess: "' + command_line + '"')
try:
command_line_process = subprocess.Popen(
command_line_args,
stdout=subprocess.PIPE,
stderr=subprocess.STDOUT,
)
process_output, _ = command_line_process.communicate()
# process_output is now a string, not a file,
# you may want to do:
# process_output = StringIO(process_output)
log_subprocess_output(process_output)
except (OSError, CalledProcessError) as exception:
logging.info('Exception occured: ' + str(exception))
logging.info('Subprocess failed')
return False
else:
# no exception was raised
logging.info('Subprocess finished')
return True
サブプロセスの出力全体をメモリにバッファリングせずに、パイプを直接渡そうとすることができます。
_from subprocess import Popen, PIPE, STDOUT
process = Popen(command_line_args, stdout=PIPE, stderr=STDOUT)
with process.stdout:
log_subprocess_output(process.stdout)
exitcode = process.wait() # 0 means success
_
log_subprocess_output()
は次のようになります。
_def log_subprocess_output(pipe):
for line in iter(pipe.readline, b''): # b'\n'-separated lines
logging.info('got line from subprocess: %r', line)
_