2017-10-13 5 views
0

J'utilise speedtest-cli pour obtenir ma vitesse Internet dans un script python. Je voudrais exécuter cette commande dans le shell via subprocess.Popen.Commande de tuyauterie avec plusieurs sorties distinctes dans le fichier

Voici la commande dans le terminal:

`speedtest-cli --share > output.log` 

speedtest-cli exécute le test, tandis que --share me fournit un lien supplémentaire dans la sortie, pointant vers une image du résultat speedtest. Voici le contenu de output.log:

Récupération configuration speedtest.net ... Test de M-net (xxx.xxx.xxx.xxx) ... Récupération liste des serveurs speedtest.net ... Sélection du meilleur serveur basé sur le ping ... Hébergé par XXXXXXXXXXXXXXXXXXXXXX [16.12 km]: 20.902 ms Test de la vitesse de téléchargement .......................... .................................................. .... Téléchargement: 48.32 Mbit/s Test de la vitesse de téléchargement ................................... .................................................. ................. Télécharger: 12.49 Mbit/s Partager les résultats: http://www.speedtest.net/result/670483456.png

Si j'exécute la commande dans le terminal, j'obtiens tous les résultats du test ainsi que le lien dans le fichier cible comme prévu. Je confirme qu'il est tout stdout et pas un autre canal en utilisant ce grep trick: command | grep .

Je suis en train de l'exécuter en Python comme suit:

subprocess.Popen(['speedtest-cli', '--share', '>', 'output.log`], 
        stdout=subprocess.PIPE, shell=True) 

... et j'ai aussi essayé de mettre la sortie dans la fichier directement via python:

with open('output.log', 'w') as f: 
    Popen(['speedtest-cli', '--json', '--share'], stdout=f, shell=True) 

Aucune de ces méthodes ne fonctionne. Je reçois un joli fichier créé avec cette dernière approche, MAIS le lien n'est pas inclus! (la dernière ligne de la sortie ci-dessus).

contre tous les avertissements de sécurité et une meilleure deprecation avec l'aide du module subprocess, je suis devenu desparate et essayé os.system():

os.system('speedtest-cli --share > output.log') 

Fâcheusement, cela fonctionne ... la sortie complète ainsi que le lien est capturé dans la fichier.

Que se passe-t-il ici? Comment puis-je obtenir le lien à capturer en utilisant Popen?

J'utilise Python 3.5

Répondre

2

Lorsque vous utilisez shell=True, votre argument Popen doit être une chaîne , pas une liste:

subprocess.Popen('speedtest-cli --json --share > output.log', 
       stdout=subprocess.PIPE, shell=True) 

Comparez:

>>> subprocess.Popen('echo hello', shell=True) 
>>> hello 

Et:

>>> subprocess.Popen(['echo', 'hello'], shell=True) 
>>> 

Quand vous passez une liste et yo Vous utilisez shell=True, seul le premier élément est pertinent et le reste est ignoré.

Si vous voulez récupérer la sortie vous-même, pensez à subprocess.check_output:

>>> output = subprocess.check_output(['echo', 'hello']) 
>>> output 
b'hello\n' 

Ou:

>>> output = subprocess.check_output('echo hello', shell=True) 

La méthode check_output fonctionne avec Python 2 et Python 3. En Python 3, vous aussi avoir à disposition la méthode run.

+0

Merci - J'ai simplement besoin de créer une seule chaîne. Dans votre premier exemple de code, vous avez la chaîne unique en tant que liste, qui ne fonctionne pas alors - devrait-elle être corrigée? –

+0

En fait, cela fonctionne bien ("... seulement le premier élément est pertinent et le reste est ignoré ... "), mais c'était une faute de frappe et je l'ai corrigé – larsks

+0

shell = True est un cauchemar de sécurité, donc il est recommandé d'utiliser shell = False et de passer une liste de paramètres (ce n'est pas un problème de sécurité). cas, car il n'est exploitable que si un attaquant peut contrôler l'un des paramètres, mais il vaut mieux l'éviter) – user9876