2009-03-25 50 views
10

Trên Linux, lệnh ps aux xuất ra một danh sách các quy trình có nhiều cột cho mỗi chỉ số. ví dụ.Tách đầu ra của ps bằng cách sử dụng 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 

Tôi muốn có thể đọc điều này bằng cách sử dụng Python và tách từng hàng và sau đó mỗi cột để chúng có thể được sử dụng làm giá trị.

Đối với hầu hết các phần, đây không phải là một vấn đề:

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

bây giờ tôi có thể lặp qua các quy trình để có được mỗi hàng và chia nó ra bằng dấu cách, ví dụ

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

Tuy nhiên, vấn đề là cột cuối cùng, lệnh, đôi khi có dấu cách. Trong ví dụ trên, bạn có thể thấy trong lệnh

pickup -l -t fifo -u 

mà sẽ được chia ra như

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

nhưng tôi thực sự muốn nó như:

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

Vì vậy, câu hỏi của tôi là, làm thế nào tôi có thể chia ra các cột nhưng khi nói đến cột lệnh, giữ toàn bộ chuỗi như một phần tử danh sách chứ không phải chia nhỏ theo không gian?

+3

Đừng làm điều đó. đầu ra ps là ** NOT ** được thiết kế để có thể đọc được trên máy. Hoặc khai thác thông tin này trên hệ thống tập tin/proc, hoặc sử dụng PSI, như đề xuất của vartec. – Juliano

+0

Tại sao nó không phải là máy có thể đọc được? – DavidM

+0

David, tôi nghĩ Juliano đơn giản muốn nói rằng đầu ra PS thay đổi rất nhiều (như bạn đã chỉ ra, chuỗi lệnh được chia thành nhiều phần bởi regex của bạn và không có cách nào để chương trình biết điều này không mong muốn) sẽ dễ dàng hơn cho bạn khi sử dụng/proc fs hoặc PSI. Nó không phải là nó * KHÔNG MÁY READABLE * nó là nó sẽ là một nỗi đau để làm. – sholsapp

Trả lời

22

Sử dụng thông số thứ hai để split chỉ định số trường tối đa để chia chuỗi thành. Tôi đoán bạn có thể tìm số bằng cách đếm số trường trong dòng đầu tiên, tức là tiêu đề cột.

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

Các maxsplit đối số tùy chọn cho phương thức split có thể giúp bạn:

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

Tại sao bạn không sử dụng PSI để thay thế? PSI cung cấp thông tin quy trình trên Linux và các biến thể Unix khác.

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

Điều này dễ hơn nhiều so với việc cố gắng phân tích đầu ra của ps. –

+0

FWIW, liên kết tới PSI đã chết vào năm 2014-09-19 –

12

Kiểm tra gói python.psutils.

psutil.process_iter trả về trình tạo mà bạn có thể sử dụng để lặp qua tất cả các quy trình. p.cmdline là danh sách các đối số cmdline của từng đối tượng quy trình, được tách riêng theo cách bạn muốn.

Bạn có thể tạo từ điển pids vs (pid,cmdline,path) chỉ với một dòng và sau đó sử dụng nó bất cứ khi nào bạn muốn.

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

+1, psutil chắc chắn là cách để đi (http://pypi.python.org/pypi/psutil/). Nó di động và không phụ thuộc vào đầu ra của ps. – sorki

+1

Ví dụ được cung cấp có thể được cải thiện bằng cách đơn giản hóa trường hợp sử dụng. Tôi thấy rất có giá trị khi biết rằng các đối tượng 'Process' mà' next (process_iter()) 'trả về có một phương thức' as_dict' a (IMO) hữu ích hơn nhiều so với dict mà câu trả lời này tạo ra cho bạn. Ngoài ra, lưu ý rằng không phải tất cả các giá trị 'Process' đều là chuỗi! – ThorSummoner

1

Dưới đây là một thói quen và sử dụng thoải mái để giúp bạn đi:

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]) 
Các vấn đề liên quan