पृष्ठभूमि प्रक्रिया की प्रक्रिया आईडी कैसे प्राप्त करें?


375

मैं अपनी शेल स्क्रिप्ट से एक पृष्ठभूमि प्रक्रिया शुरू करता हूं, और जब मेरी स्क्रिप्ट खत्म हो जाएगी तो मैं इस प्रक्रिया को मारना चाहूंगा।

मेरे शेल स्क्रिप्ट से इस प्रक्रिया का पीआईडी ​​कैसे प्राप्त करें? जहाँ तक मैं देख सकता हूँ कि चर $!में वर्तमान स्क्रिप्ट का पीआईडी ​​है, न कि पृष्ठभूमि प्रक्रिया।


8
$! सही है। क्या आप वाकई BG में स्क्रिप्ट शुरू कर रहे हैं? नमूना कृपया।
पिक्सेलबीट

7
ह $! सही है। मैं गलत था।
वलोडिमिर बेजुग्ली

11
$$ में वर्तमान स्क्रिप्ट PID है।
हब

जवाबों:


582

जब आप इसे शुरू करते हैं, तो आपको पृष्ठभूमि प्रक्रिया के पीआईडी ​​को बचाने की आवश्यकता होती है:

foo &
FOO_PID=$!
# do other stuff
kill $FOO_PID

आप नौकरी पर नियंत्रण का उपयोग नहीं कर सकते हैं, क्योंकि यह एक इंटरैक्टिव सुविधा है और एक नियंत्रण टर्मिनल से बंधा है। एक स्क्रिप्ट में जरूरी नहीं कि एक टर्मिनल होगा, जिससे नौकरी पर नियंत्रण जरूरी नहीं होगा।


22
$ के बाद से! अंतिम बैकग्राउंड प्रोसेस की पिड लौटाता है। क्या यह संभव है कि दोनों के बीच कुछ शुरू होता है fooऔर $!, और हम के बजाय है कि कुछ के पीआईडी पाने fooके?
WiSaGaN

53
@WiSaGaN: नहीं। उन पंक्तियों के बीच कुछ भी नहीं है। सिस्टम पर कोई अन्य गतिविधि इसको प्रभावित नहीं करेगी। $! उस शेल में अंतिम पृष्ठभूमि प्रक्रिया के पीआईडी ​​तक विस्तारित होगा ।
Camh

8
... जो fooकई पाइप्ड कमांड (जैसे। tail -f somefile.txt | grep sometext) होने पर आपको खोखला कर देता है । ऐसे मामलों में, आपको $!टेल कमांड के बजाय ग्रीप कमांड का पीआईडी ​​मिलेगा यदि आप वही खोज रहे हैं जो आप चाहते थे। आपको इस उदाहरण में उपयोग jobsया psपसंद करने की आवश्यकता होगी ।
जॉन रिक्स

1
@ जॉनरिक्स: जरूरी नहीं। आप के पीआईडी ​​मिल जाएगा grep, लेकिन अगर आप इसे मारते हैं, तो पूंछ को पाइप से लिखने की कोशिश करने पर एक साइपिप मिलेगा। लेकिन जैसे ही आप किसी भी मुश्किल प्रक्रिया प्रबंधन / नियंत्रण में आने की कोशिश करते हैं, बैश / शेल काफी दर्दनाक हो जाता है।
camh

5
एक और योग्य समाधान (करने के लिए एक जवाब के लिए एक टिप्पणी) में सुझाव दिया है कैसे बस शुरू के PID करने के लिए ओह, और "oneliner": /bin/sh -c 'echo $$>/tmp/my.pid && exec program args' &- sysfault नवंबर 24 '10 14:28 पर
IMZ - इवान Zakharyaschev

148

आप jobs -lकिसी विशेष जॉब में जाने के लिए कमांड का उपयोग कर सकते हैं

^Z
[1]+  Stopped                 guard

my_mac:workspace r$ jobs -l
[1]+ 46841 Suspended: 18           guard

इस मामले में, 46841 पीआईडी ​​है।

से help jobs:

-L प्रक्रिया समूह आईडी और नौकरियों की कार्यशील निर्देशिका की रिपोर्ट करें।

jobs -p एक और विकल्प है जो सिर्फ पीआईडी ​​दिखाता है।


