किसी प्रक्रिया समूह के सभी सदस्यों को संकेत भेजने का सबसे अच्छा तरीका क्या है?


422

मैं एक पूरी प्रक्रिया पेड़ को मारना चाहता हूं। किसी भी सामान्य स्क्रिप्टिंग भाषाओं का उपयोग करने का सबसे अच्छा तरीका क्या है? मैं एक सरल उपाय की तलाश में हूं।


3
जब सिस्टम फिर से चलता है तो लाश को दूर जाना चाहिए। मैं मानता हूँ कि मैंने ऐसे सिस्टम देखे हैं जहाँ लाश मिलती है, लेकिन यह असामान्य है।
ब्रायन नोब्लुच

7
कभी-कभी उन सुस्त लाश कुछ डरावनी गतिविधि के लिए जिम्मेदार होती हैं।
यूजर 1

में से एक का उपयोग करें chronosया herodesआदेशों।
माइकल ले बारबियर ग्रुएनवाल्ड

8
$ मारने (pstree <पीआईडी> -p -एक -l | कटौती -d, -f2 | कटौती -d '' -f1)
vrdhn

@ MichaelLeBarbierGrünewald क्या आप उन कार्यक्रमों से जुड़ सकते हैं?
स्टायरोफोम फ्लाई

जवाबों:


305

आप यह नहीं कहते कि जिस पेड़ को आप मारना चाहते हैं, वह एकल प्रक्रिया समूह है। (यह अक्सर ऐसा होता है यदि पेड़ एक सर्वर स्टार्ट या शेल कमांड लाइन से फोर्किंग का परिणाम है।) आप GNU ps का उपयोग करके प्रक्रिया समूहों की खोज कर सकते हैं:

 ps x -o  "%p %r %y %x %c "

यदि यह एक प्रक्रिया समूह है जिसे आप मारना चाहते हैं, तो केवल kill(1)कमांड का उपयोग करें लेकिन इसे एक प्रक्रिया संख्या देने के बजाय, इसे समूह संख्या का नकार दें । उदाहरण के लिए, समूह 5112 में हर प्रक्रिया को मारने के लिए उपयोग करें kill -TERM -- -5112


3
किल -74313 -बैश: किल: 74313: अमान्य सिग्नल विनिर्देश यदि मैं किल -15 को जोड़ता हूं -GPID यह पूरी तरह से काम करता है।
एडम पेक

51
लगभग किसी भी आदेश के साथ, यदि आप एक सामान्य तर्क चाहते हैं - जो कि एक के रूप में शुरू होता है - एक स्विच के रूप में व्याख्या नहीं किया जाना है, तो इसके साथ पूर्ववर्ती करें: - मारें
-GPID

9
pgrepप्रक्रिया समूह आईडी खोजने के लिए एक आसान तरीका प्रदान कर सकते हैं। उदाहरण के लिए, my-script.sh प्रक्रिया समूह को मारने के लिए, दौड़ें kill -TERM -$(pgrep -o my-script.sh)
जोश केली 13

9
पर बेहतर लग रहे stackoverflow.com/questions/392022/... अपने अब तक एक और अधिक सुरुचिपूर्ण समाधान द्वारा और यदि आप बच्चों की पीआईडी की सूचीबद्ध करने की आवश्यकता तो का उपयोग करें:ps -o pid --no-headers --ppid $PARENT_PID
ज़ीमॉन Jez

4
और यदि आप प्रारूप को थोड़ा और क्रमबद्ध रूप से संशोधित करते हैं, तो आपको सभी प्रक्रियाओं को अच्छी तरह से समूहीकृत और प्रत्येक समूह में समूह माता-पिता के साथ शुरुआत करते हुए देखने को मिलता है:ps x -o "%r %p %y %x %c" | sort -nk1,2
haridsv

199

प्रक्रिया समूह ID ( ) का उपयोग करके एक ही प्रक्रिया ट्री से संबंधित सभी प्रक्रियाओं को मारेंPGID

  • kill -- -$PGID     डिफ़ॉल्ट सिग्नल का उपयोग करें ( TERM= 15)
  • kill -9 -$PGID     संकेत का उपयोग करें KILL(9)

आप उसी प्रोसेस ट्री केPGID किसी भी प्रोसेस-आईडी ( PID) से पुनः प्राप्त कर सकते हैं

  • kill -- -$(ps -o pgid= $PID | grep -o '[0-9]*')   (संकेत TERM)
  • kill -9 -$(ps -o pgid= $PID | grep -o '[0-9]*')   (संकेत KILL)

विशेष धन्यवाद tanager और Speakus पर योगदान के लिए $PIDशेष रिक्त स्थान और OSX अनुकूलता।

व्याख्या

  • kill -9 -"$PGID"=> KILLसभी बच्चों और पोते को संकेत 9 ( ) भेजें ...
  • PGID=$(ps opgid= "$PID")=> प्रक्रिया-समूह-आईडी को पेड़ की किसी भी प्रक्रिया-आईडी से वापस लें, न केवल प्रक्रिया-अभिभावक-आईडी । का एक रूपांतर है ps opgid= $PID, ps -o pgid --no-headers $PIDजहां pgidसे प्रतिस्थापित किया जा सकता है pgrp
    परंतु:
    • psप्रमुख स्थान सम्मिलित करता है जब PIDपांच अंकों से कम होता है और तानागर द्वारा देखा गया ठीक संरेखित होता है । आप उपयोग कर सकते हैं:
      PGID=$(ps opgid= "$PID" | tr -d ' ')
    • psOSX से हमेशा हेडर प्रिंट होता है, इसलिए स्पीकस प्रस्ताव करता है:
      PGID="$( ps -o pgid "$PID" | grep [0-9] | tr -d ' ' )"
  • grep -o [0-9]* क्रमिक अंकों को केवल प्रिंट करता है (रिक्त स्थान या वर्णमाला हेडर को प्रिंट नहीं करता है)।

