2009-03-25 20 views
10

En Linux, el comando ps aux muestra una lista de procesos con múltiples columnas para cada estadística. p.ej.División de la salida de ps utilizando Python

USER  PID %CPU %MEM VSZ RSS TTY  STAT START TIME COMMAND 
... 
postfix 22611 0.0 0.2 54136 2544 ?  S 15:26 0:00 pickup -l -t fifo -u 
apache 22920 0.0 1.5 198340 16588 ?  S 09:58 0:05 /usr/sbin/httpd 

Quiero ser capaz de leer esto en el uso de Python y dividir a cabo cada fila y cada columna a continuación, para que puedan ser utilizados como valores.

En su mayor parte, esto no es un problema:

ps = subprocess.Popen(['ps', 'aux'], stdout=subprocess.PIPE).communicate()[0] 
processes = ps.split('\n') 

ahora puedo bucle a través de los procesos para conseguir cada fila, que se dividió a cabo por espacios, por ejemplo

sep = re.compile('[\s]+') 
for row in processes: 
    print sep.split(row) 

Sin embargo, el problema es que la última columna, el comando, a veces tiene espacios en. En el ejemplo anterior, esto se puede ver en el comando

pickup -l -t fifo -u 

el que se dividiría como

['postfix', '22611', '0.0', '0.2', '54136', '2544', '?', 'S', '15:26', '0:00', 'pickup', '-l', '-t', 'fifo', '-u'] 

pero realmente quiero como:

['postfix', '22611', '0.0', '0.2', '54136', '2544', '?', 'S', '15:26', '0:00', 'pickup -l -t fifo -u'] 

Así que mi pregunta es, ¿cómo puedo dividir las columnas, pero cuando se trata de la columna de mando, mantener toda la cadena como un elemento de lista en lugar de dividir por espacios?

+3

no hacen eso. La salida ps está ** NO ** destinada a ser legible por máquina. O explota esta información en el sistema de archivos/proc o usa PSI, como sugiere vartec. – Juliano

+0

¿Por qué no se supone que sea legible por máquina? – DavidM

+0

David, creo que Juliano simplemente quiere decir que la salida PS varía tanto (como usted señaló, la secuencia de comandos se divide en muchas partes por su expresión regular y no hay forma de que el programa sepa que esto es indeseable) que sería más fácil para usted usar/proc fs o PSI. No es que sea * NO MÁQUINA LECTURA * es que será un dolor hacerlo. – sholsapp

Respuesta

22

Utilice el segundo parámetro para split que especifica el número máximo de campos para dividir la cadena. Supongo que puede encontrar el número contando el número de campos en la primera línea, es decir, los títulos de las columnas.

ps = subprocess.Popen(['ps', 'aux'], stdout=subprocess.PIPE).communicate()[0] 
processes = ps.split('\n') 
# this specifies the number of splits, so the splitted lines 
# will have (nfields+1) elements 
nfields = len(processes[0].split()) - 1 
for row in processes[1:]: 
    print row.split(None, nfields) 
1

El maxsplit argumento opcional al método split pueden ayudar:

sep.split.(row, maxsplit=42) 
4

¿Por qué no usar PSI en su lugar? PSI proporciona información de proceso sobre Linux y otras variantes de Unix.

import psi.process 
for p in psi.process.ProcessTable().values(): … 
+0

Esto fue mucho más fácil que tratar de analizar la salida de ps. –

+0

FWIW, el enlace a PSI está muerto a partir de 2014-09-19 –

12

Salida del paquete python.psutils.

psutil.process_iter devuelve un generador que puede usar para iterar sobre todos los procesos. p.cmdline es una lista de los argumentos cmdline de cada objeto de proceso, separados de la manera que desee.

Puede crear un diccionario de pids vs (pid,cmdline,path) con solo una línea y luego usarlo como quiera.

pid_dict = dict([(p.pid, dict([('pid',p.pid), ('cmdline',p.cmdline), ('path',p.path)])) 
       for p in psutil.process_iter()])) 
+2

+1, psutil es definitivamente el camino a seguir (http://pypi.python.org/pypi/psutil/). Es portátil y no depende de la salida de ps. – sorki

+1

El ejemplo proporcionado podría mejorarse simplificando el caso de uso. Me pareció muy valioso aprender que los objetos 'Process' que' next (process_iter()) 'arrojan tienen un método' as_dict' (IMO) mucho más útil que el dict que crea esta respuesta para ti. ¡Además, tenga en cuenta que no todos los valores de 'Proceso' son cadenas! – ThorSummoner

1

Aquí es una buena rutina y el uso para que te va:

def getProcessData(): 
    ps = subprocess.Popen(['ps', 'aux'], stdout=subprocess.PIPE).communicate()[0] 
    processes = ps.split('\n') 
    # this specifies the number of splits, so the splitted lines 
    # will have (nfields+1) elements 
    nfields = len(processes[0].split()) - 1 
    retval = [] 
    for row in processes[1:]: 
     retval.append(row.split(None, nfields)) 
    return retval 

wantpid = int(contents[0]) 
pstats = getProcessData() 
for ps in pstats: 
    if (not len(ps) >= 1): continue 
    if (int(ps[1]) == wantpid): 
     print "process data:" 
     print "USER    PID  %CPU  %MEM  VSZ  RSS  TTY  STAT  START TIME  COMMAND" 
     print "%-10.10s %10.10s %10.10s %10.10s %10.10s %10.10s %10.10s %10.10s %10.10s %s" % (ps[0], ps[1], ps[2], ps[3], ps[4], ps[5], ps[6], ps[7], ps[8], ps[9]) 
Cuestiones relacionadas