2010-08-27 29 views
17

Hãy nói rằng tôi chạy ps axf và tôi có thể thấy rằng cây quá trình lệnh của tôi trông như thế này:Làm cách nào để tìm PID cấp cao nhất của một quy trình cụ thể bằng cách sử dụng bash?

800 ?  Ss  0:00 /usr/sbin/sshd 
10186 ?  Ss  0:00 \_ sshd: yukondude [priv] 
10251 ?  S  0:00  \_ sshd: [email protected]/0 
10252 pts/0 Ss  0:00   \_ -bash 
10778 pts/0 S  0:00    \_ su - 
10785 pts/0 S  0:00     \_ -su 
11945 pts/0 R+  0:00      \_ ps axf 

Tôi biết tôi có thể kiểm tra $$ cho PID vỏ hiện tại (10.785) hoặc $PPID cho phụ huynh PID (10778) .

Nhưng tôi chỉ muốn PID cấp cao nhất của cha mẹ, sẽ là 800 (SSH daemon) trong ví dụ này. Có cách nào để làm điều đó dễ dàng không?

tôi học được từ this SO answer mà tôi đệ quy có thể kiểm tra sự xâm nhập thứ 4 trong file /proc/PID/stat để tìm PID cha mẹ của mỗi quá trình:

# cut -f4 -d' ' /proc/10785/stat 
10778 
# cut -f4 -d' ' /proc/10778/stat 
10252 
# cut -f4 -d' ' /proc/10252/stat 
10251 
# cut -f4 -d' ' /proc/10251/stat 
10186 
# cut -f4 -d' ' /proc/10186/stat 
800 
# cut -f4 -d' ' /proc/800/stat 
1 

(Các top-level mẹ PID sẽ là một trong những ngay trước khi tôi đạt init PID của bạn, tức là, 1.)

Trước khi tôi viết một vòng lặp nhỏ (Tôi thậm chí không chắc chắn nếu bạn có thể sử dụng đệ quy trong bash) để làm điều này, có một phương pháp đơn giản hơn nhiều mà tôi đang thiếu ? Có thể chỉ là một thông số khác của tệp dưới /proc? Một grep thông qua các tệp đó không tiết lộ bất cứ điều gì hiển nhiên.

Chỉnh sửa: Tất nhiên, quy trình cấp cao nhất cho tất cả các quy trình Linux là/sbin/init với PID 1. Tôi muốn là PID của cha mẹ ngay trước đó: cha mẹ áp chót.

+1

Bạn không cần đệ quy cho điều này, chỉ cần một vòng lặp đơn giản ... – JanC

+1

Đúng, nhưng đệ quy chỉ là thú vị hơn rất nhiều và máy tính-sciency. – yukondude

+1

Không đời nào. Các vòng lặp cơ bản hơn: P Đừng quên những công cụ cơ bản nhất của bạn. –

Trả lời

10

Không một giải pháp tốt hơn, đây là một đơn giản (recursive) kịch bản để có được từ trên mức mẹ PID của bất kỳ số quá trình bạn cung cấp cho nó (hoặc vỏ hiện tại nếu bạn bỏ qua các tham số PID):

#!/bin/bash 
# Look up the top-level parent Process ID (PID) of the given PID, or the current 
# process if unspecified. 

function top_level_parent_pid { 
    # Look up the parent of the given PID. 
    pid=${1:-$$} 
    stat=($(</proc/${pid}/stat)) 
    ppid=${stat[3]} 

    # /sbin/init always has a PID of 1, so if you reach that, the current PID is 
    # the top-level parent. Otherwise, keep looking. 
    if [[ ${ppid} -eq 1 ]] ; then 
     echo ${pid} 
    else 
     top_level_parent_pid ${ppid} 
    fi 
} 

Chỉ source kịch bản này và gọi top_level_parent_pid có hoặc không có một đối số PID, như thích hợp.

Nhờ @Dennis Williamson vì nhiều đề xuất của ông về cách viết kịch bản này gọn nhẹ và hiệu quả.

+1