आगे कमांड लाइन

PGID=$(ps -o pgid= $PID | grep -o [0-9]*)
kill -TERM -"$PGID"  # kill -15
kill -INT  -"$PGID"  # correspond to [CRTL+C] from keyboard
kill -QUIT -"$PGID"  # correspond to [CRTL+\] from keyboard
kill -CONT -"$PGID"  # restart a stopped process (above signals do not kill it)
sleep 2              # wait terminate process (more time if required)
kill -KILL -"$PGID"  # kill -9 if it does not intercept signals (or buggy)

सीमा

  • जैसा कि डेविड और ह्यूबर्ट करियो द्वारा देखा गया है , जब killएक ही पेड़ से संबंधित प्रक्रिया द्वारा लगाया जाता है, killतो पूरे पेड़ की हत्या को समाप्त करने से पहले खुद को मारने का जोखिम होता है।
  • इसलिए, एक अलग प्रक्रिया-समूह-आईडी वाली प्रक्रिया का उपयोग करके कमांड चलाना सुनिश्चित करें ।

लम्बी कहानी

> cat run-many-processes.sh
#!/bin/sh
echo "ProcessID=$$ begins ($0)"
./child.sh background &
./child.sh foreground
echo "ProcessID=$$ ends ($0)"

> cat child.sh
#!/bin/sh
echo "ProcessID=$$ begins ($0)"
./grandchild.sh background &
./grandchild.sh foreground
echo "ProcessID=$$ ends ($0)"

> cat grandchild.sh
#!/bin/sh
echo "ProcessID=$$ begins ($0)"
sleep 9999
echo "ProcessID=$$ ends ($0)"

'और' का उपयोग करके प्रक्रिया ट्री को पृष्ठभूमि में चलाएं

> ./run-many-processes.sh &    
ProcessID=28957 begins (./run-many-processes.sh)
ProcessID=28959 begins (./child.sh)
ProcessID=28958 begins (./child.sh)
ProcessID=28960 begins (./grandchild.sh)
ProcessID=28961 begins (./grandchild.sh)
ProcessID=28962 begins (./grandchild.sh)
ProcessID=28963 begins (./grandchild.sh)

> PID=$!                    # get the Parent Process ID
> PGID=$(ps opgid= "$PID")  # get the Process Group ID

> ps fj
 PPID   PID  PGID   SID TTY      TPGID STAT   UID   TIME COMMAND
28348 28349 28349 28349 pts/3    28969 Ss   33021   0:00 -bash
28349 28957 28957 28349 pts/3    28969 S    33021   0:00  \_ /bin/sh ./run-many-processes.sh
28957 28958 28957 28349 pts/3    28969 S    33021   0:00  |   \_ /bin/sh ./child.sh background
28958 28961 28957 28349 pts/3    28969 S    33021   0:00  |   |   \_ /bin/sh ./grandchild.sh background
28961 28965 28957 28349 pts/3    28969 S    33021   0:00  |   |   |   \_ sleep 9999
28958 28963 28957 28349 pts/3    28969 S    33021   0:00  |   |   \_ /bin/sh ./grandchild.sh foreground
28963 28967 28957 28349 pts/3    28969 S    33021   0:00  |   |       \_ sleep 9999
28957 28959 28957 28349 pts/3    28969 S    33021   0:00  |   \_ /bin/sh ./child.sh foreground
28959 28960 28957 28349 pts/3    28969 S    33021   0:00  |       \_ /bin/sh ./grandchild.sh background
28960 28964 28957 28349 pts/3    28969 S    33021   0:00  |       |   \_ sleep 9999
28959 28962 28957 28349 pts/3    28969 S    33021   0:00  |       \_ /bin/sh ./grandchild.sh foreground
28962 28966 28957 28349 pts/3    28969 S    33021   0:00  |           \_ sleep 9999
28349 28969 28969 28349 pts/3    28969 R+   33021   0:00  \_ ps fj

कमांड pkill -P $PIDपोते को नहीं मारता:

> pkill -P "$PID"
./run-many-processes.sh: line 4: 28958 Terminated              ./child.sh background
./run-many-processes.sh: line 4: 28959 Terminated              ./child.sh foreground
ProcessID=28957 ends (./run-many-processes.sh)
[1]+  Done                    ./run-many-processes.sh

> ps fj
 PPID   PID  PGID   SID TTY      TPGID STAT   UID   TIME COMMAND
28348 28349 28349 28349 pts/3    28987 Ss   33021   0:00 -bash
28349 28987 28987 28349 pts/3    28987 R+   33021   0:00  \_ ps fj
    1 28963 28957 28349 pts/3    28987 S    33021   0:00 /bin/sh ./grandchild.sh foreground
28963 28967 28957 28349 pts/3    28987 S    33021   0:00  \_ sleep 9999
    1 28962 28957 28349 pts/3    28987 S    33021   0:00 /bin/sh ./grandchild.sh foreground
28962 28966 28957 28349 pts/3    28987 S    33021   0:00  \_ sleep 9999
    1 28961 28957 28349 pts/3    28987 S    33021   0:00 /bin/sh ./grandchild.sh background
28961 28965 28957 28349 pts/3    28987 S    33021   0:00  \_ sleep 9999
    1 28960 28957 28349 pts/3    28987 S    33021   0:00 /bin/sh ./grandchild.sh background
28960 28964 28957 28349 pts/3    28987 S    33021   0:00  \_ sleep 9999

कमांड kill -- -$PGIDपोते सहित सभी प्रक्रियाओं को मारता है।

> kill --    -"$PGID"  # default signal is TERM (kill -15)
> kill -CONT -"$PGID"  # awake stopped processes
> kill -KILL -"$PGID"  # kill -9 to be sure

> ps fj
 PPID   PID  PGID   SID TTY      TPGID STAT   UID   TIME COMMAND
