Saya ingin membunuh seluruh pohon proses. Apa cara terbaik untuk melakukan ini menggunakan bahasa scripting umum? Saya mencari solusi sederhana.
chronos
atau herodes
perintah.
Saya ingin membunuh seluruh pohon proses. Apa cara terbaik untuk melakukan ini menggunakan bahasa scripting umum? Saya mencari solusi sederhana.
chronos
atau herodes
perintah.
Jawaban:
Anda tidak mengatakan jika pohon yang ingin Anda bunuh adalah kelompok proses tunggal. (Ini sering terjadi jika pohon adalah hasil forking dari awal server atau baris perintah shell.) Anda dapat menemukan grup proses menggunakan GNU ps sebagai berikut:
ps x -o "%p %r %y %x %c "
Jika itu adalah grup proses yang ingin Anda bunuh, cukup gunakan kill(1)
perintah tetapi alih-alih berikan nomor proses, berikan negasi nomor grup. Misalnya untuk membunuh setiap proses dalam grup 5112, gunakan kill -TERM -- -5112
.
pgrep
dapat menawarkan cara yang lebih mudah untuk menemukan ID grup proses. Misalnya, untuk membunuh grup proses my-script.sh, jalankan 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
Bunuh semua proses milik pohon proses yang sama menggunakan ID Grup Proses ( PGID
)
kill -- -$PGID
Gunakan sinyal default ( TERM
= 15)kill -9 -$PGID
Gunakan sinyal KILL
(9)Anda dapat mengambil PGID
dari ID-Proses ( PID
) dari pohon proses yang sama
kill -- -$(ps -o pgid= $PID | grep -o '[0-9]*')
(sinyal TERM
)kill -9 -$(ps -o pgid= $PID | grep -o '[0-9]*')
(sinyal KILL
)Terima kasih khusus kepada tanager dan Speakus untuk kontribusi pada $PID
ruang yang tersisa dan kompatibilitas OSX.
kill -9 -"$PGID"
=> Kirim sinyal 9 ( KILL
) ke semua anak dan cucu ...PGID=$(ps opgid= "$PID")
=> Mengambil Proses-Group-ID dari setiap proses-ID pohon, tidak hanya Proses-Parent-ID . Variasi ps opgid= $PID
adalah ps -o pgid --no-headers $PID
tempat pgid
dapat diganti oleh pgrp
. ps
menyisipkan spasi terdepan saat PID
kurang dari lima digit dan disejajarkan dengan benar seperti yang diperhatikan oleh penyamakan . Kamu bisa menggunakan:PGID=$(ps opgid= "$PID" | tr -d ' ')
ps
dari OSX selalu mencetak header, oleh karena itu Speakus mengusulkan:PGID="$( ps -o pgid "$PID" | grep [0-9] | tr -d ' ' )"
grep -o [0-9]*
hanya mencetak digit berturut-turut (tidak mencetak spasi atau header alfabet).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
diminta oleh proses yang termasuk dalam pohon yang sama, kill
berisiko untuk membunuh dirinya sendiri sebelum mengakhiri seluruh pembunuhan pohon.> 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)"
Jalankan pohon proses di latar belakang menggunakan '&'
> ./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
Perintah pkill -P $PID
tidak membunuh cucu:
> 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
Perintah kill -- -$PGID
membunuh semua proses termasuk cucu.
> 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
Saya perhatikan dalam contoh ini PID
dan PGID
sama ( 28957
).
Inilah mengapa saya awalnya berpikir kill -- -$PID
sudah cukup. Tapi dalam kasus proses ini menelurkan dalam Makefile
satu ID Proses ini berbeda dengan ID Grup .
Saya pikir kill -- -$(ps -o pgid= $PID | grep -o [0-9]*)
adalah trik sederhana terbaik untuk membunuh seluruh pohon proses ketika dipanggil dari ID Grup yang berbeda (pohon proses lain).
kill
harus selalu mengirim sinyal ke seluruh pohon sebelum menerima sinyal sendiri. Tetapi dalam beberapa keadaan / implementasi tertentu, kill
dapat mengirim sendiri sinyal, terganggu, dan kemudian menerima sinyal sendiri. Namun risikonya harus cukup minimal, dan dapat diabaikan dalam sebagian besar kasus karena bug lain harus terjadi sebelum ini. Bisakah risiko ini diabaikan dalam kasus Anda? Selain itu jawaban lain memiliki bug umum ini ( kill
bagian dari pohon proses dibunuh). Semoga ini bisa membantu .. Ceria;)
man
itu suka melakukannya. Di sisi lain, jika Anda ingin mematikan proses gandchild dari proses anak, kill -- -$pid
tidak akan berhasil. Jadi itu bukan solusi umum.
child.sh
.
pkill -TERM -P 27888
Ini akan membunuh semua proses yang memiliki ID proses induk 27888.
Atau lebih kuat:
CPIDS=$(pgrep -P 27888); (sleep 33 && kill -KILL $CPIDS &); kill -TERM $CPIDS
jadwal yang menewaskan 33 detik kemudian dan dengan sopan meminta proses untuk mengakhiri.
Lihat jawaban ini untuk mengakhiri semua keturunan.
pkill -P
mengirim sinyal hanya kepada anak => cucu tidak menerima sinyal => Oleh karena itu saya telah menulis jawaban lain untuk menjelaskannya. Cheers ;-)
pkill -TERM -P ${$}
.
$ time for i in {1..32768}; do ( echo $BASHPID >> pids ); done real 0m18.860s
Untuk membunuh pohon proses secara rekursif, gunakan killtree ():
#!/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 $@
--
argumen untuk ps
tidak bekerja pada OS X. Untuk membuatnya bekerja ada mengganti ps
perintah dengan: ps ax -o "pid= ppid=" | grep -E "${_regex}" | sed -E "s/${_regex}/\1/g
di mana _regex
didefinisikan sebelum for
lingkaran:local _regex="[ ]*([0-9]+)[ ]+${_pid}"
killtree()
berfungsi dengan andal?
ps
tidak mendukung --ppid
, seseorang dapat menggunakan pgrep -P ${_pid}
sebagai gantinya
jawaban brad adalah apa yang saya rekomendasikan juga, kecuali bahwa Anda dapat menghapus awk
semuanya jika Anda menggunakan --ppid
opsi tersebut ps
.
for child in $(ps -o pid -ax --ppid $PPID) do ....... done
jika Anda tahu lulus pid dari proses induk, inilah skrip shell yang seharusnya berfungsi:
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
Saya menggunakan versi yang sedikit dimodifikasi dari metode yang dijelaskan di sini: https://stackoverflow.com/a/5311362/563175
Jadi terlihat seperti itu:
kill `pstree -p 24901 | sed 's/(/\n(/g' | grep '(' | sed 's/(\(.*\)).*/\1/' | tr "\n" " "`
di mana 24901 adalah PID induk.
Itu terlihat sangat jelek tetapi apakah itu bekerja dengan sempurna.
pstree -p 24901 | grep -oP '(?<=\()[0-9]+(?=\))'
-l
untuk pstree
, sehingga antrean panjang tidak mendapatkan dipotong; dapat dibuat lebih mudah untuk dibaca juga dengan kill `pstree -l -p 24901 |grep "([[:digit:]]*)" -o |tr -d '()'`
(tidak perlu mengkonversi \n
ke ruang karena akan berfungsi dengan baik), thx!
Versi modifikasi dari jawaban 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
hanya dapat pada proses yang sudah Anda mulai, tidak semua precesses, jadi ini bukan solusi umum
wait
akan menekan Terminated
pesan jika itu anak-anak.
Saya tidak dapat berkomentar (tidak memiliki reputasi yang cukup), jadi saya terpaksa menambahkan jawaban baru , meskipun ini sebenarnya bukan jawaban.
Ada sedikit masalah dengan jawaban sebaliknya yang sangat bagus dan menyeluruh yang diberikan oleh @olibre pada tanggal 28 Februari. Keluaran dari ps opgid= $PID
akan berisi spasi utama untuk PID yang lebih pendek dari lima digit karena ps
membenarkan kolom (rigly align the numbers). Di dalam seluruh baris perintah, ini menghasilkan tanda negatif, diikuti oleh spasi, diikuti oleh grup PID. Solusi sederhana adalah menyalurkan ps
ke tr
untuk menghilangkan ruang:
kill -- -$( ps opgid= $PID | tr -d ' ' )
Untuk menambahkan jawaban Norman Ramsey, mungkin ada baiknya melihat setsid jika Anda ingin membuat grup proses.
http://pubs.opengroup.org/onlinepubs/009695399/functions/setsid.html
Fungsi setsid () akan membuat sesi baru, jika proses panggilan bukan pemimpin grup proses. Setelah kembali proses pemanggilan akan menjadi ketua sesi sesi baru ini, akan menjadi ketua kelompok proses dari kelompok proses baru, dan tidak akan memiliki terminal pengendali. ID grup proses dari proses pemanggilan harus sama dengan ID proses dari proses pemanggilan. Proses panggilan akan menjadi satu-satunya proses dalam kelompok proses baru dan satu-satunya proses dalam sesi baru.
Yang saya maksud adalah bahwa Anda dapat membuat grup dari proses awal. Saya menggunakan ini dalam php untuk dapat membunuh seluruh pohon proses setelah memulainya.
Ini mungkin ide yang buruk. Saya tertarik dengan komentar.
Terinspirasi oleh komentar ysth
kill -- -PGID
alih-alih memberikan nomor proses, berikan negasi nomor grup. Seperti biasa dengan hampir semua perintah, jika Anda menginginkan argumen normal yang dimulai dengan a
-
untuk tidak diartikan sebagai switch, awali dengan--
PGID
dari PID
. Bagaimana menurut anda? Cheers
Fungsi shell berikut mirip dengan banyak jawaban lain, tetapi berfungsi baik di Linux dan BSD (OS X, dll) tanpa dependensi eksternal seperti 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
untuk fungsi itu agar tidak mengganggu variabel lain (non-lokal) dengan nama yang sama dan untuk memastikan nilai variabel lokal dibersihkan setelah fungsi berakhir.
Sangat mudah melakukan ini dengan python menggunakan psutil . Cukup instal psutil dengan pip dan kemudian Anda memiliki serangkaian alat manipulasi proses:
def killChildren(pid):
parent = psutil.Process(pid)
for child in parent.get_children(True):
if child.is_running():
child.terminate()
Jika Anda ingin mematikan proses dengan nama:
killall -9 -g someprocessname
atau
pgrep someprocessname | xargs pkill -9 -g
Ini adalah versi saya untuk membunuh semua proses anak menggunakan skrip bash. Itu tidak menggunakan rekursi dan tergantung pada perintah pgrep.
Menggunakan
killtree.sh PID SIGNAL
Isi dari 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//,/ }
Berikut adalah variasi jawaban @ zhigang yang tidak memiliki AWK, hanya bergantung pada kemungkinan parsing asli Bash:
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"
}
Tampaknya berfungsi dengan baik pada Mac dan Linux. Dalam situasi di mana Anda tidak dapat mengandalkan kemampuan untuk mengelola grup proses - seperti ketika menulis skrip untuk menguji perangkat lunak yang harus dibangun di beberapa lingkungan - teknik berjalan dengan pohon ini jelas sangat membantu.
Terima kasih atas kebijaksanaan Anda, kawan. Script saya membiarkan beberapa proses anak keluar dan tip negasi membuat segalanya lebih mudah. Saya menulis fungsi ini untuk digunakan dalam skrip lain jika perlu:
# 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
}
Bersulang.
Mungkin lebih baik membunuh orang tua sebelum anak-anak; jika tidak, orang tua mungkin akan melahirkan anak baru lagi sebelum dia bunuh diri. Ini akan selamat dari pembunuhan.
Versi ps saya berbeda dari yang di atas; mungkin terlalu tua, oleh karena itu aneh ...
Menggunakan skrip shell sebagai ganti fungsi shell memiliki banyak keuntungan ...
Namun, itu pada dasarnya adalah gagasan zhigang
#!/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
Berikut ini telah diuji pada FreeBSD, Linux dan MacOS X dan hanya bergantung pada pgrep dan kill (versi ps -o tidak berfungsi di bawah BSD). Argumen pertama adalah pid orangtua yang anak-anak harus diakhiri. Argumen kedua adalah boolean untuk menentukan apakah pid orangtua harus diakhiri juga.
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
Ini akan mengirim SIGTERM ke proses anak / cucu apa pun dalam skrip shell dan jika SIGTERM tidak berhasil, ia akan menunggu 10 detik dan kemudian mengirim kill.
Jawaban sebelumnya:
Berikut ini juga berfungsi tetapi akan membunuh shell itu sendiri di BSD.
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
Saya mengembangkan solusi zhigang, xyuri dan solidsneck lebih lanjut:
#!/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
Versi ini akan menghindari pembunuhan keturunannya - yang menyebabkan membanjirnya proses anak dalam solusi sebelumnya.
Proses dihentikan dengan benar sebelum daftar anak ditentukan, sehingga tidak ada anak baru yang dibuat atau menghilang.
Setelah terbunuh, pekerjaan yang dihentikan harus dilanjutkan untuk menghilang dari sistem.
Pertanyaan lama, saya tahu, tetapi semua tanggapan tampaknya terus memanggil ps, yang saya tidak suka.
Solusi berbasis awk ini tidak memerlukan rekursi dan hanya memanggil ps satu kali.
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)
}'
Atau dalam satu baris:
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)}'
Pada dasarnya idenya adalah bahwa kita membangun sebuah array (a) dari orangtua: entri anak, kemudian loop di sekitar array menemukan anak-anak untuk orang tua kita yang cocok, menambahkan mereka ke daftar orang tua kita (p) saat kita pergi.
Jika Anda tidak ingin membunuh proses level atas, maka lakukan
sub(/[0-9]*/, "", p)
tepat sebelum sistem () baris akan menghapusnya dari set kill.
Ingatlah bahwa ada kondisi balapan di sini, tapi itu benar (sejauh yang saya bisa lihat) dari semua solusi. Itu melakukan apa yang saya butuhkan karena naskah yang saya butuhkan tidak membuat banyak anak berumur pendek.
Latihan untuk pembaca adalah membuatnya menjadi loop 2-pass: setelah pass pertama, kirim SIGSTOP ke semua proses dalam daftar p, kemudian loop untuk menjalankan ps lagi dan setelah pass kedua kirim SIGTERM, lalu SIGCONT. Jika Anda tidak peduli dengan akhir yang bagus maka pass kedua hanya bisa menjadi SIGKILL, saya kira.
Jika Anda tahu pid tentang hal yang ingin Anda bunuh, Anda biasanya dapat beralih dari id sesi, dan semuanya dalam sesi yang sama. Saya akan mengecek, tapi saya menggunakan ini untuk skrip yang memulai rsyncs di loop yang saya ingin mati, dan tidak memulai yang lain (karena loop) seperti yang akan terjadi jika saya baru saja membunuh semua rsync.
kill $(ps -o pid= -s $(ps -o sess --no-heading --pid 21709))
Jika Anda tidak tahu pid Anda masih bisa bersarang lagi
kill $(ps -o pid= -s $(ps -o sess --no-heading --pid $(pgrep rsync )))
ps -o pid= --ppid $PPID | xargs kill -9
kill -9
, sungguh.
kill -15
tidak akan membantu.
Dalam sh perintah perintah akan daftar proses latar belakang. Dalam beberapa kasus mungkin lebih baik untuk membunuh proses terbaru terlebih dahulu, misalnya yang lebih lama membuat soket bersama. Dalam kasus tersebut, sortir PID dalam urutan terbalik. Terkadang Anda ingin menunggu saat pekerjaan menulis sesuatu pada disk atau hal-hal seperti itu sebelum berhenti.
Dan jangan bunuh jika Anda tidak perlu!
for SIGNAL in TERM KILL; do
for CHILD in $(jobs -s|sort -r); do
kill -s $SIGNAL $CHILD
sleep $MOMENT
done
done
Membunuh proses anak dalam skrip shell:
Banyak kali kita perlu membunuh proses anak yang digantung atau diblokir karena alasan tertentu. misalnya. Masalah koneksi FTP.
Ada dua pendekatan,
1) Untuk membuat induk baru yang terpisah untuk setiap anak yang akan memantau dan membunuh proses anak setelah batas waktu tercapai.
Buat test.sh sebagai berikut,
#!/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;
dan perhatikan proses yang memiliki nama sebagai 'uji' di terminal lain menggunakan perintah berikut.
watch -n1 'ps x -o "%p %r %c" | grep "test" '
Script di atas akan membuat 4 proses anak baru dan orang tua mereka. Setiap proses anak akan berjalan selama 10 detik. Tetapi begitu batas waktu 5dtk tercapai, proses induk masing-masing akan membunuh anak-anak itu. Jadi anak tidak akan dapat menyelesaikan eksekusi (10dtk). Bermain di sekitar waktu tersebut (beralih 10 dan 5) untuk melihat perilaku lain. Dalam hal ini anak akan menyelesaikan eksekusi dalam 5 detik sebelum mencapai batas waktu 10 detik.
2) Biarkan orang tua saat ini memantau dan membunuh proses anak setelah batas waktu tercapai. Ini tidak akan membuat orangtua terpisah untuk memantau setiap anak. Anda juga dapat mengelola semua proses anak dengan benar dalam induk yang sama.
Buat test.sh sebagai berikut,
#!/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;
dan perhatikan proses yang memiliki nama sebagai 'uji' di terminal lain menggunakan perintah berikut.
watch -n1 'ps x -o "%p %r %c" | grep "test" '
Script di atas akan membuat 4 proses anak baru. Kami menyimpan pids dari semua proses anak dan mengulanginya untuk memeriksa apakah prosesnya selesai atau masih berjalan. Proses anak akan dieksekusi hingga waktu CMD_TIME. Tetapi jika CNT_TIME_OUT batas waktu habis, Semua anak akan terbunuh oleh proses orang tua. Anda dapat mengganti waktu dan bermain-main dengan skrip untuk melihat perilaku. Salah satu kelemahan dari pendekatan ini adalah, ia menggunakan id grup untuk membunuh semua pohon anak. Tetapi proses induk itu sendiri milik kelompok yang sama sehingga juga akan terbunuh.
Anda mungkin perlu menetapkan id grup lain untuk proses induk jika Anda tidak ingin orangtua dibunuh.
Rincian lebih lanjut dapat ditemukan di sini,
Script ini juga berfungsi:
#/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
Saya tahu itu sudah lama, tetapi itu adalah solusi yang lebih baik yang saya temukan:
killtree() {
for p in $(pstree -p $1 | grep -o "([[:digit:]]*)" |grep -o "[[:digit:]]*" | tac);do
echo Terminating: $p
kill $p
done
}