शेल स्क्रिप्ट में इसका उपयोग करने के लिए, आपको आउटपुट प्रोसेस करना होगा।
फिल

6
@ केवल सूचीबद्ध करने के लिए Phil: jobs -p। एक निश्चित नौकरी की सूची को सूचीबद्ध करने के लिए: नौकरियों -p% 3। आउटपुट को संसाधित करने की आवश्यकता नहीं है।
एरिक एरोनिटी

1
@ विभिन्न आदेशों / तर्कों के साथ आप मेरी टिप्पणी के संदर्भ को बदल दें। अतिरिक्त तर्क के बिना सुझाव दिया गया कि आउटपुट को प्रसंस्करण की आवश्यकता है। उत्तर के लिए सुधार का सुझाव दें!
फिल

$!आपके द्वारा शुरू किए जाने के बाद से पीआईडी ​​को सहेजना ज्यादातर स्थितियों में अधिक पोर्टेबल और अधिक सीधा है। वर्तमान में स्वीकृत जवाब यही है।
ट्रिपल

jobs -pjobs -lल्यूबुन्टू 16.4
टिमो

46
  • $$ वर्तमान स्क्रिप्ट की पिड है
  • $! अंतिम पृष्ठभूमि की प्रक्रिया है

यहाँ एक बैश सत्र से एक नमूना प्रतिलेख है ( %1पृष्ठभूमि प्रक्रिया की क्रमिक संख्या से जैसा कि देखा गया है jobs):

$ echo $$
3748

$ sleep 100 &
[1] 192

$ echo $!
192

$ kill %1

[1]+  Terminated              sleep 100

इको %1मेरे उबंटू पर पृष्ठभूमि की प्रक्रिया को वापस नहीं करता है जबकि echo $!करता है
टिमो

25

बैश स्क्रिप्ट की सभी बाल प्रक्रिया को मारने का एक सरल तरीका:

pkill -P $$

-Pध्वज के साथ उसी तरह काम करता pkillहै और pgrep- यह बच्चे प्रक्रियाओं हो जाता है, साथ ही pkillबच्चे प्रक्रियाओं को मार डाला और मिल के साथ pgrepबच्चे PIDs stdout में मुद्रित कर रहे हैं।


बहुत ही सुविधाजनक! यह सुनिश्चित करने का सबसे अच्छा तरीका है कि आप पृष्ठभूमि पर खुली प्रक्रियाओं को न छोड़ें।
लेप

@lepe: काफी नहीं। यदि आप एक दादा दादी हैं, तो यह काम नहीं करेगा: bash -c 'bash -c "sleep 300 &"' & दौड़ने के बाद pgrep -P $$कुछ भी नहीं दिखाता है, क्योंकि नींद आपके खोल का सीधा बच्चा नहीं होगी।
पेट्र

1
@AlexeyPolonsky: यह होना चाहिए: एक स्क्रिप्ट नहीं, एक खोल के सभी बच्चे को मार डालो। क्योंकि $$वर्तमान शेल को संदर्भित करता है।
तिमो