28348 28349 28349 28349 pts/3    29039 Ss   33021   0:00 -bash
28349 29039 29039 28349 pts/3    29039 R+   33021   0:00  \_ ps fj

निष्कर्ष

मैं इस उदाहरण में देखता हूं PIDऔर PGIDबराबर ( 28957) हैं।
यही कारण है कि मुझे लगता है कि मूल रूप kill -- -$PIDसे पर्याप्त था। लेकिन मामले में प्रक्रिया के भीतर एक अंडे है प्रक्रिया आईडी से अलग है समूह आईडीMakefile

मुझे लगता kill -- -$(ps -o pgid= $PID | grep -o [0-9]*)है कि एक अलग समूह आईडी (एक अन्य प्रक्रिया ट्री) से कॉल करने पर पूरी प्रक्रिया ट्री को मारने के लिए सबसे सरल सरल चाल है ।


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

3
यह केवल तभी काम करता है जब उप-आदेश स्वयं समूह लीडर न बनें। यहां तक ​​कि ऐसे सरल उपकरण भी manऐसा करते हैं। दूसरी ओर, यदि आप बाल प्रक्रिया से गैंडचिल्ड प्रक्रिया को मारना चाहते हैं, तो kill -- -$pidकाम नहीं करेगा। तो यह सामान्य समाधान नहीं है।
ह्यूबर्ट करियो

1
इसका उदाहरण "बच्चे" है जो अपने बच्चों को मारने की कोशिश कर रहा है (इसलिए उपयोगकर्ता के पोते ने कमांड शुरू की)। IOW, पृष्ठभूमि प्रक्रिया को पदानुक्रम में मारने का प्रयास करें child.sh
ह्यूबर्ट करियो

1
> किल-आईआईटी - "$ पीजीआईडी" # कीबोर्ड से [CRTL + C] के समान संकेत ---- QUIT को INT में बदल दिया जाना चाहिए
मैक्सिम खोलियाक्विन

1
OSX विकल्प के लिए - कोई हेडर समर्थित नहीं है, इसलिए कोड को अपडेट किया जाना चाहिए: PGID = "$ (ps-pgid" $ PID "| grep [0-9] | tr -d '')"
Maxim Hholyavkin

166
pkill -TERM -P 27888

यह उन सभी प्रक्रियाओं को मार देगा जिनकी मूल प्रक्रिया ID 27888 है।

या अधिक मजबूत:

CPIDS=$(pgrep -P 27888); (sleep 33 && kill -KILL $CPIDS &); kill -TERM $CPIDS

कौन सा समय बाद में 33 सेकंड की हत्या और समय-समय पर प्रक्रियाओं को समाप्त करने के लिए पूछना।

सभी वंशजों को समाप्त करने के लिए यह उत्तर देखें ।


19
मेरे त्वरित परीक्षण में, pgrep ने केवल तत्काल बच्चों की सूचना दी, इसलिए यह पूरी पदानुक्रम को नहीं मार सकता है।
हरदिवस

10
मैं @haridsv से सहमत हूं: pkill -Pबच्चे को सिग्नल भेजता है => पोते को सिग्नल नहीं मिलता है => इसलिए मैंने उसे समझाने के लिए एक और जवाब दिया है। चीयर्स ;-)
ओलिब्रे

1
एक बैश स्क्रिप्ट से, अपने बच्चों को मारने के लिए, उपयोग करें pkill -TERM -P ${$}
फ्रांस्वा ब्यूसोलिल

3
@Onlyjob, क्या यह सोने के लिए खतरनाक नहीं है? इस बीच ओएस द्वारा प्रक्रिया आईडी का पुन: उपयोग किया जा सकता है: आप उन प्रक्रियाओं को मार रहे होंगे जो अब आपके बच्चे नहीं हैं। मुझे संदेह है कि इस बारे में सुनिश्चित करने के लिए pkill को फिर से कॉल करना होगा।
फ्रांस्वा ब्यूसोलिल

2
@Onlyjob FYI करें, मैं अपनी मशीन पर 19 सेकंड से भी कम समय में प्रकाश I / O पहुंच के साथ 32768 प्रक्रियाएँ, सिंगल थ्रेडेड करने में सक्षम हूं:$ time for i in {1..32768}; do ( echo $BASHPID >> pids ); done real 0m18.860s
cychoi

102

पुनरावर्ती पेड़ की प्रक्रिया को मारने के लिए, किल्ट्री () का उपयोग करें:

#!/bin/bash

killtree() {
    local _pid=$1
    local _sig=${2:--TERM}
    kill -stop ${_pid} # needed to stop quickly forking parent from producing children between child killing and parent killing
    for _child in $(ps -o pid --no-headers --ppid ${_pid}); do
        killtree ${_child} ${_sig}
    done
    kill -${_sig} ${_pid}
}

