2010-08-27 12 views
17

मान लीजिए कि मैं ps axf चलाते हैं और मैं देख सकता हूँ कि मेरे आदेश की प्रक्रिया पेड़ इस तरह दिखता है:बैश का उपयोग करके किसी दिए गए प्रक्रिया के शीर्ष-स्तर के पैरेंट पीआईडी ​​को मैं कैसे ढूंढूं?

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 

मैं जानता हूँ कि मैं वर्तमान खोल के पीआईडी ​​(10785) या $PPID माता पिता पीआईडी ​​के लिए के लिए जाँच कर सकते हैं $$ (10,778) ।

लेकिन मैं सिर्फ शीर्ष-स्तर के माता-पिता पीआईडी ​​चाहता हूं, जो इस उदाहरण में 800 (एसएसएच डिमन) होगा। क्या आसानी से ऐसा करने का कोई तरीका है?

मैं this SO answer से सीखा है कि मैं रिकर्सिवली /proc/PID/stat फ़ाइल में 4 प्रविष्टि की जांच कर सकते प्रत्येक प्रक्रिया के माता-पिता पीआईडी ​​को खोजने के लिए:

# 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 

(शीर्ष स्तर के माता-पिता पीआईडी ​​एक बस से पहले मैं init तक पहुँचने के लिए किया जाएगा पीआईडी, यानी, 1.)

इससे पहले कि मैं थोड़ा लूप लिखूं (मुझे यह भी सुनिश्चित नहीं है कि आप बैश में रिकर्सन का उपयोग कर सकते हैं), क्या यह एक और अधिक सरल तरीका है जिसे मैं याद कर रहा हूं ? शायद /proc के तहत फ़ाइल का एक और पैरामीटर? उन फ़ाइलों के माध्यम से grep कुछ स्पष्ट नहीं दिखाया।

संपादित: बेशक, सभी लिनक्स प्रक्रियाओं के लिए उच्च-स्तरीय प्रक्रिया 1. की एक पीआईडी ​​के साथ/sbin/init है क्या मैं चाहता हूँ सिर्फ इतना है कि पहले माता-पिता की पीआईडी ​​है: अंत से पहले माता-पिता।

+1

आपको इसके लिए रिकर्सन की आवश्यकता नहीं है, बस एक साधारण पाश ... – JanC

+1

सच है, लेकिन रिकर्सन इतना अधिक मजेदार और कंप्यूटर-विज्ञान है। – yukondude

+1

कोई रास्ता नहीं। लूप्स अधिक मौलिक हैं: पी न करें 'अपने सबसे बुनियादी उपकरण भूल जाओ। –

उत्तर

10

एक बेहतर समाधान न करना, यहाँ एक सरल (पुनरावर्ती) स्क्रिप्ट शीर्ष पाने के लिए है किसी भी प्रक्रिया नंबर पर आप इसे देने के स्तर माता पिता पीआईडी ​​(या वर्तमान खोल यदि आप पीआईडी ​​तर्क को छोड़):

#!/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 
} 

बस source इस स्क्रिप्ट और के साथ या एक पीआईडी ​​तर्क के बिना top_level_parent_pid फोन, के रूप में उचित।

इस लिपि को कॉम्पैक्टली और कुशलतापूर्वक लिखने के तरीके पर उनके कई सुझावों के लिए @ डेनिस विलियमसन का धन्यवाद।

+1

पढ़ें I पूरी लिपि की बजाय रिकर्सन करने के लिए स्क्रिप्ट के भीतर कार्य करें। यह सिर्फ neater लगता है। साथ ही, जिस तरह से, आपकी स्क्रिप्ट को आपके '$ PATH' में होना होगा या आपको पिछली पंक्ति (रिकर्सिव कॉल) के दूसरे के रूप में '$ 0 $ ppid' का उपयोग करना होगा। वैसे, आपकी पहली 'अगर ... fi' को केवल इस जगह से बदला जा सकता है: 'pid = $ {1: - $$}'। –

+0

उत्कृष्ट युक्तियाँ। जब मुझे सामना करना पड़ता है तो मुझे हमेशा बैश पैरामीटर प्रतिस्थापन नियम देखना पड़ता है, लेकिन वे स्पेस सेवर हैं। मैंने एक समारोह भी माना लेकिन इस छोटी सी लिपि के काम के बाद मुझे आलसी हो गई। अगर इसे अधिक बार उपयोग की जाने वाली उपयोगिता समाप्त हो जाती है तो मुझे इसे फेंकना होगा। – yukondude

+1

+1 अच्छा लगता है। आप फ़ंक्शन के अंदर डिफ़ॉल्ट भी डाल सकते हैं। फिर यदि आप फ़ाइल को स्रोत करते हैं तो फ़ंक्शन "निवासी" है जिसे इसे बिना किसी तर्क के कहा जा सकता है। 'pid = $ {1: - $$}' –

9

बैश निश्चित रूप से रिकर्सन कर सकता है।

आप कुछ इस तरह करने से बाहरी cut उपयोगिता का उपयोग किए बिना स्टेट फ़ाइल से चौथे क्षेत्र को पुनः प्राप्त कर सकते हैं:

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

उस सुझाव के लिए धन्यवाद। मैंने इसे एक छोटे से स्क्रिप्ट में इस्तेमाल किया जिसे मैंने संभावित समाधान के रूप में पोस्ट किया था। – yukondude

+1

पुराना धागा मुझे पता है, लेकिन मैंने सोचा कि मैं उपर्युक्त के 'sh' अनुकूल संस्करण में फेंक दूंगा .. _ _ _ ppid _ Dave

4

एक और (here से) समाधान:

ps -p $$ -o ppid= 
+0

जो केवल प्रक्रिया के तत्काल अभिभावक के पीआईडी ​​को देखता है, न कि "शीर्ष-स्तर" अभिभावक। हालांकि इसे करने के लिए बहुत साफ तरीका है। – yukondude

+0

यदि आप व्हाइटस्पेस पैडिंग से बचना चाहते हैं, तो '-o ppid: 1 = ' – bukzor

0

ओएस एक्स संस्करण, @albert और @ yukondude के जवाब से अनुकूलित:

#!/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

Iterative संस्करण:

# 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 
} 

दो अलग-अलग कार्यों के रूप में, क्योंकि कभी-कभी आप केवल माता पिता पीआईडी ​​चाहते हैं, और कभी-कभी आप पूरे पेड़ को चाहते हैं।

संबंधित मुद्दे