使用Python拆分ps的输出

时间:2009-03-25 16:50:57

标签: python regex linux

在Linux上,命令ps aux输出每个统计数据包含多列的进程列表。 e.g。

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

所以我的问题是,如何拆分列,但是当涉及到命令列时,将整个字符串保留为一个列表元素而不是按空格拆分?

5 个答案:

答案 0 :(得分:22)

使用第二个参数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)

答案 1 :(得分:13)

查看python.psutils包。

psutil.process_iter返回一个生成器,您可以使用它来迭代所有进程。 p.cmdline是每个Process对象的cmdline参数的列表,以您希望的方式分隔。

您只需一行就可以创建一个pids与(pid,cmdline,path)的字典,然后无论如何都可以使用它。

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

答案 2 :(得分:4)

为什么不使用PSI? PSI提供有关Linux和其他Unix变体的过程信息。

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

答案 3 :(得分:1)

maxsplit方法的split可选参数可能会对您有所帮助:

sep.split.(row, maxsplit=42)

答案 4 :(得分:1)

这是一个很好的例程和用法,可以帮助您:

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