if [ $# -eq 0 -o $# -gt 2 ]; then
    echo "Usage: $(basename $0) <pid> [signal]"
    exit 1
fi

killtree $@

3
ओएस एक्स पर काम नहीं --करने के तर्क । psइसे वहां काम करने के लिए psकमान द्वारा प्रतिस्थापित करें : ps ax -o "pid= ppid=" | grep -E "${_regex}" | sed -E "s/${_regex}/\1/gजहां लूप _regexसे पहले परिभाषित किया गया forहै:local _regex="[ ]*([0-9]+)[ ]+${_pid}"
आर्टूर

5
बंद प्रक्रियाओं SIGTERM के साथ मारे नहीं जाते। मेरा जवाब
x-yuri

1
! -1 का उपयोग करता है # / bin / # के बजाय पार्टी / usr / bin / env बैश (या बेहतर अभी तक POSIX केवल निर्माणों और / bin / श)!
अच्छा व्यक्ति

क्या killtree()मज़बूती से काम करने की गारंटी देने के लिए SIGKILL की जगह SIGKILL भेजना पर्याप्त होगा ?
डैविड

3
अगर psसमर्थन नहीं करता है --ppid, तो pgrep -P ${_pid}इसके बजाय एक उपयोग कर सकते हैं
ह्यूबर्ट करियो

16

rkill से आदेश pslist पैकेज संकेत (या दिए गए भेजता हैSIGTERMनिर्दिष्ट प्रक्रिया और उसके सभी वंशजों को डिफ़ॉल्ट रूप से):

rkill [-SIG] pid/name...

11

ब्रैड का उत्तर वह है जो मैं भी सुझाऊंगा, सिवाय इसके कि awkयदि आप --ppidविकल्प का उपयोग करते हैं तो आप पूरी तरह से दूर कर सकते हैं ps

for child in $(ps -o pid -ax --ppid $PPID) do ....... done

यह मेरे लिए तब तक काम नहीं करता जब तक कि मैं किसी कारण के लिए -ax को बाहर नहीं निकालता (Centos5)। अन्यथा यह महान है!
xitrium

9

यदि आप जानते हैं कि मूल प्रक्रिया के बीच से गुजरना है, तो यहां एक शेल स्क्रिप्ट है जो काम करना चाहिए:

for child in $(ps -o pid,ppid -ax | \
   awk "{ if ( \$2 == $pid ) { print \$1 }}")
do
  echo "Killing child process $child because ppid = $pid"
  kill $child
done

यदि आप "कुल्हाड़ी" के बजाय "-ax" का उपयोग करते हैं तो ps के कुछ संस्करण एक चेतावनी फेंक देंगे। इस प्रकार: $ $ में बच्चे के लिए (ps -o pid, ppid ax। \ Awk "{if (($ $ 2 == $ pid) {प्रिंट \ $ 1}}")
Cory R. King

9

मैं यहाँ वर्णित विधि के एक छोटे से संशोधित संस्करण का उपयोग करता हूं: https://stackoverflow.com/a/5311362/563175

तो ऐसा लगता है कि:

kill `pstree -p 24901 | sed 's/(/\n(/g' | grep '(' | sed 's/(\(.*\)).*/\1/' | tr "\n" " "`

जहां 24901 माता-पिता की पीआईडी ​​है।

यह बहुत बदसूरत लग रहा है, लेकिन यह पूरी तरह से काम करता है।


1
जीआरपी के साथ सरल, सीड के बजाय ...pstree -p 24901 | grep -oP '(?<=\()[0-9]+(?=\))'
ऐशसेन

2
आप जोड़ना चाहिए -lकरने के लिए pstreeहै, तो लंबी लाइनों न काट; इसे पढ़ने के लिए और भी सरल बनाया जा सकता है kill `pstree -l -p 24901 |grep "([[:digit:]]*)" -o |tr -d '()'`( \nस्थान को रूपांतरित करने की आवश्यकता नहीं है क्योंकि यह ठीक काम करेगा), thx!
कुंभ राशि पॉवर

9

Zhigang के उत्तर का संशोधित संस्करण:

#!/usr/bin/env bash
set -eu

killtree() {
    local pid
    for pid; do
        kill -stop $pid
        local cpid
        for cpid in $(pgrep -P $pid); do
            killtree $cpid
        done
        kill $pid
        kill -cont $pid
        wait $pid 2>/dev/null || true
   done
}

cpids() {
    local pid=$1 options=${2:-} space=${3:-}
    local cpid
    for cpid in $(pgrep -P $pid); do
        echo "$space$cpid"
        if [[ "${options/a/}" != "$options" ]]; then
            cpids $cpid "$options" "$space  "
        fi
    done
}

while true; do sleep 1; done &
cpid=$!
for i in $(seq 1 2); do
    cpids $$ a
    sleep 1
done
killtree $cpid
echo ---
cpids $$ a

आप wait $pidकेवल उन प्रक्रियाओं पर ही चल सकते हैं जो आपने शुरू की हैं, न कि सभी पूर्वाग्रहों से, इसलिए यह एक सामान्य समाधान नहीं है
ह्यूबर्ट करियो

@ हूबर्ट करियो उस मामले में, प्रतीक्षा केवल गैर-शून्य स्थिति से बाहर निकलेगी और स्क्रिप्ट को निष्पादित करना जारी रखेगी। क्या मै गलत हु? लेकिन अगर यह बच्चा है तो संदेश waitको दबा देगा Terminated
x- यूरी

9

मैं टिप्पणी नहीं कर सकता (पर्याप्त प्रतिष्ठा नहीं), इसलिए मुझे एक नया उत्तर जोड़ने के लिए मजबूर किया जाता है , भले ही यह वास्तव में उत्तर नहीं है।

28 फरवरी को @olibre द्वारा दिए गए अन्यथा बहुत अच्छे और गहन उत्तर के साथ थोड़ी समस्या है। उत्पादन में ps opgid= $PIDपांच अंकों से कम पीआईडी ​​के लिए प्रमुख स्थान होंगे क्योंकि psकॉलम को सही करना है (रिग संख्‍या संरेखित करें)। संपूर्ण कमांड लाइन के भीतर, यह एक नकारात्मक संकेत देता है, इसके बाद स्पेस (एस), उसके बाद समूह पीआईडी। रिक्त स्थान को हटाने के लिए सरल उपाय पाइप psहै tr:

kill -- -$( ps opgid= $PID | tr -d ' ' )

शुक्रिया तानगर। मैं अपना उत्तर ठीक करूंगा;) चीयर्स
ओलिब्रे

8

नॉर्मन रैमसे के जवाब में जोड़ने के लिए, यदि आप एक प्रक्रिया समूह बनाना चाहते हैं, तो यह सेटसाइड को देखने के लायक हो सकता है।
http://pubs.opengroup.org/onlinepubs/009695399/functions/setsid.html

