मूल रूप से वंशज प्रक्रियाओं की सूची प्राप्त करें


23

मैं उन सभी प्रक्रियाओं की एक सूची प्राप्त करना चाहूंगा जो (जैसे बच्चे, भव्य-बच्चे, आदि) से उतरते हैं $pid। यह सबसे आसान तरीका है जिसके साथ मैं आया हूं:

pstree -p $pid | tr "\n" " " |sed "s/[^0-9]/ /g" |sed "s/\s\s*/ /g"

क्या सभी वंश प्रक्रियाओं की पूरी सूची प्राप्त करने के लिए कोई आदेश, या कोई सरल तरीका है?


वहाँ एक कारण है कि आप उन सभी को एक लाइन पर जरूरत है? आप उस आउटपुट के साथ क्या कर रहे हैं? मुझे लगता है कि यह एक xy समस्या है, और आप गलत सवाल पूछ रहे हैं।
जोर्डनम

जब तक यह साफ है मैं प्रारूप के बारे में परवाह नहीं करता (यानी मैं '\n'सीमांकित बनाम ' 'सीमांकित के बारे में परवाह नहीं करता )। व्यावहारिक उपयोग का मामला है: ए) शुद्ध व्याख्यात्मकता (विशेष रूप से, "स्टॉप" कार्यक्षमता के द्वारा लिखी गई एक डीमोनाइज़र स्क्रिप्ट में जो कुछ भी प्रक्रियाओं के पेड़ को हटाने की प्रक्रिया होती है); और बी) एक टाइमआउट स्क्रिप्ट जो समयबद्ध प्रक्रिया को बनाने में कामयाब रहेगी।
STENyaK

2
@STenyaK आपके उपयोग के मामलों से मुझे लगता है कि आप प्रक्रिया समूह और नकारात्मक तर्क की तलाश कर रहे हैं killUnix.stackexchange.com/questions/9480/… , unix.stackexchange.com/questions/50555/…
Gilles 'SO- बुराई होना बंद करो'

@Gilles का उपयोग करके ps ax -opid,ppid,pgrp,cmdमैं देख रहा हूं कि कई प्रक्रियाएं हैं जो उसी pgrpसटीक सबट्री को साझा करती हैं जिसे मैं मारना चाहता हूं। (साथ ही, मैं नहीं देख सकते हैं setpgrp: डेबियन स्थिर संकुल में कहीं भी सूचीबद्ध कार्यक्रम packages.debian.org/... )
STenyaK

1
एक अन्य उपयोग का मामला: एक पूरी प्रक्रिया के पेड़ पर रेनाइस / आयनिस जो बहुत सारे संसाधनों को खा रहा है, जैसे कि एक बड़ा समानांतर निर्माण।
चीता

जवाबों:


15

निम्नलिखित कुछ सरल है, और कमांड नामों में संख्याओं की अनदेखी करने का अतिरिक्त लाभ है:

pstree -p $pid | grep -o '([0-9]\+)' | grep -o '[0-9]\+'

या पर्ल के साथ:

pstree -p $pid | perl -ne 'print "$1\n" while /\((\d+)\)/g'

हम कोष्ठकों के भीतर संख्याओं की तलाश कर रहे हैं ताकि हम उदाहरण के लिए, 2 को एक बच्चे की प्रक्रिया के रूप में न दें जब हम भर में चलते हैं gif2png(3012)। लेकिन अगर कमांड नाम में एक कोष्ठक संख्या है, तो सभी दांव बंद हैं। अभी तक केवल टेक्स्ट प्रोसेसिंग ही आपको ले जा सकती है।

इसलिए मुझे यह भी लगता है कि प्रक्रिया समूह जाने का तरीका है। यदि आप अपने स्वयं के प्रक्रिया समूह में एक प्रक्रिया चलाना चाहते हैं, तो आप डेबियन पैकेज 'डेमोंटूलम्स' से 'pgrphack' टूल का उपयोग कर सकते हैं:

pgrphack my_command args

या आप फिर से पर्ल में बदल सकते हैं:

perl -e 'setpgid or die; exec { $ARGV[0] } @ARGV;' my_command args

यहां केवल यह कहा जाता है कि प्रक्रिया समूह घोंसला नहीं बनाते हैं, इसलिए यदि कुछ प्रक्रिया अपने स्वयं के प्रक्रिया समूह बना रही है, तो इसके उपप्रकार अब आपके द्वारा बनाए गए समूह में नहीं होंगे।


