2009-03-25 12 views
10

Sous Linux, la commande ps aux génère une liste de processus avec plusieurs colonnes pour chaque statistique. par exemple.Division de la sortie de ps à l'aide de 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 

Je veux être en mesure de lire ceci en utilisant Python et divisé sur chaque ligne et chaque colonne afin qu'ils puissent être utilisés comme valeurs.

Pour la plupart, ce n'est pas un problème: pour obtenir chaque ligne et le diviser par des espaces, par exemple

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

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

Je peux maintenant boucle à travers les processus Cependant, le problème est que la dernière colonne, la commande, a parfois des espaces dans. Dans l'exemple ci-dessus, cela peut être vu dans la commande

pickup -l -t fifo -u 

qui serait divisé comme

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

mais je veux vraiment comme:

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

Donc ma question est, comment puis-je diviser les colonnes, mais quand il vient à la colonne de commande, garder la chaîne entière comme un élément de la liste plutôt que de séparer par des espaces?

+3

Ne fais pas ça. La sortie ps est ** NOT ** destinée à être lisible par machine. Creusez ces informations sur le système de fichiers/proc, ou utilisez PSI, comme suggéré par vartec. – Juliano

+0

Pourquoi n'est-il pas censé être lisible par une machine? – DavidM

+0

David, je pense que Juliano veut simplement dire que la sortie du PS varie énormément (comme vous l'avez souligné, la chaîne de commande est divisée en plusieurs parties par votre regex et il n'y a aucun moyen que le programme sache cela). serait plus facile pour vous d'utiliser le/proc fs ou PSI. Ce n'est pas que c'est * PAS MACHINE LISIBLE * c'est que ce sera une douleur à faire. – sholsapp

Répondre

22

Utilisez le second paramètre à split qui spécifie le nombre maximal de champs dans lesquels la chaîne doit être divisée. Je suppose que vous pouvez trouver le nombre en comptant le nombre de champs dans la première ligne, c'est-à-dire les titres de colonnes.

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

Le maxsplit argument optionnel à la méthode split peut vous aider:

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

Pourquoi utilisez-vous pas PSI à la place? PSI fournit des informations sur le processus sous Linux et d'autres variantes Unix.

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

Cela a été beaucoup plus facile que d'essayer d'analyser la sortie de ps. –

+0

FWIW, le lien vers PSI est mort à compter du 2014-09-19 –

12

Extrayez le package python.psutils.

psutil.process_iter renvoie un générateur que vous pouvez utiliser pour parcourir tous les processus. p.cmdline est une liste des arguments cmdline de chaque objet Process, séparés comme vous le souhaitez.

Vous pouvez créer un dictionnaire de pids vs (pid,cmdline,path) avec une seule ligne, puis l'utiliser comme vous le souhaitez.

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

+1, psutil est définitivement le chemin à parcourir (http://pypi.python.org/pypi/psutil/). C'est portable et ne dépend pas de la sortie de ps. – sorki

+1

L'exemple fourni pourrait être amélioré en simplifiant le cas d'utilisation. J'ai trouvé très utile d'apprendre que les objets 'Process' que' next (process_iter()) 'renvoie ont une méthode' as_dict' un objet (IMO) beaucoup plus utile que le dict que cette réponse crée pour vous. De plus, notez que toutes les valeurs 'Process' ne sont pas des chaînes! – ThorSummoner

1

Voici une routine agréable et utilisation pour vous aller:

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]) 
Questions connexes