सेटिंग () फ़ंक्शन एक नया सत्र बनाएगा, अगर कॉलिंग प्रक्रिया एक प्रक्रिया समूह नेता नहीं है। लौटने पर कॉलिंग प्रक्रिया इस नए सत्र का सत्र नेता होगी, एक नई प्रक्रिया समूह का प्रोसेस ग्रुप लीडर होगा, और इसका कोई नियंत्रण टर्मिनल नहीं होगा। कॉलिंग प्रक्रिया की प्रक्रिया समूह आईडी, कॉलिंग प्रक्रिया की प्रक्रिया आईडी के बराबर सेट की जाएगी। कॉलिंग प्रक्रिया नई प्रक्रिया समूह में एकमात्र प्रक्रिया और नए सत्र में एकमात्र प्रक्रिया होगी।

जो मुझे लगता है कि आप शुरू करने की प्रक्रिया से एक समूह बना सकते हैं। मैंने इसे php में इस्तेमाल किया ताकि इसे शुरू करने के बाद एक पूरी प्रक्रिया पेड़ को मारने में सक्षम हो।

यह एक बुरा विचार हो सकता है। मुझे टिप्पणियों में दिलचस्पी होगी।


वास्तव में यह एक महान विचार है और बहुत अच्छी तरह से काम करता है। मैं उन मामलों में इसका उपयोग कर रहा हूं जहां मैं एक ही प्रक्रिया समूह में प्रक्रियाएं डाल सकता हूं (या वे एक ही समूह में पहले से ही हैं)।
बीमारी

7

Ysth की टिप्पणी से प्रेरित है

kill -- -PGID

इसे प्रक्रिया संख्या देने के बजाय, इसे समूह संख्या का नकार दें। जैसा कि लगभग किसी भी आदेश के साथ होता है, यदि आप एक सामान्य तर्क चाहते हैं जो कि -एक स्विच के रूप में व्याख्या नहीं किया जाना शुरू होता है , तो इसके साथ पहले--


उफ़, मुझे एहसास हुआ है कि मैंने आपको वही जवाब दिया है जो आपने => +1 किया है। लेकिन इसके अलावा मैं समझाता हूँ कि कैसे बस से मिलता PGIDहै PID। तुम क्या सोचते हो? चीयर्स
ओलिब्रे

5

निम्नलिखित शेल फ़ंक्शन कई अन्य उत्तरों के समान है, लेकिन यह बाहरी निर्भरता के बिना लिनक्स और बीएसडी (ओएस एक्स, आदि) दोनों पर काम करता है जैसे pgrep:

killtree() {
    local parent=$1 child
    for child in $(ps -o ppid= -o pid= | awk "\$1==$parent {print \$2}"); do
        killtree $child
    done
    kill $parent
}

मुझे लगता है कि आपके पास 2 पंक्ति के अंत में अतिरिक्त शब्द "बच्चा" है।
Mato

@ ममाटो - यह अतिरिक्त नहीं है। यह $childउस फ़ंक्शन के दायरे को सीमित करता है ताकि एक ही नाम के साथ अन्य (गैर-स्थानीय) चर को परेशान न करें और यह सुनिश्चित करें कि फ़ंक्शन समाप्त होने के बाद स्थानीय चर का मान साफ ​​हो जाए।
एडम काट्ज

ओह, मैं अब देख रहा हूं, मुझे लगा कि यह असाइनमेंट का हिस्सा है। मुझे लगता है कि मुझे एक टिप्पणी लिखने से पहले (धीमी) फिर से पढ़ना चाहिए। :) धन्यवाद।
मटका

Btw, क्या बच्चों की सूची बनाना बेहतर नहीं होगा और फिर शीर्ष (माता-पिता) से हत्या शुरू हो जाएगी? .. इस प्रकार हम एक ऐसी स्थिति से बच सकते हैं जब कोई अभिभावक बच्चे का पुन: निर्माण करता है या अगले कोड को जारी रखता है जो संभावित रूप से व्यवहार को बदल सकता है।
मटका

5

Psutil का उपयोग करके अजगर के साथ ऐसा करना आसान है । बस पाइप के साथ psutil स्थापित करें और फिर आपके पास प्रक्रिया हेरफेर उपकरण का एक पूरा सूट है:

def killChildren(pid):
    parent = psutil.Process(pid)
    for child in parent.get_children(True):
        if child.is_running():
            child.terminate()

5

Zhigang के जवाब के आधार पर, यह आत्म-हत्या से बचता है:

init_killtree() {
    local pid=$1 child

    for child in $(pgrep -P $pid); do
        init_killtree $child
    done
    [ $pid -ne $$ ] && kill -kill $pid
}

4

यदि आप किसी प्रक्रिया को नाम से मारना चाहते हैं:

killall -9 -g someprocessname

या

pgrep someprocessname | xargs pkill -9 -g

3

यह बैश स्क्रिप्ट का उपयोग करके सभी बच्चे प्रक्रियाओं को मारने का मेरा संस्करण है। यह पुनरावृत्ति का उपयोग नहीं करता है और pgrep कमांड पर निर्भर करता है।

उपयोग

killtree.sh PID SIGNAL

Killtrees.sh की सामग्री

#!/bin/bash
PID=$1
if [ -z $PID ];
then
    echo "No pid specified"
fi

PPLIST=$PID
CHILD_LIST=`pgrep -P $PPLIST -d,`

while [ ! -z "$CHILD_LIST" ]
do
    PPLIST="$PPLIST,$CHILD_LIST"
    CHILD_LIST=`pgrep -P $CHILD_LIST -d,`
done

SIGNAL=$2

if [ -z $SIGNAL ]
then
    SIGNAL="TERM"
