2009-03-25 11 views
10

W systemie Linux polecenie ps aux wyświetla listę procesów z wieloma kolumnami dla każdej statystyki. na przykładDzielenie wyjścia ps za pomocą Pythona

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 

Chcę być w stanie odczytać to w Pythonie i podzielić się każdy wiersz, a następnie każdą kolumnę, więc mogą być używane jako wartości.

W przeważającej części, to nie jest problem:

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

mogę teraz pętli procesów, aby każdy wiersz i podzielić ją przez przestrzenie, na przykład

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

jednak Problem polega na tym, że ostatnia kolumna, polecenie, czasami ma spacje. W powyższym przykładzie widać to w komendzie

pickup -l -t fifo -u 

które byłyby wydzielone jako

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

ale naprawdę chcę ją jako:

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

Więc moje pytanie brzmi: w jaki sposób mogę podzielić się kolumny, ale gdy przychodzi do kolumny poleceń, zachować cały łańcuch jako jeden element listy, a nie podzielić go spacjami?

+3

nie rób tego. Wyjście ps jest ** NIE ** przeznaczone do odczytu maszynowego. Albo wykopuj te informacje w systemie plików/proc, albo użyj PSI, jak sugeruje vartec. – Juliano

+0

Dlaczego nie powinno być możliwe do odczytu maszynowego? – DavidM

+0

David, myślę, że Juliano oznacza po prostu, że wynik PS różni się tak bardzo (jak zauważyłeś, ciąg poleceń jest podzielony na wiele części przez twoje wyrażenie regularne i nie ma możliwości, aby program wiedział o tym niepożądanym), że byłoby łatwiej użyć/proc fs lub PSI. To nie jest to, że to NIE MASZYNA CZYTELNA * to jest ból. – sholsapp

Odpowiedz

22

Użyj drugiego parametru do split, który określa maksymalną liczbę pól do podziału ciągu. Domyślam się, że możesz znaleźć liczbę, licząc liczbę pól w pierwszym wierszu, tj. Tytuły kolumn.

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

maxsplit opcjonalny argument do metody split może pomóc:

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

Dlaczego nie używacie PSI zamiast? PSI udostępnia informacje o procesach w systemie Linux i innych wersjach systemu Unix.

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

To było znacznie łatwiejsze niż próba analizy pliku PS. –

+0

FWIW, link do PSI jest martwy od 2014-09-19 –

12

Sprawdź pakiet python.psutils.

psutil.process_iter zwraca generator, którego można użyć do iteracji wszystkich procesów. p.cmdline to lista argumentów cmdline każdego obiektu Process, oddzielonych tak, jak chcesz.

Możesz stworzyć słownik pidów kontra (pid,cmdline,path) za pomocą tylko jednej linii, a następnie użyć go w dowolny sposób.

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

+1, psutil jest zdecydowanie do zrobienia (http://pypi.python.org/pypi/psutil/). Jest przenośny i nie opiera się na wyjściu ps. – sorki

+1

Podany przykład można poprawić, upraszczając przypadek użycia. Zauważyłem, że bardzo cenne jest poznanie, że obiekty 'Process' zwracane przez' next (process_iter()) mają metodę 'as_dict' a (IMO) o wiele bardziej przydatny obiekt niż ten, który ta odpowiedź tworzy dla ciebie. Dodatkowo zauważ, że nie wszystkie wartości "Process" są ciągami! – ThorSummoner

1

Oto ładny rutyna i zwyczaj, aby dostać się dzieje:

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]) 
Powiązane problemy