Pregunta Salida estándar del subproceso de tubería a una variable


Quiero ejecutar un comando en pythong, usando el módulo de subproceso, y almacena 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 el listado del directorio en la terminal, en lugar de tenerlo almacenado en a. También lo intenté:

 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 algo anticuado, desde que funcioné ls > tmp en el terminal no se imprime ls a la terminal en absoluto, pero la almacena en tmp. Sin embargo, pasa lo mismo.

Editar:

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

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

75
2017-12-22 23:45


origen


Respuestas:


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

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

El comando cdrecord --help salidas a stderr, por lo que debe canalizar ese indstead. También debe dividir el comando en una lista de tokens como he hecho a continuación, o la alternativa es pasar el shell=True argumento, pero esto dispara un shell completamente reventado que puede ser peligroso si no controlas 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 genera tanto stdout como stderr y desea fusionarlos, puede hacerlo conectando stderr a stdout y luego capturando stdout.

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

Como se menciona por Chris Morgan, deberías estar usando proc.communicate() en 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 #.
...

112
2017-12-22 23:49



Si está utilizando Python 2.7 o posterior, la manera más fácil de hacerlo es usar subprocess.check_output() mando. Aquí hay un ejemplo:

output = subprocess.check_output('ls')

Para redirigir 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)

23
2018-03-16 18:25



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

Cualquiera de estos funcionará. El 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, Deberías usar .communicate() (consulte la documentación del subproceso para saber por qué).

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

10
2017-12-23 00:17