fi
#do substring from comma to space
kill -$SIGNAL ${PPLIST//,/ }

1
यह विफल हो जाएगा, अगर बच्चे की सूची के निर्माण के बाद नई प्रक्रियाएं बनाई जाती हैं।
छत

3

यहाँ @ ज़िगैंग के उत्तर की भिन्नता है जो AWK के बिना करता है, जो केवल बैश के देशी पार्सिंग संभावनाओं पर निर्भर करता है:

function killtree {
  kill -STOP "$1"
  ps -e -o pid= -o ppid= | while read -r pid ppid
                           do
                             [[ $ppid = $1 ]] || continue
                             killtree "$pid"  || true # Skip over failures
                           done
  kill -CONT "$1"          
  kill -TERM "$1"
}

यह मैक और लिनक्स दोनों पर ठीक काम करता है। उन स्थितियों में जहां आप प्रक्रिया समूहों को प्रबंधित करने में सक्षम नहीं हो सकते हैं - जैसे कि सॉफ्टवेयर के एक टुकड़े के परीक्षण के लिए स्क्रिप्ट लिखते समय, जिसे कई वातावरणों में बनाया जाना चाहिए - यह ट्री-वॉकिंग तकनीक निश्चित रूप से सहायक है।


1

आपके ज्ञान, लोगों के लिए धन्यवाद। मेरी स्क्रिप्ट कुछ बाल प्रक्रियाओं को बाहर निकलने पर छोड़ रही थी और नकारात्मक टिप ने चीजों को आसान बना दिया। यदि आवश्यक हो तो मैंने इस फ़ंक्शन को अन्य लिपियों में उपयोग करने के लिए लिखा है:

# kill my group's subprocesses:          killGroup
# kill also myself:                      killGroup -x
# kill another group's subprocesses:     killGroup N  
# kill that group all:                   killGroup -x N
# N: PID of the main process (= process group ID).

function killGroup () {
    local prid mainpid
    case $1 in
        -x) [ -n "$2" ] && kill -9 -$2 || kill -9 -$$ ;;
        "") mainpid=$$ ;;
         *) mainpid=$1 ;;
    esac
    prid=$(ps ax -o pid,pgid | grep $mainpid)
    prid=${prid//$mainpid/}
    kill -9 $prid 2>/dev/null
    return
}

चीयर्स।


1

यदि आपके पास अपने सिस्टम पर pstree और perl है, तो आप यह कोशिश कर सकते हैं:

perl -e 'kill 9, (`pstree -p PID` =~ m/\((\d+)\)/sg)'

1

बच्चों से पहले माता-पिता को मारना बेहतर है; अन्यथा माता-पिता अपने बच्चों को मारने से पहले नए बच्चों को फिर से पाल सकते हैं। ये हत्या से बच जाएंगे।

मेरे ps का संस्करण उस से अलग है; शायद बहुत पुराना है, इसलिए अजीब अजीब ...

शेल फ़ंक्शन के बजाय शेल स्क्रिप्ट का उपयोग करने के कई फायदे हैं ...

हालांकि, यह मूल रूप से zhigangs विचार है


#!/bin/bash
if test $# -lt 1 ; then
    echo >&2 "usage: kiltree pid (sig)"
fi ;

_pid=$1
_sig=${2:-TERM}
_children=$(ps j | grep "^[ ]*${_pid} " | cut -c 7-11) ;
echo >&2 kill -${_sig} ${_pid}
kill -${_sig} ${_pid}
for _child in ${_children}; do
    killtree ${_child} ${_sig}
done

ध्यान दें कि @zhighang स्क्रिप्ट मूल प्रक्रिया का संकेत देती है और रोकी गई प्रक्रिया को संकेत प्रदान करती है, इसलिए यह (AFAIK) प्रक्रिया और बच्चों के निर्माण और सिग्नल वितरण के बीच दौड़ की स्थिति का कारण नहीं होना चाहिए। हालांकि आपके संस्करण में बच्चों की सूची प्राप्त करने और माता-पिता को सिग्नल देने के बीच दौड़ है।
ह्यूबर्ट करियो

1

निम्नलिखित को FreeBSD, Linux और MacOS X पर परीक्षण किया गया है और यह केवल pgrep और किल (ps -o संस्करण BSD के तहत काम नहीं करता है) पर निर्भर करता है। पहला तर्क माता-पिता का है जिसमें बच्चों को समाप्त किया जाना है। दूसरा तर्क यह निर्धारित करने के लिए एक बूलियन है कि क्या मूल पिड को भी समाप्त करना है।

KillChilds() {
        local pid="${1}"
        local self="${2:-false}"

        if children="$(pgrep -P "$pid")"; then
                for child in $children; do
                        KillChilds "$child" true
                done
        fi

        if [ "$self" == true ]; then
                kill -s SIGTERM "$pid" || (sleep 10 && kill -9 "$pid" &)
        fi
}

KillChilds $$ > /dev/null 2>&1

यह एक शेल स्क्रिप्ट के भीतर किसी भी बच्चे / पोते की प्रक्रिया में SIGTERM भेजेगा और अगर SIGTERM सफल नहीं होता है, तो यह 10 सेकंड प्रतीक्षा करेगा और फिर किल भेज देगा।


पहले उत्तर:

निम्नलिखित भी काम करता है लेकिन बीएसडी पर शेल को मार देगा।

KillSubTree() {
    local parent="${1}"
    for child in $(ps -o pid=$parent); do
            if [ $$ -ne $child ]; then (kill -s SIGTERM $child || (sleep 10 && kill -9 $child & )) > /dev/null 2>&1 ; fi
    done
}
# Example lanch from within script
KillSubTree $$ > /dev/null 2>&1

1

मैं ज़ियागंग, ज़्युरी और सोलिड्सनेक के समाधान को और विकसित करता हूं:

 #!/bin/bash

if test $# -lt 1 ; then
    echo >&2 "usage: kiltree pid (sig)"
    exit 1 ;
  fi ;

_pid=$1
_sig=${2:-TERM}