बाल प्रक्रियाएं मनमानी हैं और स्वयं प्रक्रिया समूह का उपयोग कर सकते हैं या नहीं कर सकते हैं (मैं कुछ भी ग्रहण नहीं कर सकता)। हालाँकि आपका उत्तर लिनक्स में प्राप्य होने के लिए सबसे नजदीक आता है, इसलिए मैं इसे स्वीकार करूँगा। धन्यवाद।
STENyaK

यह बहुत उपयोगी था!
मिकाल गैलोविक

Pstree पाइप में थ्रेड आईडी भी शामिल होंगे, यानी थ्रेड्स की आईडी $ pid शुरू हो गई है।
मैक्सक्लेपजिग

आप सिंगल pstree -lp | grep -Po "(?<=\()\d+(?=\))"
ग्रीप का

7
descendent_pids() {
    pids=$(pgrep -P $1)
    echo $pids
    for pid in $pids; do
        descendent_pids $pid
    done
}

यह केवल यह देखते हुए कि इस आधुनिक गोले पर काम करेंगे लायक होगा ( bash, zsh, fish, और यहां तक ksh 99), लेकिन हो सकता है बड़े गोले पर काम नहीं है, जैसेksh 88
grochmal

@grochmal, ksh-88 में काम करने वाले ट्रैवर्सल समाधान के लिए मेरा जवाब नीचे देखें।
मैक्सचेलपिजिग

1

सबसे छोटा संस्करण जो मैंने पाया है कि जैसे कमांड के साथ सही ढंग से व्यवहार करता है pop3d:

pstree -p $pid | perl -ne 's/\((\d+)\)/print " $1"/ge'

यह गलत तरीके से व्यवहार करता है यदि आपके पास ऐसे आदेश हैं जिनके अजीब नाम हैं my(23)prog:।


1
यह उन कमांड के लिए काम नहीं करता है जो कुछ थ्रेड चला रहे हैं (क्योंकि pstree उन आईडी को प्रिंट करता है, साथ ही)।
मैक्सस्लेपज़िग

@ maxschlepzig ने बताया कि ffmpegथ्रेड्स के उपयोग से बहुत समस्या है । हालांकि, जल्दी टिप्पणियों से, ऐसा लगता है कि धागे घुंघराले ब्रेसिज़ के अंदर उनके नाम के साथ दिया जाता है { }
जिप्सी वर्तनी अध्येता

1

शुद्धता का मुद्दा भी है। pstreeकई कारणों से समस्या का उत्पादन पार्सिंग रूप से समस्याग्रस्त है:

  • Pstree पीआईडी और थ्रेड्स के आईडी प्रदर्शित करता है (नाम घुंघराले ब्रेसिज़ में दिखाए गए हैं)
  • एक कमांड नाम में घुंघराले ब्रेसिज़ हो सकते हैं, कोष्ठक में संख्या जो विश्वसनीय पार्सिंग को असंभव बनाती है

यदि आपके पास पायथन है और psutilपैकेज स्थापित है, तो आप इस स्निपेट का उपयोग सभी वंश प्रक्रियाओं को सूचीबद्ध करने के लिए कर सकते हैं:

pid=2235; python3 -c "import psutil
for c in psutil.Process($pid).children(True):
  print(c.pid)"

(Psutil पैकेज उदाहरण के लिए फ़ेडोरा tracer/ CentOS पर उपलब्ध कमांड की निर्भरता के रूप में स्थापित है ।)

वैकल्पिक रूप से, आप प्रक्रिया के पेड़ की एक चौड़ाई में एक बर्थ-प्रथम ट्रैवर्सल कर सकते हैं:

ps=2235; while [ "$ps" ]; do echo $ps; ps=$(echo $ps | xargs -n1 pgrep -P); \
  done | tail -n +2 | tr " " "\n"

एक पिड के सकर्मक-समापन की गणना के लिए, पूंछ भाग को छोड़ा जा सकता है।

ध्यान दें कि उपर्युक्त पुनरावृत्ति का उपयोग नहीं करता है और ksh-88 में भी चलता है।

लिनक्स पर, कोई pgrepकॉल को समाप्त कर सकता है और इसके बजाय से जानकारी पढ़ सकता है /proc:

ps=2235; while [ "$ps" ]; do echo $ps ; \
  ps=$(for p in $ps; do cat /proc/$p/task/$p/children; done); done \
  | tr " " "\n"' | tail -n +2

यह अधिक कुशल है क्योंकि हम प्रत्येक पीआईडी ​​के लिए एक कांटा / निष्पादन बचाते हैं और pgrepप्रत्येक कॉल में कुछ अतिरिक्त काम करते हैं।


1

