web-dev-qa-db-fra.com

Sortie du sous-processus Python3

Je souhaite exécuter l'utilitaire de comptage de mots Linux wc pour déterminer le nombre de lignes figurant actuellement dans/var/log/syslog, afin de pouvoir détecter sa croissance. J'ai essayé divers tests et, bien que je récupère les résultats de wc, ils incluent à la fois le nombre de lignes et la commande (par exemple, var/log/syslog). 

Alors ça retourne: 1338 /var/log/syslogMais je ne veux que le nombre de lignes, je veux donc supprimer la partie/var/log/syslog et ne garder que 1338.

J'ai essayé de le convertir en chaîne à partir de bytestring, puis de supprimer le résultat, mais pas de joie. Même histoire pour la conversion en chaîne et le stripping, le décodage, etc. - tous ne parviennent pas à produire le résultat recherché.

Voici quelques exemples de ce que je reçois, avec 1338 lignes dans syslog: 

  • b'1338/var/log/syslog\n '
  • 1338/var/log/syslog

Voici un code de test que j'ai écrit pour essayer de résoudre ce problème, mais pas de solution:

import subprocess

#check_output returns byte string
stdoutdata = subprocess.check_output("wc --lines /var/log/syslog", Shell=True)
print("2A stdoutdata: " + str(stdoutdata))
stdoutdata = stdoutdata.decode("utf-8")
print("2B stdoutdata: " + str(stdoutdata))    
stdoutdata=stdoutdata.strip()
print("2C stdoutdata: " + str(stdoutdata))    

La sortie de ceci est:

  • 2A stdoutdata: b'1338/var/log/syslog\n '

  • 2B stdoutdata: 1338/var/log/syslog

  • 2C stdoutdata: 1338/var/log/syslog

  • Stdoutdata 2D: 1338/var/log/syslog

31
user2565677

Je suggère que vous utilisiez subprocess.getoutput() car il fait exactement ce que vous voulez - lancez une commande dans un shell et obtenez son string output (par opposition à byte string output). Ensuite, vous pouvez diviser les espaces blancs et récupérer le premier élément de la liste de chaînes renvoyée.

Essaye ça:

import subprocess
stdoutdata = subprocess.getoutput("wc --lines /var/log/syslog")
print("stdoutdata: " + stdoutdata.split()[0])
53
Joseph Dunn

Pour éviter d'appeler un shell et de décoder des noms de fichiers pouvant être une séquence d'octets arbitraire (à l'exception de '\0') sur * nix, vous pouvez transmettre le fichier en tant que stdin:

import subprocess

with open(b'/var/log/syslog', 'rb') as file:
    nlines = int(subprocess.check_output(['wc', '-l'], stdin=file))
print(nlines)

Ou vous pouvez ignorer les erreurs de décodage:

import subprocess

stdoutdata = subprocess.check_output(['wc', '-l', '/var/log/syslog'])
nlines = int(stdoutdata.decode('ascii', 'ignore').partition(' ')[0])
print(nlines)
10
jfs

Depuis Python 3.6, vous pouvez demander à check_output() de renvoyer une str au lieu de bytes en lui attribuant un paramètre encoding :

check_output('wc --lines /var/log/syslog', encoding='UTF-8', Shell=True)
1
Curt J. Sampson

Équivalent à la réponse de Curt J. Sampson est également celle-ci (elle renvoie une chaîne):

subprocess.check_output('wc -l /path/to/your/file | cut -d " " -f1', universal_newlines=True, Shell=True)

de docs:

Si un codage ou des erreurs sont spécifiés ou si le texte est true, les objets de fichier pour .__ stdin, stdout et stderr s'ouvrent en mode texte à l'aide du fichier .__ spécifié. codage et erreurs ou la valeur par défaut de io.TextIOWrapper. Le L'argument universal_newlines est équivalent au texte et est fourni pour rétrocompatibilité. Par défaut, les objets de fichier sont ouverts en binaire mode.

Quelque chose de similaire, mais un peu plus complexe en utilisant subprocess.run ():

subprocess.run(command, Shell=True, check=True, universal_newlines=True, stdout=subprocess.PIPE).stdout

as subprocess.check_output () pourrait être équivalent à subprocess.run ().

1
Catalin B.