प्रदर्शन करते हुए bash -c 'bash -c "sleep 300 &"' & ; pgrep -P $$, मैं stdout [1] <pid>. So at least it shows something, but this is probably not the output of pgrep`
Timo

यहां तक ​​कि प्रक्रियाएं उन्हें मूल प्रक्रिया से अलग कर सकती हैं। सिंपल ट्रिक है फोर्क को कॉल करना (पोते का निर्माण करना) और फिर पोते के काम करते समय बच्चे को बाहर निकलने दें। (डीमॉनेटाइजेशन कीवर्ड है) लेकिन फिर भी अगर बच्चा बहुत ज्यादा pkill चल रहा है, तो पोते-पोतियों को सिग्नल फैलाने के लिए पर्याप्त नहीं है। संपूर्ण आश्रित प्रक्रिया वृक्ष का पालन करने के लिए pstree जैसे उपकरण की आवश्यकता होती है। लेकिन यह इस प्रक्रिया से शुरू हुए डेमन को पकड़ नहीं पाएगा क्योंकि उनके माता-पिता की प्रक्रिया 1 है। जैसे:bash -c 'bash -c "sleep 10 & wait $!"' & sleep 0.1; pstree -p $$
पाउली नीमिनेन

4

यही है जो मैने किया है। इसे देखें, आशा है कि यह मदद कर सकता है।

#!/bin/bash
#
# So something to show.
echo "UNO" >  UNO.txt
echo "DOS" >  DOS.txt
#
# Initialize Pid List
dPidLst=""
#
# Generate background processes
tail -f UNO.txt&
dPidLst="$dPidLst $!"
tail -f DOS.txt&
dPidLst="$dPidLst $!"
#
# Report process IDs
echo PID=$$
echo dPidLst=$dPidLst
#
# Show process on current shell
ps -f
#
# Start killing background processes from list
for dPid in $dPidLst
do
        echo killing $dPid. Process is still there.
        ps | grep $dPid
        kill $dPid
        ps | grep $dPid
        echo Just ran "'"ps"'" command, $dPid must not show again.
done

तो बस इसे चलाने के रूप में: ./bgkill.shपाठ्यक्रम की उचित अनुमति के साथ

root@umsstd22 [P]:~# ./bgkill.sh
PID=23757
dPidLst= 23758 23759
UNO
DOS
UID        PID  PPID  C STIME TTY          TIME CMD
root      3937  3935  0 11:07 pts/5    00:00:00 -bash
root     23757  3937  0 11:55 pts/5    00:00:00 /bin/bash ./bgkill.sh
root     23758 23757  0 11:55 pts/5    00:00:00 tail -f UNO.txt
root     23759 23757  0 11:55 pts/5    00:00:00 tail -f DOS.txt
root     23760 23757  0 11:55 pts/5    00:00:00 ps -f
killing 23758. Process is still there.
23758 pts/5    00:00:00 tail
./bgkill.sh: line 24: 23758 Terminated              tail -f UNO.txt
Just ran 'ps' command, 23758 must not show again.
killing 23759. Process is still there.
23759 pts/5    00:00:00 tail
./bgkill.sh: line 24: 23759 Terminated              tail -f DOS.txt
Just ran 'ps' command, 23759 must not show again.
root@umsstd22 [P]:~# ps -f
UID        PID  PPID  C STIME TTY          TIME CMD
root      3937  3935  0 11:07 pts/5    00:00:00 -bash
root     24200  3937  0 11:56 pts/5    00:00:00 ps -f

3

तुम भी pstree का उपयोग करने में सक्षम हो सकता है:

pstree -p user

यह आमतौर पर "उपयोगकर्ता" के लिए सभी प्रक्रियाओं का एक पाठ प्रतिनिधित्व देता है और -p विकल्प प्रक्रिया-आईडी देता है। यह निर्भर नहीं करता है, जहां तक ​​मैं समझता हूं, मौजूदा शेल के स्वामित्व वाली प्रक्रियाओं का होना चाहिए। यह कांटे भी दिखाता है।


1
शेल स्क्रिप्ट में इसका उपयोग करने के लिए, आपको आउटपुट को भारी प्रोसेस करना होगा।
फिल

1

pgrepआप एक माता पिता की प्रक्रिया के सभी बच्चे PIDs प्राप्त कर सकते हैं। जैसा कि पहले बताया गया $$है कि वर्तमान स्क्रिप्ट पीआईडी ​​है। इसलिए, यदि आप एक ऐसी स्क्रिप्ट चाहते हैं, जो खुद के बाद साफ हो जाए, तो यह काम करना चाहिए:

trap 'kill $( pgrep -P $$ | tr "\n" " " )' SIGINT SIGTERM EXIT

यह बहुत मार नहीं होगा?
फिल

हाँ, यह सवाल कभी भी बाहर निकलने पर कुछ पृष्ठभूमि के बच्चों को जीवित रखने का उल्लेख नहीं करता।
misant.info

trap 'pkill -P $$' SIGING SIGTERM EXITसरल दिखता है, लेकिन मैंने इसका परीक्षण नहीं किया।
पेट्रे

अनुकूलता के लिए, SIGउपसर्ग का उपयोग न करें । इसे POSIX द्वारा अनुमति दी गई है लेकिन सिर्फ एक विस्तार के रूप में जो कार्यान्वयन का समर्थन कर सकता है : pubs.opengroup.org/onlinepubs/007904975/utilities/trap.html उदाहरण के लिए डैश शैल नहीं है।
josch
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.