web-dev-qa-db-fra.com

Pipe la sortie standard du sous-processus vers une variable

Je souhaite exécuter une commande dans pythong à l'aide du module de sous-processus et stocker le résultat dans une variable. Cependant, je ne souhaite pas que la sortie de la commande soit imprimée sur le terminal. Pour ce code:

def storels():
   a = subprocess.Popen("ls",Shell=True)
storels()

Je reçois la liste des répertoires dans le terminal, au lieu de la stocker dans a. J'ai aussi essayé:

 def storels():
       subprocess.Popen("ls > tmp",Shell=True)
       a = open("./tmp")
       [Rest of Code]
 storels()

Ceci affiche également la sortie de ls sur mon terminal. J'ai même essayé cette commande avec la méthode un peu datée de os.system, depuis l'exécution de ls > tmp dans le terminal n’imprime pas ls sur le terminal, mais le stocke dans tmp. Cependant, la même chose se passe.

Edit:

J'obtiens l'erreur suivante après avoir suivi les conseils de marcog, mais uniquement lors de l'exécution d'une commande plus complexe. cdrecord --help. Python) crache ceci:

Traceback (most recent call last):
  File "./install.py", line 52, in <module>
    burntrack2("hi")
  File "./install.py", line 46, in burntrack2
    a = subprocess.Popen("cdrecord --help",stdout = subprocess.PIPE)
  File "/usr/lib/python2.6/subprocess.py", line 633, in __init__
    errread, errwrite)
  File "/usr/lib/python2.6/subprocess.py", line 1139, in _execute_child
    raise child_exception
OSError: [Errno 2] No such file or directory
88
Insomaniacal

Pour obtenir le résultat de ls, utilisez stdout=subprocess.PIPE .

>>> proc = subprocess.Popen('ls', stdout=subprocess.PIPE)
>>> output = proc.stdout.read()
>>> print output
bar
baz
foo

La commande cdrecord --help Est envoyée à stderr, vous devez donc diriger cet indstead. Vous devez également diviser la commande en une liste de jetons, comme je l’ai déjà fait ci-dessous. Sinon, vous pouvez passer l’argument Shell=True, Mais cela déclenche un shell entièrement développé qui peut être dangereux si vous ne le faites pas. t contrôler le contenu de la chaîne de commande.

>>> proc = subprocess.Popen(['cdrecord', '--help'], stderr=subprocess.PIPE)
>>> output = proc.stderr.read()
>>> print output
Usage: wodim [options] track1...trackn
Options:
    -version    print version information and exit
    dev=target  SCSI target to use as CD/DVD-Recorder
    gracetime=# set the grace time before starting to write to #.
...

Si vous avez une commande qui envoie à la fois stdout et stderr et que vous voulez les fusionner, vous pouvez le faire en redirigeant stderr sur stdout, puis en prenant stdout.

subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.STDOUT)

Comme mentionné par Chris Morgan , vous devriez utiliser proc.communicate() au lieu de proc.read().

>>> proc = subprocess.Popen(['cdrecord', '--help'], stdout=subprocess.PIPE, stderr=subprocess.PIPE)
>>> out, err = proc.communicate()
>>> print 'stdout:', out
stdout: 
>>> print 'stderr:', err
stderr:Usage: wodim [options] track1...trackn
Options:
    -version    print version information and exit
    dev=target  SCSI target to use as CD/DVD-Recorder
    gracetime=# set the grace time before starting to write to #.
...
123
marcog

Si vous utilisez python 2.7 ou version ultérieure, la méthode la plus simple consiste à utiliser la commande subprocess.check_output() . Voici un exemple:

output = subprocess.check_output('ls')

Pour rediriger également stderr, vous pouvez utiliser les éléments suivants:

output = subprocess.check_output('ls', stderr=subprocess.STDOUT)



Si vous souhaitez passer des paramètres à la commande, vous pouvez utiliser une liste ou utiliser invoke un shell et utiliser une seule chaîne.

output = subprocess.check_output(['ls', '-a'])
output = subprocess.check_output('ls -a', Shell=True)
30
amicitas

Avec a = subprocess.Popen("cdrecord --help",stdout = subprocess.PIPE), vous devez utiliser une liste ou utiliser Shell=True;

L'un ou l'autre fonctionnera. Le premier est préférable.

a = subprocess.Popen(['cdrecord', '--help'], stdout=subprocess.PIPE)

a = subprocess.Popen('cdrecord --help', Shell=True, stdout=subprocess.PIPE)

De plus, au lieu d'utiliser Popen.stdout.read/Popen.stderr.read, Vous devriez utiliser .communicate() (reportez-vous à la documentation du sous-processus pour connaître le pourquoi).

proc = subprocess.Popen(['cdrecord', '--help'], stdout=subprocess.PIPE, stderr=subprocess.PIPE)
stdout, stderr = proc.communicate()
11
Chris Morgan