Canalizar la salida estándar de subproceso a una variable

Quiero ejecutar un comando en pythong , usando el módulo de subproceso, y almacenar la salida en una variable. Sin embargo, no quiero que la salida del comando se imprima en el terminal. Para este código:

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

Obtengo la lista del directorio en el terminal, en lugar de tenerlo almacenado en a archivo. También he intentado:

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

Esto también imprime la salida de ls a mi terminal. Incluso he intentado este comando con el método os.system un tanto anticuado, ya que ejecutar ls > tmp en el terminal no imprime ls en el terminal, sino que lo almacena en tmp . Sin embargo, lo mismo sucede.

Editar:

Recibo el siguiente error después de seguir los consejos de marcog, pero solo cuando se ejecuta un comando más complejo. cdrecord --help . Python escupe esto:

 Traceback (most recent call last): File "./install.py", line 52, in  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 

Para obtener la salida de ls , use stdout=subprocess.PIPE .

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

El comando cdrecord --help salida a stderr, por lo que necesita canalizar ese indstead. También debe dividir el comando en una lista de tokens como lo he hecho a continuación, o la alternativa es pasar el argumento shell=True pero esto activa un shell completamente soplado que puede ser peligroso si no controla el Contenido de la cadena de comandos.

 >>> 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 tiene un comando que emite tanto a stdout como a stderr y desea fusionarlos, puede hacerlo canalizando stderr a stdout y luego capturando stdout.

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

Como lo mencionó Chris Morgan , debería usar proc.communicate() lugar 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 #. ... 

Si está usando python 2.7 o posterior, la forma más sencilla de hacerlo es usar el comando subprocess.check_output() . Aquí hay un ejemplo:

 output = subprocess.check_output('ls') 

Para redireccionar también stderr puede usar lo siguiente:

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

En el caso de que desee pasar parámetros al comando, puede usar una lista o usar invocar un shell y usar una sola cadena.

 output = subprocess.check_output(['ls', '-a']) output = subprocess.check_output('ls -a', shell=True) 

Con a = subprocess.Popen("cdrecord --help",stdout = subprocess.PIPE) , necesita usar una lista o usar shell=True ;

Cualquiera de estos funcionará. Lo primero es preferible.

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

Además, en lugar de usar Popen.stdout.read / Popen.stderr.read , debe usar .communicate() (consulte la documentación del subproceso para ver por qué).

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