इस लिनक्स संस्करण की जरूरत है / खरीद और पी एस केवल। यह @ maxschlepzig के उत्कृष्ट उत्तर के अंतिम टुकड़े से अनुकूलित है । यह संस्करण लूप में उप-प्रक्रिया को स्पॉन करने के बजाय सीधे शेल से पढ़ता / खरीदता है। यह थ्रेड शीर्षक अनुरोधों के अनुसार थोड़ा तेज़ और यकीनन थोड़ा अधिक सुरुचिपूर्ण है।

#!/bin/dash

# Print all descendant pids of process pid $1
# adapted from /unix//a/339071

ps=${1:-1}
while [ "$ps" ]; do
  echo $ps
  unset ps1 ps2
  for p in $ps; do
    read ps2 < /proc/$p/task/$p/children 2>/dev/null
    ps1="$ps1 $ps2"
  done
  ps=$ps1
done | tr " " "\n" | tail -n +2

0

आपके प्रत्येक दो (प्रतीत होता है बहुत कृत्रिम) मामलों में, आप कुछ दुर्भाग्यपूर्ण प्रक्रिया की उप-प्रक्रियाओं को क्यों मारना चाहते हैं? आप एक प्रक्रिया से बेहतर कैसे जान सकते हैं कि उसके बच्चों को कब जीना या मरना चाहिए? यह मुझे खराब डिजाइन की तरह लगता है; एक प्रक्रिया के बाद खुद को साफ करना चाहिए।

यदि आप वास्तव में बेहतर जानते हैं, तो आपको इन उप-प्रक्रियाओं का पालन करना चाहिए, और 'डीमॉनेटाइज़्ड प्रक्रिया' को जाहिर तौर पर बहुत अधिक गूंगा होना चाहिए fork(2)

आपको चाइल्ड प्रोसेस की सूची रखने से बचना चाहिए या प्रोसेस ट्री के माध्यम से ग्रोवेलिंग करना चाहिए, जैसे @Gilles द्वारा सुझाए गए एक अलग प्रोसेस ग्रुप में चाइल्ड प्रोसेस डालकर।

किसी भी मामले में, मुझे संदेह है कि उप-उप-उप-प्रक्रियाओं के एक गहरे पेड़ की तुलना में एक श्रमिक थ्रेड पूल (जो आवश्यक रूप से इसकी युक्त प्रक्रिया के साथ मर जाता है) बनाने से बेहतर होगा कि आपकी सफाई की प्रक्रिया बेहतर होगी। ।


2
दोनों उपयोग के मामलों का उपयोग निरंतर एकीकरण / परीक्षण वातावरण में किया जाता है, इसलिए उन्हें बच्चे की प्रक्रिया में मौजूद बग की संभावना से निपटना होगा। यह बग खुद को या अपने बच्चों को ठीक से बंद करने में असमर्थता के रूप में प्रकट हो सकता है, इसलिए मुझे यह सुनिश्चित करने का एक तरीका चाहिए कि मैं उन सभी को सबसे खराब स्थिति में बंद कर सकूं।
STENyaK

1
उस स्थिति में, मैं @ गिल्स और @ जेंडर के साथ हूं; प्रक्रिया समूह सबसे अच्छा तरीका है।
समेलीगीक

0

यहाँ एक pgrep आवरण स्क्रिप्ट है जो आपको pgrep का उपयोग करने देता है और एक ही समय में सभी वंश प्राप्त करता है।

~/bin/pgrep_wrapper:

#!/bin/bash

# the delimiter argument must be the first arg, otherwise it is ignored
delim=$'\n'
if [ "$1" == "-d" ]; then
    delim=$2
    shift 2
fi

pids=
newpids=$(pgrep "$@")
status=$?
if [ $status -ne 0 ]; then
    exit $status
fi

while [ "$pids" != "$newpids" ]; do
    pids=$newpids
    newpids=$( { echo "$pids"; pgrep -P "$(echo -n "$pids" | tr -cs '[:digit:]' ',')"; } | sort -u )
done
if [ "$delim" != $'\n' ]; then
    first=1
    for pid in $pids; do
        if [ $first -ne 1 ]; then
            echo -n "$delim"
        else
            first=0
        fi  
        echo -n "$pid"
    done
else
    echo "$pids"
fi

जिस तरह से आप सामान्य pgrep आह्वान करेंगे, उसी तरह लागू करें जैसे pgrep_recursive -U $USER javaकि वर्तमान उपयोगकर्ता से सभी जावा प्रक्रियाएँ और उप-प्रक्रियाएँ खोजें।


1
चूँकि यह bash है, इसलिए मुझे लगता है कि PIDs को सीमांकक के साथ मिलाने के लिए उपयोग किए जाने वाले कोड को IFSसरणियों ( "${array[*]}") के साथ प्रतिस्थापित किया जा सकता है ( ")
muru
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.