# echo >&2 "killtree($_pid) mypid = $$"
# ps axwwf | grep -6 "^[ ]*$_pid " >&2 ;

function _killtree () {
    local _children
    local _child
    local _success

    if test $1 -eq $2 ; then # this is killtree - don't commit suicide!
        echo >&2 "killtree can´t kill it´s own branch - some processes will survive." ; 
        return 1 ;
      fi ;
    # this avoids that children are spawned or disappear.
    kill -SIGSTOP $2 ;

    _children=$(ps -o pid --no-headers --ppid $2) ;        
    _success=0 
    for _child in ${_children}; do
        _killtree $1 ${_child} $3 ;
        _success=$(($_success+$?)) ;
      done ;

    if test $_success -eq 0 ; then
        kill -$3 $2
      fi ;
    # when a stopped process is killed, it will linger in the system until it is continued
    kill -SIGCONT $2
    test $_success -eq 0 ;
    return $?
    }

_killtree $$ $_pid $_sig

यह संस्करण अपने वंश को मारने से बच जाएगा - जो पिछले समाधानों में बच्चे की प्रक्रियाओं की बाढ़ का कारण बनता है।

चाइल्ड लिस्ट निर्धारित होने से पहले प्रक्रियाओं को ठीक से रोक दिया जाता है, ताकि कोई नया बच्चा न बने या गायब न हो।

मारे जाने के बाद, रुकी हुई नौकरियों को सिस्टम से गायब होना जारी रखना होगा।


1

पुराना सवाल है, मुझे पता है, लेकिन सभी प्रतिक्रियाएं कॉलिंग पीएस रखने के लिए लगती हैं, जो मुझे पसंद नहीं था।

इस awk- आधारित समाधान पुनरावृत्ति की आवश्यकता नहीं है और केवल एक बार पीएस कहता है।

awk 'BEGIN {
  p=1390
  while ("ps -o ppid,pid"|getline) a[$1]=a[$1]" "$2
  o=1
  while (o==1) {
    o=0
    split(p, q, " ")
    for (i in q) if (a[q[i]]!="") {
      p=p""a[q[i]]
      o=1
      a[q[i]]=""
    }
  }
  system("kill -TERM "p)
}'

या एकल-पंक्ति पर:

awk 'BEGIN {p=1390;while ("ps -o ppid,pid"|getline) a[$1]=a[$1]" "$2;o=1;while (o==1) {o=0;split(p, q, " ");for (i in q) {if (a[q[i]]!="") {p=p""a[q[i]];o=1;a[q[i]]=""}}}system("kill -TERM "p)}'

मूल रूप से यह विचार है कि हम अभिभावकों की एक सरणी (ए) का निर्माण करते हैं: बच्चे की प्रविष्टियां, फिर हमारे मिलान वाले माता-पिता के लिए बच्चों को खोजने वाले सरणी के चारों ओर लूप करें, उन्हें अपने माता-पिता की सूची (पी) में जोड़ दें।

यदि आप शीर्ष-स्तरीय प्रक्रिया को मारना नहीं चाहते हैं, तो कर रहे हैं

sub(/[0-9]*/, "", p)

सिस्टम के ठीक पहले () लाइन इसे किल सेट से हटा देगी।

ध्यान रखें कि यहाँ एक रेस की स्थिति है, लेकिन यह सच है (जहाँ तक मैं देख सकता हूँ) सभी समाधानों में से। यह वही करता है जो मुझे चाहिए था क्योंकि स्क्रिप्ट जिसकी मुझे आवश्यकता थी वह बहुत से अल्पकालिक बच्चे पैदा नहीं करता है।

पाठक के लिए एक व्यायाम इसे 2-पास लूप बनाने के लिए होगा: पहले पास के बाद, पी सूची में सभी प्रक्रियाओं को SIGSTOP भेजें, फिर ps को फिर से चलाने के लिए लूप करें और दूसरे पास के बाद SIGTERM, फिर SIGCONT भेजें। यदि आप अच्छे अंत के बारे में परवाह नहीं करते हैं, तो सेकंड-पास सिर्फ SIGKILL हो सकता है, मुझे लगता है।


0

यदि आप उस चीज़ के बारे में जानते हैं जिसे आप मारना चाहते हैं, तो आप आमतौर पर सत्र आईडी और उसी सत्र में सब कुछ से जा सकते हैं। मैं दोबारा जाँच करूँगा, लेकिन मैंने लिपियों में rsyncs शुरू करने वाली लिपियों के लिए इसका उपयोग किया था जो कि मैं मरना चाहता हूँ, और दूसरा (लूप के कारण) शुरू नहीं करना चाहता क्योंकि अगर मैं सिर्फ rsync को मार देता।

kill $(ps -o pid= -s $(ps -o sess --no-heading --pid 21709))

यदि आप नहीं जानते कि आप अभी भी अधिक घोंसला कर सकते हैं

kill $(ps -o pid= -s $(ps -o sess --no-heading --pid $(pgrep rsync )))


0

शोज़ नौकरियों में पृष्ठभूमि प्रक्रियाओं को सूचीबद्ध करेगा। कुछ मामलों में सबसे पहले नवीनतम प्रक्रिया को मारना बेहतर हो सकता है, जैसे कि पुराने ने एक साझा सॉकेट बनाया। उन मामलों में पीआईडी ​​को रिवर्स ऑर्डर में सॉर्ट करें। कभी-कभी आप नौकरियों के लिए डिस्क या सामान की तरह कुछ लिखने से पहले रुकना चाहते हैं, इससे पहले कि वे रुकें।

और अगर तुम्हें नहीं करना है तो मत मारो!

for SIGNAL in TERM KILL; do
  for CHILD in $(jobs -s|sort -r); do
    kill -s $SIGNAL $CHILD
    sleep $MOMENT
  done
done

0

शेल स्क्रिप्ट में बाल प्रक्रिया को मारना:

