Ejecutar comandos del shell en Python y capturar su salida

miércoles, noviembre 19, 2008

A veces cuando escribimos un programa necesitamos ejecutar algún comando en la consola y tomar su salida para realizar una acción o tomar una decisión.

La mayoría de los lenguajes de programación incorporan funciones que nos permiten ejecutar órdenes en la consola del sistema operativo y Python no es la excepción. Además lo hace realmente fácil ;)

Para ello haremos uso del módulo subprocess, que a diferencia del os.system() o del os.popen() es mucho más intuitivo y sencillo de usar.

El módulo define una función conveniente llamada call que ejecuta un comando y espera hasta que termine su ejecución. Recibe una gran cantidad de parámetros, pero solo nos interesan el comando a ejecutar, el descriptor de archivo de la salida estándar (stdout) y el descriptor de archivo de la salida de errores (stderr). Estos descriptores son importantes porque allí es donde se almacenará la salida del programa (lo que normalmente imprime en la consola) y los mensajes de error (que también se imprimen en la consola).

El comando debe ser una lista de cádenas de caracteres, el primer elemento a ejecutar es el comando y los elementos siguientes son cada uno de los argumentos que recibe dicho comando. Los descriptores de archivos son eso... vulgares descriptores de archivos :D

Pero es suficiente de preámbulos... Show me the code!

# importamos el módulo
import subprocess

# Creamos los descriptores de archivos como dos vulgares archivos
# con permisos de escritura llamados 'archivo_out' y 'archivo_err'
outfd = open('archivo_out', 'w+')
errfd = open('archivo_err', 'w+')

# Supongamos que queremos ejecutamos el comando: ls -l -a
subprocess.call(['ls', '-l', '-a'], stdout=outfd, stderr=errfd)

# Cerramos los archivos para que se escriban los cambios y se liberen
# los buffers de I/O
outfd.close()
errfd.close()

# Ahora leemos todo lo que tengan los archivos y guardamos en la variable
# output la salida estándar y en err la salida de error.
fd = open('archivo_out', 'r')
output = fd.read()
fd.close()

fd = open('archivo_err', 'r')
err = fd.read()
fd.close()

# Por último mostramos lo que tienen las variables
print 'stdout: %s\n' % output
print 'stderr: %s' % err

Con eso ya podemos ejecutar cualquier comando en la shell usando Python, esperar su salida y además guardarla en una variable para procesarla más adelante

4 comentarios:

Txumari dijo...

Muy buenas, muy bien explicado. Aunque yo he llegado aqui buscando alguna solucion para poder ejecutar un comando y cuando luego me pide mas datos mandarselos. Es decir por ejemplo cuando ejecutas algo y te pregunta yes/no, o en mi caso que ejecuto "gpg -c archivo.ext" desde python con "commands.getoutput()" y luego me pide la password y despues su confirmacion.

Gracias por escucharme.

Roge dijo...

estuve viendo como es la cosa y se reduce a:

process = subprocess.Popen('ls -l', stdout=subprocess.PIPE, stderr=subprocess.PIPE, shell=True)

despues a process se le pide subprocess.stdout y ya es un objeto de archivo comun y corriente de python, lo mismo pidiendo stdin, y stderr te da archivos con los parametros de entrada y si dio algun error o excepcion esta en el archivo subprocess.stderr, muy bueno el modulito subprocess

Joger Quintero dijo...

Hola que tal!

Me gustaría saber si si se puede hacer lo que pregunta Txumari, es decir, en mi caso quiero realizar una aplicación gráfica para pwpass y este me pide el password y confirmación, no sé cómo podría yo desde python enviarlo.

De antemano muchas gracias por la respuesta que me puedan dar

Anónimo dijo...

Muchas gracias ! ! ! ! !

Me has solucionado un gran problema ;)