Разделение вывода ps с помощью Python

В Linux команда ps aux выводит список процессов с несколькими столбцами для каждого стата. например.

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

Я хочу иметь возможность прочитать это при использовании Python и разделить каждую строку, а затем каждый столбец, чтобы они могли использоваться как значения.

По большей части это не проблема:

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

Теперь я могу перебирать процессы, чтобы получить каждую строку и разбить ее пробелами, например

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

Однако проблема заключается в том, что последний столбец, команда, иногда имеет пробелы. В приведенном выше примере это можно увидеть в команде

pickup -l -t fifo -u

который будет разделен на

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

но я действительно хочу это как:

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

Итак, мой вопрос в том, как я могу разделить столбцы, но когда дело доходит до столбца команды, сохраните всю строку как один элемент списка, а не разделите ее пробелами?

Ответ 1

Используйте второй параметр split, который задает максимальное количество полей для разделения строки на. Я думаю, вы можете найти номер, посчитав количество полей в первой строке, то есть заголовки столбцов.

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)

Ответ 2

Проверьте пакет python.psutils.

psutil.process_iter возвращает генератор, который вы можете использовать для итерации по всем процессам. p.cmdline - это список аргументов cmdline каждого объекта процесса, разделенных так, как вы хотите.

Вы можете создать словарь pids vs (pid,cmdline,path) только с одной строкой, а затем использовать его в любом случае.

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

Ответ 3

Почему бы вам не использовать PSI? PSI предоставляет информацию о процессах в Linux и других вариантах Unix.

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

Ответ 4

Дополнительный аргумент maxsplit для метода split может помочь вам:

sep.split.(row, maxsplit=42)

Ответ 5

Здесь хорошая рутина и использование, чтобы вы начали:

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