Tôi khuyên bạn nên sử dụng trong kịch bản để thực hiện đệ quy thay vì toàn bộ tập lệnh. Nó chỉ có vẻ neater. Ngoài ra, theo cách của nó, kịch bản của bạn sẽ phải nằm trong '$ PATH' của bạn hoặc bạn phải sử dụng' $ 0 $ ppid' làm dòng thứ hai để cuối cùng (cuộc gọi đệ quy). Bằng cách này, 'if ... fi' đầu tiên của bạn có thể được thay thế bằng chỉ:' pid = $ {1: - $$} '. –

+0

Mẹo tuyệt vời. Tôi luôn luôn phải tìm kiếm các quy tắc thay thế tham số bash khi tôi gặp chúng, nhưng chúng là các trình tiết kiệm không gian. Tôi cũng được coi là một chức năng nhưng tôi đã lười biếng sau khi kịch bản nhỏ này đã làm công việc. Tôi sẽ phải tô nó lên nếu nó kết thúc là một tiện ích được sử dụng thường xuyên hơn. – yukondude

+1

+1 Có vẻ tốt. Bạn cũng có thể đặt mặc định bên trong hàm. Sau đó, nếu bạn nguồn tập tin để chức năng là "cư dân" nó có thể được gọi mà không có bất kỳ đối số. 'pid = $ {1: - $$}' –

9

Bash chắc chắn có thể thực hiện đệ quy.

Bạn có thể lấy trường thứ tư từ tập tin stat mà không sử dụng cut tiện ích bên ngoài bằng cách làm một cái gì đó như thế này:

stat=($(</proc/$$/stat)) # create an array 
ppid=${stat[3]}    # get the fourth field 
+0

Cảm ơn đề xuất đó. Tôi đã sử dụng nó trong tập lệnh nhỏ mà tôi đã đăng dưới dạng giải pháp khả thi. – yukondude

+1

Chủ đề cũ mà tôi biết, nhưng tôi nghĩ mình sẽ ném vào một phiên bản thân thiện 'sh' ở trên .. đọc _ _ _ ppid _ Dave

4

Một giải pháp (từ here):

ps -p $$ -o ppid= 
+0

Điều đó chỉ tra cứu PID của cha mẹ ngay lập tức của quá trình, không phải là "cấp cao nhất" cha mẹ. Cách rất gọn gàng để làm điều đó mặc dù. – yukondude

+0

nếu bạn muốn tránh khoảng trắng, sử dụng '-o ppid: 1 =' – bukzor

0

OS X phiên bản, chuyển thể từ câu trả lời @albert và @ yukondude của:

#!/usr/bin/env bash 
# Look up the top-level parent Process ID (PID) of the given PID, or the current 
# process if unspecified. 

# From http://stackoverflow.com/questions/3586888/how-do-i-find-the-top-level-parent-pid-of-a-given-process-using-bash 
function top_level_parent_pid { 
    # Look up the parent of the given PID. 
    PID=${1:-$$} 
    PARENT=$(ps -p $PID -o ppid=) 

    # /sbin/init always has a PID of 1, so if you reach that, the current PID is 
    # the top-level parent. Otherwise, keep looking. 
    if [[ ${PARENT} -eq 1 ]] ; then 
     echo ${PID} 
    else 
     top_level_parent_pid ${PARENT} 
    fi 
} 
0

Lặp đi lặp lại phiên bản:

# ppid -- Show parent PID 
# $1 - The process whose parent you want to show, default to $$ 
function ppid() { 
    local stat=($(</proc/${1:-$$}/stat)) 
    echo ${stat[3]} 
} 

# apid -- Show all ancestor PID 
# $1 - The process whose ancestors you want to show, default to $$ 
# $2 - Stop when you reach this ancestor PID, default to 1 
function apid() { 
    local ppid=$(ppid ${1:$$}) 
    while [ 0 -lt $ppid -a ${2:-1} -ne $ppid ]; do 
     echo $ppid 
     ppid=$(ppid $ppid) 
    done 
} 

Là hai hàm riêng biệt, bởi vì đôi khi bạn chỉ muốn cha mẹ PID, và đôi khi bạn muốn toàn bộ cây.

Các vấn đề liên quan