Bütün bir süreç ağacını öldürmek istiyorum. Herhangi bir yaygın komut dosyası dilini kullanarak bunu yapmanın en iyi yolu nedir? Basit bir çözüm arıyorum.
chronos
Veya herodes
komutlarından birini kullanın .
Bütün bir süreç ağacını öldürmek istiyorum. Herhangi bir yaygın komut dosyası dilini kullanarak bunu yapmanın en iyi yolu nedir? Basit bir çözüm arıyorum.
chronos
Veya herodes
komutlarından birini kullanın .
Yanıtlar:
Öldürmek istediğiniz ağacın tek bir süreç grubu olup olmadığını söylemezsiniz. (Bu genellikle ağaç bir sunucu başlangıcından veya kabuk komut satırından çatallanmanın sonucuysa geçerlidir.) GNU ps'yi kullanarak işlem gruplarını aşağıdaki gibi keşfedebilirsiniz:
ps x -o "%p %r %y %x %c "
Eğer öldürmek istediğiniz bir süreç grubuysa, sadece kill(1)
komutu kullanın, fakat ona bir işlem numarası vermek yerine , grup numarasının reddini verin . Örneğin, 5112 grubundaki her işlemi öldürmek için kullanın kill -TERM -- -5112
.
pgrep
işlem grubu kimliğini bulmanın daha kolay bir yolunu sunabilir. Örneğin, my-script.sh'nin işlem grubunu öldürmek için çalıştırın kill -TERM -$(pgrep -o my-script.sh)
.
ps -o pid --no-headers --ppid $PARENT_PID
ps x -o "%r %p %y %x %c" | sort -nk1,2
İşlem Grubu Kimliği'ni ( ) kullanarak aynı işlem ağacına ait tüm işlemleri öldürünPGID
kill -- -$PGID
Varsayılan sinyali kullan ( TERM
= 15)kill -9 -$PGID
Sinyali kullanma KILL
(9)Sen alabilirsiniz PGID
herhangi birinden Proses-ID ( PID
aynı) işlem ağacının
kill -- -$(ps -o pgid= $PID | grep -o '[0-9]*')
(sinyal TERM
)kill -9 -$(ps -o pgid= $PID | grep -o '[0-9]*')
(sinyal KILL
)Kalan alanlara katkılar ve OSX uyumluluğu için tanager ve Speakus'a özel teşekkürler $PID
.
kill -9 -"$PGID"
=> KILL
Tüm çocuk ve torunlara sinyal 9 ( ) gönder ...PGID=$(ps opgid= "$PID")
=> Process-Group-ID değerini yalnızca Process-Parent-ID değerinden değil, ağacın herhangi bir Process -ID'sinden al . Bir varyasyonu ps opgid= $PID
IS ile ikame edilmiş olabilir . Fakat:
ps -o pgid --no-headers $PID
pgid
pgrp
ps
PID
beş basamaktan az olduğunda ve tanager tarafından fark edildiği gibi sağa hizalandığında önde gelen boşlukları ekler . Kullanabilirsiniz:PGID=$(ps opgid= "$PID" | tr -d ' ')
ps
OSX'ten her zaman başlığı yazdırır, bu nedenle Speakus şunları önerir:PGID="$( ps -o pgid "$PID" | grep [0-9] | tr -d ' ' )"
grep -o [0-9]*
yalnızca art arda rakamlar yazdırır (boşluk veya alfabetik başlık yazdırmaz).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
aynı ağaca ait bir işlemle çağrılır,kill
bütün ağaç öldürme sonlandırmadan önce kendisini öldürmeye riske atar.> 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)"
İşlem ağacını '&' kullanarak arka planda çalıştırın
> ./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
Komut pkill -P $PID
torunu öldürmez:
> 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
Komut kill -- -$PGID
, torun da dahil olmak üzere tüm işlemleri öldürür.
> 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
Bu örnekte fark ettim PID
ve PGID
eşittir ( 28957
).
Bu yüzden başlangıçta kill -- -$PID
yeterli olduğunu düşündüm . Ama durumda süreç içinde yumurtlamaya edilir İşlem Kimliği farklıdır Grup kimliği .Makefile
kill -- -$(ps -o pgid= $PID | grep -o [0-9]*)
Farklı bir grup kimliğinden (başka bir işlem ağacı) çağrıldığında tüm süreç ağacını öldürmenin en basit hilesi olduğunu düşünüyorum .
kill
Kendi sinyalini almadan önce her zaman sinyali tüm ağaca göndermesi gerektiğini düşünüyorum . Ancak bazı özel durumlarda / uygulamalarda, kill
kendi kendine sinyal gönderebilir, kesintiye uğrayabilir ve sonra kendi sinyalini alabilir. Bununla birlikte, risk yeterince az olmalıdır ve çoğu durumda göz ardı edilebilir, çünkü bundan önce başka hatalar meydana gelmelidir. Davanızda bu risk göz ardı edilebilir mi? Dahası, diğer cevaplar bu ortak hataya sahiptir ( kill
süreç ağacının bir kısmı öldürülmektedir). Umarım bu yardım .. Şerefe;)
man
. Öte yandan, çocuk sürecinden gandchild sürecini öldürmek istiyorsanız, kill -- -$pid
işe yaramaz. Yani genel bir çözüm değil.
child.sh
.
pkill -TERM -P 27888
Bu, üst işlem kimliği 27888 olan tüm işlemleri öldürür.
Veya daha sağlam:
CPIDS=$(pgrep -P 27888); (sleep 33 && kill -KILL $CPIDS &); kill -TERM $CPIDS
33 saniye sonra öldürmeyi planlayan ve kibarca süreçlerin sona erdirilmesini isteyen.
Tüm torunları sonlandırmak için bu cevaba bakınız .
pkill -P
sadece çocuğa sinyal gönderir => torun sinyal almaz => Bu yüzden bunu açıklamak için başka bir cevap wroten var. Şerefe ;-)
pkill -TERM -P ${$}
.
$ time for i in {1..32768}; do ( echo $BASHPID >> pids ); done real 0m18.860s
Bir işlem ağacını özyinelemeli olarak öldürmek için killtree () kullanın:
#!/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 $@
--
Argümanlar için ps
o yerine orada çalışır hale OS X'de To değil işi ps
: Komudu önce tanımlanır : döngüps ax -o "pid= ppid=" | grep -E "${_regex}" | sed -E "s/${_regex}/\1/g
_regex
for
local _regex="[ ]*([0-9]+)[ ]+${_pid}"
killtree()
Güvenilir çalışmasını garanti etmek için SIGTERM yerine bir SIGKILL göndermek yeterli olur mu?
ps
desteklemediği --ppid
, birini kullanabilirsiniz pgrep -P ${_pid}
yerine
brad'nin cevabı ben de tavsiye ederim, ancak seçeneği awk
kullanırsanız tamamen ortadan kaldırabilirsiniz .--ppid
ps
for child in $(ps -o pid -ax --ppid $PPID) do ....... done
Üst sürecin pid'ini geçerseniz, işleyecek bir kabuk betiği aşağıdadır:
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
Burada açıklanan bir yöntemin biraz değiştirilmiş bir sürümünü kullanın: https://stackoverflow.com/a/5311362/563175
Yani şöyle görünüyor:
kill `pstree -p 24901 | sed 's/(/\n(/g' | grep '(' | sed 's/(\(.*\)).*/\1/' | tr "\n" " "`
burada 24901 ebeveynin PID'sidir.
Oldukça çirkin görünüyor ama mükemmel bir iş çıkarıyor.
pstree -p 24901 | grep -oP '(?<=\()[0-9]+(?=\))'
-l
gerekir pstree
, bu yüzden uzun çizgiler kesilmez; ile okumak daha kolay yapılabilir kill `pstree -l -p 24901 |grep "([[:digit:]]*)" -o |tr -d '()'`
( \n
iyi çalışacağı için uzaya dönüştürmeye gerek yok ), thx!
Zhigang'ın cevabının değiştirilmiş versiyonu:
#!/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
yalnızca başlattığınız süreçlerde yapabilirsiniz , bu yüzden bu genel bir çözüm değildir
wait
çocuksa Terminated
mesajı bastırır .
Yorum yapamıyorum (yeterli itibar), bu yüzden bu gerçekten bir cevap olmasa da yeni bir cevap eklemek zorunda kalıyorum .
28 Şubat'ta @olibre tarafından verilen aksi halde çok güzel ve kapsamlı bir cevapla ilgili küçük bir sorun var. Çıktı , sütunu haklı gösterdiği için (rakamları tam olarak hizalayın) ps opgid= $PID
beş basamaktan kısa bir PID için önde gelen boşluklar içerecektir ps
. Komut satırının tamamında negatif bir işaret, ardından boşluk (lar) ve PID grubu gelir. Basit çözüm, boşlukları kaldırmak için boruya ps
bağlamaktır tr
:
kill -- -$( ps opgid= $PID | tr -d ' ' )
Norman Ramsey'in cevabına eklemek için, bir süreç grubu oluşturmak istiyorsanız setid'e bakmaya değer olabilir.
http://pubs.opengroup.org/onlinepubs/009695399/functions/setsid.html
Çağıran süreç bir süreç grubu lideri değilse, setsid () işlevi yeni bir oturum oluşturur. Geri dönüşün ardından çağrı süreci, bu yeni oturumun oturum lideri, yeni bir süreç grubunun süreç grubu lideri olacak ve kontrol terminali bulunmayacaktır. Çağıran sürecin işlem grubu kimliği, çağıran işlemin işlem kimliğine eşit olarak ayarlanmalıdır. Çağıran süreç, yeni süreç grubundaki tek süreç ve yeni oturumdaki tek süreç olacaktır.
Yani başlangıç sürecinden bir grup oluşturabileceğiniz anlamına geliyor. Ben php bu işlem başladıktan sonra tüm süreç ağaç öldürmek için kullanılır.
Bu kötü bir fikir olabilir. Yorumlarla ilgilenirim.
Ysth adlı kullanıcının yorumundan ilham aldı
kill -- -PGID
işlem numarası vermek yerine grup numarasının reddini verin. Her zamanki gibi her komutta olduğu gibi, a ile başlayan normal bir argümanın
-
anahtar olarak yorumlanmamasını istiyorsanız,--
PGID
gelen PID
. Ne düşünüyorsun? Şerefe
Aşağıdaki kabuk işlevi diğer yanıtların çoğuna benzer, ancak Linux ve BSD'de (OS X, vb.) Dış bağımlılıklar olmadan çalışır 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
}
$child
Aynı ada sahip diğer (yerel olmayan) değişkenleri rahatsız etmemek ve işlev sona erdikten sonra yerel değişkenin değerinin temizlenmesini sağlamak için bu işlevin .
Bunu psutil kullanarak python ile yapmak çok kolay . Sadece pip ile psutil yükleyin ve daha sonra tam bir süreç manipülasyon araçları paketine sahipsiniz:
def killChildren(pid):
parent = psutil.Process(pid)
for child in parent.get_children(True):
if child.is_running():
child.terminate()
Bir işlemi adıyla öldürmek istiyorsanız:
killall -9 -g someprocessname
veya
pgrep someprocessname | xargs pkill -9 -g
Bu benim bash betiği kullanarak tüm alt işlemleri öldürmek benim versiyonu. Özyineleme kullanmaz ve pgrep komutuna bağlıdır.
kullanım
killtree.sh PID SIGNAL
Killtrees.sh içeriği
#!/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//,/ }
Yalnızca Bash'in yerel ayrıştırma olasılıklarına dayanarak AWK'sız yapılan @ zhigang'ın cevabının bir çeşidi:
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"
}
Hem Mac'lerde hem de Linux'ta iyi çalışıyor gibi görünüyor. Süreç gruplarını yönetemeyeceğiniz durumlarda - birden fazla ortamda oluşturulması gereken bir yazılım parçasını test etmek için komut dosyaları yazarken olduğu gibi - bu ağaç yürüyüş tekniği kesinlikle yararlıdır.
Bilgeliğiniz için teşekkürler millet. Betiğim çıkışta bazı alt süreçler bırakıyordu ve olumsuzlama ipucu işleri kolaylaştırdı. Bu işlevi gerekirse diğer komut dosyalarında kullanılmak üzere yazdım:
# 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
}
Şerefe.
Ebeveynleri çocuklardan önce öldürmek muhtemelen daha iyidir; aksi halde ebeveyn kendini öldürmeden önce tekrar yeni çocuklar doğurabilir. Bunlar öldürmeden kurtulur.
Benim ps versiyonum yukarıdakinden farklı; belki çok yaşlı, bu yüzden garip selamlama ...
Kabuk fonksiyonu yerine kabuk komut dosyası kullanmanın birçok avantajı vardır ...
Ancak, temelde zhigangs fikir
#!/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
Aşağıdakiler FreeBSD, Linux ve MacOS X üzerinde test edilmiştir ve sadece pgrep ve kill'e bağlıdır (ps -o sürümleri BSD altında çalışmaz). İlk argüman çocukların feshedilmesi gereken ana pid. ikinci argüman, ana pid'in de sonlandırılması gerekip gerekmediğini belirlemek için bir mantıksaldır.
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
Bu, SIGTERM'i bir kabuk komut dosyası içindeki herhangi bir alt / torun işlemine gönderir ve SIGTERM başarılı olmazsa, 10 saniye bekleyecek ve sonra kill gönderecektir.
Daha önce cevap:
Aşağıdakiler de işe yarıyor ancak BSD'de kabuğun kendisini öldürecek.
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
Zhigang, xyuri ve solidsneck'in çözümünü daha da geliştiriyorum:
#!/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
Bu sürüm, atalarını öldürmekten kaçınacaktır - bu, önceki çözümlerde çocuk süreçlerinin sele neden olur.
Alt liste belirlenmeden önce süreçler düzgün şekilde durdurulur, böylece yeni çocuk oluşturulmaz veya yok olmaz.
Öldükten sonra, durdurulan işler sistemden kaybolmaya devam etmelidir.
Eski soru, biliyorum, ama tüm cevaplar sevmediğim ps aramaya devam ediyor gibi görünüyor.
Bu awk tabanlı çözüm özyineleme gerektirmez ve yalnızca ps'yi bir kez çağırır.
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)
}'
Veya tek satırda:
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)}'
Temel olarak fikir, bir ebeveyn: çocuk girişleri dizisi (a) oluşturmamız, ardından eşleşen ebeveynlerimiz için çocukları bulan dizinin etrafında dolaşıp, onları gittikçe ebeveynler listemize (p) eklediğimizdir.
Üst düzey süreci öldürmek istemiyorsanız,
sub(/[0-9]*/, "", p)
system () satırının onu kill setinden çıkarmadan hemen önce.
Burada bir yarış koşulu olduğunu aklınızda bulundurun, ancak tüm çözümler için bu (görebildiğim kadarıyla) doğrudur. İhtiyacım olanı yapıyor çünkü ihtiyacım olan senaryo çok kısa ömürlü çocuklar yaratmıyor.
Okuyucu için bir alıştırma, 2 geçişli bir döngü yapmak olacaktır: ilk geçişten sonra, p listesindeki tüm işlemlere SIGSTOP gönderin, sonra ps'yi tekrar çalıştırmak için döngü yapın ve ikinci geçişten sonra SIGTERM, ardından SIGCONT gönderin. Güzel sonları umursamıyorsanız, ikinci geçiş sadece SIGKILL olabilir, sanırım.
Öldürmek istediğiniz şeyin pidesini biliyorsanız, genellikle oturum kimliğinden ve aynı oturumdaki her şeyden gidebilirsiniz. Ben iki kez kontrol ediyorum, ama ben ölmek istediğim döngüler rsyncs başlayan komut dosyaları için kullandım ve sadece rsync killall'd olurdu gibi (döngü nedeniyle) başka bir başlatmayın.
kill $(ps -o pid= -s $(ps -o sess --no-heading --pid 21709))
Pid'i bilmiyorsanız yine de daha fazla yuva yapabilirsiniz
kill $(ps -o pid= -s $(ps -o sess --no-heading --pid $(pgrep rsync )))
ps -o pid= --ppid $PPID | xargs kill -9
kill -9
, gerçekten.
kill -15
yardımcı olmaz.
Sh içinde jobs komutu arka plan işlemlerini listeler. Bazı durumlarda, ilk önce en yeni işlemi öldürmek daha iyi olabilir, örn. Daha eski olanı paylaşılan bir soket oluşturmuş olabilir. Bu durumlarda PID'leri ters sırayla sıralayın. Bazen işlerin durmadan önce diske veya benzeri bir şeye yazmaları için biraz beklemek isteyebilirsiniz.
Ve eğer zorunda değilsen öldürme!
for SIGNAL in TERM KILL; do
for CHILD in $(jobs -s|sort -r); do
kill -s $SIGNAL $CHILD
sleep $MOMENT
done
done
Kabuk betiğinde alt işlemi öldürme:
Çoğu zaman, bir sebepten dolayı asılan veya engellenen çocuk sürecini öldürmemiz gerekir. Örneğin. FTP bağlantısı sorunu.
İki yaklaşım vardır,
1) Her çocuk için, zaman aşımına ulaşıldığında çocuk sürecini izleyecek ve öldürecek ayrı yeni ebeveyn oluşturmak.
Test.sh dosyasını aşağıdaki gibi oluşturun,
#!/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;
ve aşağıdaki komutu kullanarak diğer terminalde 'test' olarak adlandırılan işlemleri izlemek.
watch -n1 'ps x -o "%p %r %c" | grep "test" '
Yukarıdaki komut dosyası 4 yeni alt süreç ve ebeveyn oluşturacaktır. Her alt süreç 10 saniye boyunca çalışacaktır. Ancak 5 saniyelik zaman aşımı süresi dolduğunda, ilgili ana süreçler bu çocukları öldürür. Böylece çocuk uygulamayı tamamlayamayacak (10 saniye). Başka bir davranış görmek için bu zamanlamaları (anahtar 10 ve 5) oynayın. Bu durumda, çocuk 10 saniyelik bir zaman aşımına uğramadan önce yürütmeyi 5 saniye içinde tamamlar.
2) Zaman aşımına ulaşıldığında geçerli ana öğeyi izlemeli ve alt işlemi öldürmelidir. Bu, her çocuğu izlemek için ayrı bir ebeveyn oluşturmaz. Ayrıca tüm alt süreçleri aynı ebeveyn içinde düzgün bir şekilde yönetebilirsiniz.
Test.sh dosyasını aşağıdaki gibi oluşturun,
#!/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;
ve aşağıdaki komutu kullanarak diğer terminalde 'test' olarak adlandırılan işlemleri izlemek.
watch -n1 'ps x -o "%p %r %c" | grep "test" '
Yukarıdaki komut dosyası 4 yeni alt süreç oluşturacaktır. Tüm alt süreçlerin pids'lerini saklıyoruz ve yürütülmelerini tamamlayıp tamamlamadıklarını veya hala çalışıp çalışmadıklarını kontrol etmek için üzerlerine döngü yapıyoruz. Alt işlem CMD_TIME zamanına kadar yürütülür. Ancak CNT_TIME_OUT zaman aşımına ulaşırsa, Tüm çocuklar ebeveyn süreci tarafından öldürülür. Davranışı görmek için zamanlamayı değiştirebilir ve komut dosyasıyla oynayabilirsiniz. Bu yaklaşımın bir dezavantajı, tüm çocuk ağacını öldürmek için grup kimliği kullanmaktır. Ancak ebeveyn sürecinin kendisi aynı gruba aittir, bu yüzden de öldürülür.
Ebeveynin öldürülmesini istemiyorsanız üst sürece başka bir grup kimliği atamanız gerekebilir.
Daha fazla ayrıntıyı burada bulabilirsiniz,
Bu komut dosyası da çalışır:
#/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
Biliyorum bu eski, ama bulduğum daha iyi bir çözüm:
killtree() {
for p in $(pstree -p $1 | grep -o "([[:digit:]]*)" |grep -o "[[:digit:]]*" | tac);do
echo Terminating: $p
kill $p
done
}