web-dev-qa-db-fra.com

Python utilisation des caractères génériques du sous-processus

import os

import subprocess

proc = subprocess.Popen(['ls','*.bc'], stdout=subprocess.PIPE, stderr=subprocess.PIPE)

out,err = proc.communicate()

print out

Ce script devrait imprimer tous les fichiers avec le suffixe .bc mais il renvoie une liste vide. Si je fais ls * .bc manuellement dans la ligne de commande, cela fonctionne. Faire ['ls', 'test.bc'] à l'intérieur du script fonctionne également mais pour une raison quelconque, le symbole étoile ne fonctionne pas. Des idées?

57
Cemre

Vous devez fournir Shell=True pour exécuter la commande via un interpréteur Shell. Si vous le faites cependant, vous ne pouvez plus fournir de liste comme premier argument, car les arguments seront alors cités. Au lieu de cela, spécifiez la ligne de commande brute telle que vous souhaitez la transmettre au shell:

 proc = subprocess.Popen('ls *.bc', Shell=True,
                                    stdout=subprocess.PIPE,
                                    stderr=subprocess.PIPE)
68
Niklas B.

Extension du * glob fait partie du Shell, mais par défaut subprocess n'envoie pas vos commandes via un Shell, donc la commande (d'abord , ls) est exécuté, puis un littéral * est utilisé comme argument.

C'est une bonne chose, voir le bloc d'avertissement dans la section "Arguments fréquemment utilisés" , des documents du sous-processus. Il discute principalement des implications de sécurité, mais peut également aider à éviter des erreurs de programmation idiotes (car il n'y a pas de caractères magiques de Shell à craindre)

Ma principale plainte avec Shell=True est-ce que cela implique généralement qu'il existe une meilleure façon de résoudre le problème - avec votre exemple, vous devez utiliser le module glob :

import glob
files = glob.glob("*.bc")
print files # ['file1.bc', 'file2.bc']

Ce sera plus rapide (pas de surcharge de démarrage du processus), plus fiable et multiplateforme (ne dépend pas de la plate-forme ayant une commande ls)

56
dbr