Je cherche le moyen d'appeler des scripts Shell depuis python et d'écrire leur stdout et stderr dans un fichier en utilisant la journalisation. Voici mon code:
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
Et je suis sûr qu'il existe un moyen de le faire sans créer de fichier temporaire pour stocker la sortie du processus. Des idées?
Je suis sûr qu'il existe un moyen de le faire sans créer de fichier temporaire pour stocker la sortie du processus
Il vous suffit de vérifier la documentation de Popen
, en particulier sur stdout
et stderr
:
stdin
,stdout
etstderr
spécifient respectivement les descripteurs d'entrée, de sortie standard et de fichier d'erreur standard du programme exécuté. Les valeurs valides sontPIPE
, un descripteur de fichier existant (un entier positif), un objet fichier existant etNone
.PIPE
indique qu'un nouveau canal vers l'enfant doit être créé. Avec les paramètres par défaut deNone
, aucune redirection ne se produira; les descripteurs de fichiers de l'enfant seront hérités du parent. De plus,stderr
peut êtreSTDOUT
, ce qui indique que les donnéesstderr
du processus enfant doivent être capturées dans le même descripteur de fichier que pourstdout
.
Ainsi, vous pouvez voir que vous pouvez utiliser un objet fichier ou la valeur PIPE
. Cela vous permet d'utiliser la méthode communicate()
pour récupérer la sortie:
from StringIO import StringIO
process = subprocess.Popen(arguments, stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
output, error = process.communicate()
log_subprocess_output(StringIO(output))
Je réécrirais votre code comme:
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
Vous pouvez essayer de passer le canal directement sans mettre en mémoire tampon la sortie entière du sous-processus en mémoire:
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
où log_subprocess_output()
pourrait ressembler à:
def log_subprocess_output(pipe):
for line in iter(pipe.readline, b''): # b'\n'-separated lines
logging.info('got line from subprocess: %r', line)