कई बार हमें बाल प्रक्रिया को मारने की आवश्यकता होती है जो किसी कारण से फंसी या अवरुद्ध हो जाती हैं। जैसे। एफ़टीपी कनेक्शन मुद्दा।

दो दृष्टिकोण हैं,

1) प्रत्येक बच्चे के लिए अलग-अलग नए माता-पिता बनाना जो समयबाह्य होने पर बाल प्रक्रिया की निगरानी और मार करेंगे।

Test.sh इस प्रकार बनाएँ,

#!/bin/bash

declare -a CMDs=("AAA" "BBB" "CCC" "DDD")
for CMD in ${CMDs[*]}; do
    (sleep 10 & PID=$!; echo "Started $CMD => $PID"; sleep 5; echo "Killing $CMD => $PID"; kill $PID; echo "$CMD Completed.") &
done
exit;

और निम्नलिखित प्रक्रियाओं का उपयोग करके अन्य टर्मिनल में 'परीक्षण' के रूप में नाम होने वाली प्रक्रियाओं को देखें।

watch -n1 'ps x -o "%p %r %c" | grep "test" '

ऊपर स्क्रिप्ट 4 नए बच्चे की प्रक्रिया और उनके माता-पिता बनाएंगे। प्रत्येक बच्चे की प्रक्रिया 10sec के लिए चलेगी। लेकिन 5sec तक पहुंचने के बाद, संबंधित संबंधित मूल प्रक्रियाएं उन बच्चों को मार डालेंगी। इसलिए बच्चा निष्पादन (10sec) पूरा नहीं कर पाएगा। एक और व्यवहार देखने के लिए उन टाइमिंग (10 और 5 स्विच करें) के आसपास खेलें। उस स्थिति में बच्चा 10sec के समय से पहले 5sec में निष्पादन समाप्त कर देगा।

2) वर्तमान माता-पिता की निगरानी करें और समय समाप्त होने पर बच्चे की प्रक्रिया को मार दें। यह प्रत्येक बच्चे की निगरानी के लिए अलग-अलग माता-पिता नहीं बनाएगा। इसके अलावा, आप एक ही माता-पिता के भीतर सभी बाल प्रक्रियाओं को ठीक से प्रबंधित कर सकते हैं।

Test.sh इस प्रकार बनाएँ,

#!/bin/bash

declare -A CPIDs;
declare -a CMDs=("AAA" "BBB" "CCC" "DDD")

CMD_TIME=15;
for CMD in ${CMDs[*]}; do
    (echo "Started..$CMD"; sleep $CMD_TIME; echo "$CMD Done";) &
    CPIDs[$!]="$RN";
    sleep 1;
done

GPID=$(ps -o pgid= $$);
CNT_TIME_OUT=10;
CNT=0;
while (true); do
    declare -A TMP_CPIDs;

    for PID in "${!CPIDs[@]}"; do
        echo "Checking "${CPIDs[$PID]}"=>"$PID;

        if ps -p $PID > /dev/null ; then
          echo "-->"${CPIDs[$PID]}"=>"$PID" is running..";
          TMP_CPIDs[$PID]=${CPIDs[$PID]};
        else
          echo "-->"${CPIDs[$PID]}"=>"$PID" is completed.";
        fi
    done

    if [ ${#TMP_CPIDs[@]} == 0 ]; then
        echo "All commands completed.";
        break;
    else
        unset CPIDs;
        declare -A CPIDs;
        for PID in "${!TMP_CPIDs[@]}"; do
            CPIDs[$PID]=${TMP_CPIDs[$PID]};
        done
        unset TMP_CPIDs;

        if [ $CNT -gt $CNT_TIME_OUT ]; then
            echo ${CPIDs[@]}"PIDs not reponding. Timeout reached $CNT sec. killing all childern with GPID $GPID..";
            kill -- -$GPID;
        fi
    fi

    CNT=$((CNT+1));
    echo "waiting since $b secs..";
    sleep 1;
done

exit;

और निम्नलिखित प्रक्रियाओं का उपयोग करके अन्य टर्मिनल में 'परीक्षण' के रूप में नाम होने वाली प्रक्रियाओं को देखें।

watch -n1 'ps x -o "%p %r %c" | grep "test" '

उपरोक्त लिपि से 4 नई बाल प्रक्रियाओं का निर्माण होगा। हम सभी बच्चे की प्रक्रिया के छिद्रों को संचयित कर रहे हैं और यह जांचने के लिए कि वे अपने निष्पादन को समाप्त कर रहे हैं या अभी भी चल रहे हैं। बाल प्रक्रिया CMD_TIME समय तक निष्पादित होगी। लेकिन अगर CNT_TIME_OUT समय समाप्त हो गया, तो सभी बच्चे माता-पिता की प्रक्रिया से मारे जाएंगे। आप व्यवहार को देखने के लिए स्क्रिप्ट के साथ समय और खेल को बदल सकते हैं। इस दृष्टिकोण का एक दोष यह है कि यह सभी बाल वृक्षों को मारने के लिए समूह आईडी का उपयोग कर रहा है। लेकिन माता-पिता की प्रक्रिया स्वयं एक ही समूह से संबंधित होती है इसलिए यह भी मारे जाएंगे।

यदि आप माता-पिता को मारना नहीं चाहते हैं, तो आपको मूल प्रक्रिया के लिए अन्य समूह आईडी असाइन करने की आवश्यकता हो सकती है।

अधिक विवरण यहां मिल सकता है,

शेल स्क्रिप्ट में बाल प्रक्रिया को मारना


0

यह स्क्रिप्ट भी काम करती है:

#/bin/sh while true do echo "Enter parent process id [type quit for exit]" read ppid if [ $ppid -eq "quit" -o $ppid -eq "QUIT" ];then exit 0 fi for i in `ps -ef| awk '$3 == '$ppid' { print $2 }'` do echo killing $i kill $i done done


हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.