@ MichaelLeBarbierGrünewald Bisakah Anda menautkan ke program-program itu?
lalat styrofoam
Jawaban:
305
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.
kill -74313 -bash: kill: 74313: spesifikasi sinyal tidak valid Jika saya menambahkan kill -15 -GPID bekerja dengan baik.
Adam Peck
51
Seperti biasa dengan hampir semua perintah, jika Anda menginginkan argumen normal yang dimulai dengan - untuk tidak diartikan sebagai saklar, awali dengan -: kill - -GPID
ysth
9
pgrepdapat 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).
Josh Kelley
9
Lebih baik lihat stackoverflow.com/questions/392022/... ini merupakan solusi yang lebih elegan dan jika Anda perlu membuat daftar anak-anak maka gunakan:ps -o pid --no-headers --ppid $PARENT_PID
Szymon Jeż
4
Dan jika Anda mengubah sedikit format dan mengurutkan, Anda bisa melihat semua proses dikelompokkan dengan baik dan dimulai dengan (berpotensi) induk grup di setiap grup:ps x -o "%r %p %y %x %c" | sort -nk1,2
haridsv
199
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 PGIDdari ID-Proses ( PID) dari pohon proses yang sama
Terima kasih khusus kepada tanager dan Speakus untuk kontribusi pada $PIDruang yang tersisa dan kompatibilitas OSX.
Penjelasan
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= $PIDadalah ps -o pgid --no-headers $PIDtempat pgiddapat diganti oleh pgrp. Tapi:
psmenyisipkan spasi terdepan saat PIDkurang dari lima digit dan disejajarkan dengan benar seperti yang diperhatikan oleh penyamakan . Kamu bisa menggunakan: PGID=$(ps opgid= "$PID" | tr -d ' ')
psdari 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).
Baris perintah lebih lanjut
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)
Batasan
Seperti yang diperhatikan oleh davide dan Hubert Kario , ketika killdiminta oleh proses yang termasuk dalam pohon yang sama, killberisiko untuk membunuh dirinya sendiri sebelum mengakhiri seluruh pembunuhan pohon.
Oleh karena itu, pastikan untuk menjalankan perintah menggunakan proses yang memiliki ID Proses-Grup-berbeda .
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 COMMAND28348283492834928349 pts/328969Ss330210:00-bash28349289572895728349 pts/328969 S 330210:00 \_ /bin/sh ./run-many-processes.sh28957289582895728349 pts/328969 S 330210:00| \_ /bin/sh ./child.sh background28958289612895728349 pts/328969 S 330210:00|| \_ /bin/sh ./grandchild.sh background28961289652895728349 pts/328969 S 330210:00||| \_ sleep 999928958289632895728349 pts/328969 S 330210:00|| \_ /bin/sh ./grandchild.sh foreground28963289672895728349 pts/328969 S 330210:00|| \_ sleep 999928957289592895728349 pts/328969 S 330210:00| \_ /bin/sh ./child.sh foreground28959289602895728349 pts/328969 S 330210:00| \_ /bin/sh ./grandchild.sh background28960289642895728349 pts/328969 S 330210:00|| \_ sleep 999928959289622895728349 pts/328969 S 330210:00| \_ /bin/sh ./grandchild.sh foreground28962289662895728349 pts/328969 S 330210:00| \_ sleep 999928349289692896928349 pts/328969 R+330210:00 \_ ps fj
Perintah pkill -P $PIDtidak membunuh cucu:
> pkill -P "$PID"./run-many-processes.sh: line 4:28958Terminated./child.sh background./run-many-processes.sh: line 4:28959Terminated./child.sh foregroundProcessID=28957 ends (./run-many-processes.sh)[1]+Done./run-many-processes.sh> ps fj
PPID PID PGID SID TTY TPGID STAT UID TIME COMMAND28348283492834928349 pts/328987Ss330210:00-bash28349289872898728349 pts/328987 R+330210:00 \_ ps fj1289632895728349 pts/328987 S 330210:00/bin/sh ./grandchild.sh foreground28963289672895728349 pts/328987 S 330210:00 \_ sleep 99991289622895728349 pts/328987 S 330210:00/bin/sh ./grandchild.sh foreground28962289662895728349 pts/328987 S 330210:00 \_ sleep 99991289612895728349 pts/328987 S 330210:00/bin/sh ./grandchild.sh background28961289652895728349 pts/328987 S 330210:00 \_ sleep 99991289602895728349 pts/328987 S 330210:00/bin/sh ./grandchild.sh background28960289642895728349 pts/328987 S 330210:00 \_ sleep 9999
Perintah kill -- -$PGIDmembunuh 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 COMMAND28348283492834928349 pts/329039Ss330210:00-bash28349290392903928349 pts/329039 R+330210:00 \_ ps fj
Kesimpulan
Saya perhatikan dalam contoh ini PIDdan PGIDsama ( 28957).
Inilah mengapa saya awalnya berpikir kill -- -$PIDsudah cukup. Tapi dalam kasus proses ini menelurkan dalam Makefilesatu 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).
Hai @davide. Pertanyaan bagus. Saya pikir killharus selalu mengirim sinyal ke seluruh pohon sebelum menerima sinyal sendiri. Tetapi dalam beberapa keadaan / implementasi tertentu, killdapat 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 ( killbagian dari pohon proses dibunuh). Semoga ini bisa membantu .. Ceria;)
olibre
3
Ini hanya berfungsi jika sub perintah sendiri tidak menjadi pemimpin kelompok. Bahkan alat sederhana seperti manitu suka melakukannya. Di sisi lain, jika Anda ingin mematikan proses gandchild dari proses anak, kill -- -$pidtidak akan berhasil. Jadi itu bukan solusi umum.
Hubert Kario
1
Contohnya adalah "anak" yang mencoba membunuh anak-anaknya (jadi cucu dari perintah yang diinisiasi pengguna). TKI, cobalah untuk mematikan hierarki proses latar belakang di child.sh.
Hubert Kario
1
> kill -QUIT - "$ PGID" # sinyal yang sama dengan [CRTL + C] dari keyboard ---- QUIT harus diganti menjadi INT menjadi true
Maxim Kholyavkin
1
untuk opsi OSX --tidak ada header tidak didukung sehingga kode harus diperbarui ke: PGID = "$ (ps -o pgid" $ PID "| grep [0-9] | tr -d '')"
Maxim Kholyavkin
166
pkill -TERM -P 27888
Ini akan membunuh semua proses yang memiliki ID proses induk 27888.
Dalam tes cepat saya, pgrep hanya melaporkan anak-anak langsung, jadi ini mungkin tidak membunuh seluruh hierarki.
haridsv
10
Saya setuju dengan @haridsv: pkill -Pmengirim sinyal hanya kepada anak => cucu tidak menerima sinyal => Oleh karena itu saya telah menulis jawaban lain untuk menjelaskannya. Cheers ;-)
olibre
1
Dari skrip bash, untuk membunuh anak-anak Anda sendiri, gunakan pkill -TERM -P ${$}.
François Beausoleil
3
@Onjob, bukankah berbahaya untuk tidur lalu membunuh? ID proses mungkin telah digunakan kembali oleh OS untuk saat ini: Anda mungkin membunuh proses yang bukan anak-anak Anda lagi. Saya menduga panggilan ke pkill harus dilakukan lagi untuk memastikan hal ini.
François Beausoleil
2
@Onlyjob FYI, saya dapat menelurkan 32768 proses, berulir tunggal, dengan akses I / O ringan dalam waktu kurang dari 19 detik pada mesin saya:$ time for i in {1..32768}; do ( echo $BASHPID >> pids ); done real 0m18.860s
cychoi
102
Untuk membunuh pohon proses secara rekursif, gunakan killtree ():
#!/bin/bash
killtree(){local _pid=$1local _sig=${2:--TERM}
kill -stop ${_pid}# needed to stop quickly forking parent from producing children between child killing and parent killingfor _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 1fi
killtree $@
The --argumen untuk pstidak bekerja pada OS X. Untuk membuatnya bekerja ada mengganti psperintah dengan: ps ax -o "pid= ppid=" | grep -E "${_regex}" | sed -E "s/${_regex}/\1/gdi mana _regexdidefinisikan sebelum forlingkaran:local _regex="[ ]*([0-9]+)[ ]+${_pid}"
artur
5
Proses berhenti tidak terbunuh dengan SIGTERM. Lihat jawaban
x-yuri
1
-1 menggunakan #! / Bin / bash alih-alih #! / Usr / bin / env bash (atau lebih baik POSIX hanya membangun dan / bin / sh)
Orang Baik
Apakah cukup mengirim SIGKILL sebagai pengganti SIGTERM untuk menjamin bahwa itu killtree()berfungsi dengan andal?
Davide
3
jika pstidak mendukung --ppid, seseorang dapat menggunakan pgrep -P ${_pid}sebagai gantinya
Hubert Kario
16
perintah rkill daripaket pslist mengirimkan sinyal yang diberikan (atauSIGTERMsecara default) ke proses yang ditentukan dan semua turunannya:
Beberapa versi ps akan memberikan peringatan jika Anda menggunakan "-ax" alih-alih "ax". Jadi: untuk anak dalam $ (ps -o pid, ppid ax | \ awk "{if (\ $ 2 == $ pid) {print \ $ 1}}")
Anda harus menambahkan -luntuk 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 \nke ruang karena akan berfungsi dengan baik), thx!
Aquarius Power
9
Versi modifikasi dari jawaban zhigang:
#!/usr/bin/env bashset-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 "fidone}while true;do sleep 1;done&
cpid=$!for i in $(seq 12);do
cpids $$ a
sleep 1done
killtree $cpid
echo ---
cpids $$ a
Anda wait $pidhanya dapat pada proses yang sudah Anda mulai, tidak semua precesses, jadi ini bukan solusi umum
Hubert Kario
@ Hubert Kario Dalam hal ini, tunggu hanya akan keluar dengan status non-nol dan terus menjalankan skrip. Apakah aku salah? Tetapi waitakan menekan Terminatedpesan jika itu anak-anak.
x-yuri
9
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= $PIDakan berisi spasi utama untuk PID yang lebih pendek dari lima digit karena psmembenarkan 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 pske truntuk menghilangkan ruang:
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.
Sebenarnya ini adalah ide bagus dan bekerja dengan sangat baik. Saya menggunakannya dalam kasus di mana saya dapat menempatkan proses dalam kelompok proses yang sama (atau mereka semua sudah dalam kelompok yang sama).
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--
Ups, saya baru sadar bahwa saya telah memberikan jawaban yang sama seperti Anda => +1. Tapi apalagi saya menjelaskan bagaimana untuk hanya mendapatkan PGIDdari PID. Bagaimana menurut anda? Cheers
olibre
5
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
}
Saya pikir Anda memiliki kata "anak" tambahan di akhir baris ke-2.
mato
@ mato - Itu tidak ekstra. Ini membatasi ruang lingkup $childuntuk fungsi itu agar tidak mengganggu variabel lain (non-lokal) dengan nama yang sama dan untuk memastikan nilai variabel lokal dibersihkan setelah fungsi berakhir.
Adam Katz
Oh, saya mengerti sekarang, saya pikir itu adalah bagian dari tugas. Saya kira saya harus membaca kembali (lebih lambat) sebelum menulis komentar. :) Terima kasih.
mato
Btw, bukankah lebih baik membuat daftar anak-anak dan kemudian mulai membunuh dari atas (orang tua)? .. Dengan demikian kita dapat menghindari situasi ketika orang tua membuat ulang anak atau terus menjalankan kode berikutnya yang berpotensi mengubah perilaku yang diinginkan.
mato
5
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()
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}
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 ...
perhatikan bahwa skrip @zhighang SIGSTOPs proses induk dan memberikan sinyal untuk menghentikan proses, jadi ini seharusnya tidak (AFAIK) menyebabkan kondisi balapan antara proses membuat anak-anak dan pengiriman sinyal. Versi Anda meskipun memiliki ras antara mendapatkan daftar anak-anak dan pengiriman sinyal ke orang tua.
Hubert Kario
1
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.
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);doif[ $$ -ne $child ];then(kill -s SIGTERM $child ||(sleep 10&& kill -9 $child &))>/dev/null 2>&1;fidone}# Example lanch from within scriptKillSubTree $$ >/dev/null 2>&1
Saya mengembangkan solusi zhigang, xyuri dan solidsneck lebih lanjut:
#!/bin/bashif 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.";return1;fi;# this avoids that children are spawned or disappear.
kill -SIGSTOP $2 ;
_children=$(ps -o pid --no-headers --ppid $2);
_success=0for _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.
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;dofor CHILD in $(jobs -s|sort -r);do
kill -s $SIGNAL $CHILD
sleep $MOMENT
donedone
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.";fidoneif[ ${#TMP_CPIDs[@]}==0];then
echo "All commands completed.";break;else
unset CPIDs;
declare -A CPIDs;for PID in"${!TMP_CPIDs[@]}";doCPIDs[$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;fifi
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.
#/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
chronos
atauherodes
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:
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, gunakankill -TERM -- -5112
.sumber
pgrep
dapat menawarkan cara yang lebih mudah untuk menemukan ID grup proses. Misalnya, untuk membunuh grup proses my-script.sh, jalankankill -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 sinyalKILL
(9)Anda dapat mengambil
PGID
dari ID-Proses (PID
) dari pohon proses yang samakill -- -$(ps -o pgid= $PID | grep -o '[0-9]*')
(sinyalTERM
)kill -9 -$(ps -o pgid= $PID | grep -o '[0-9]*')
(sinyalKILL
)Terima kasih khusus kepada tanager dan Speakus untuk kontribusi pada
$PID
ruang yang tersisa dan kompatibilitas OSX.Penjelasan
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 . Variasips opgid= $PID
adalahps -o pgid --no-headers $PID
tempatpgid
dapat diganti olehpgrp
.Tapi:
ps
menyisipkan spasi terdepan saatPID
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).Baris perintah lebih lanjut
Batasan
kill
diminta oleh proses yang termasuk dalam pohon yang sama,kill
berisiko untuk membunuh dirinya sendiri sebelum mengakhiri seluruh pembunuhan pohon.Cerita panjang
Jalankan pohon proses di latar belakang menggunakan '&'
Perintah
pkill -P $PID
tidak membunuh cucu:Perintah
kill -- -$PGID
membunuh semua proses termasuk cucu.Kesimpulan
Saya perhatikan dalam contoh ini
PID
danPGID
sama (28957
).Inilah mengapa saya awalnya berpikir
kill -- -$PID
sudah cukup. Tapi dalam kasus proses ini menelurkan dalamMakefile
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).sumber
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
.Ini akan membunuh semua proses yang memiliki ID proses induk 27888.
Atau lebih kuat:
jadwal yang menewaskan 33 detik kemudian dan dengan sopan meminta proses untuk mengakhiri.
Lihat jawaban ini untuk mengakhiri semua keturunan.
sumber
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 ():
sumber
--
argumen untukps
tidak bekerja pada OS X. Untuk membuatnya bekerja ada menggantips
perintah dengan:ps ax -o "pid= ppid=" | grep -E "${_regex}" | sed -E "s/${_regex}/\1/g
di mana_regex
didefinisikan sebelumfor
lingkaran:local _regex="[ ]*([0-9]+)[ ]+${_pid}"
killtree()
berfungsi dengan andal?ps
tidak mendukung--ppid
, seseorang dapat menggunakanpgrep -P ${_pid}
sebagai gantinyaperintah rkill daripaket pslist mengirimkan sinyal yang diberikan (atau
SIGTERM
secara default) ke proses yang ditentukan dan semua turunannya:sumber
jawaban brad adalah apa yang saya rekomendasikan juga, kecuali bahwa Anda dapat menghapus
awk
semuanya jika Anda menggunakan--ppid
opsi tersebutps
.sumber
jika Anda tahu lulus pid dari proses induk, inilah skrip shell yang seharusnya berfungsi:
sumber
Saya menggunakan versi yang sedikit dimodifikasi dari metode yang dijelaskan di sini: https://stackoverflow.com/a/5311362/563175
Jadi terlihat seperti itu:
di mana 24901 adalah PID induk.
Itu terlihat sangat jelek tetapi apakah itu bekerja dengan sempurna.
sumber
pstree -p 24901 | grep -oP '(?<=\()[0-9]+(?=\))'
-l
untukpstree
, sehingga antrean panjang tidak mendapatkan dipotong; dapat dibuat lebih mudah untuk dibaca juga dengankill `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:
sumber
wait $pid
hanya dapat pada proses yang sudah Anda mulai, tidak semua precesses, jadi ini bukan solusi umumwait
akan menekanTerminated
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 karenaps
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 menyalurkanps
ketr
untuk menghilangkan ruang:sumber
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
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.
sumber
Terinspirasi oleh komentar ysth
sumber
PGID
dariPID
. Bagaimana menurut anda? CheersFungsi shell berikut mirip dengan banyak jawaban lain, tetapi berfungsi baik di Linux dan BSD (OS X, dll) tanpa dependensi eksternal seperti
pgrep
:sumber
$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:
sumber
Berdasarkan jawaban zhigang, ini menghindari bunuh diri:
sumber
Jika Anda ingin mematikan proses dengan nama:
atau
sumber
Ini adalah versi saya untuk membunuh semua proses anak menggunakan skrip bash. Itu tidak menggunakan rekursi dan tergantung pada perintah pgrep.
Menggunakan
Isi dari killtrees.sh
sumber
Berikut adalah variasi jawaban @ zhigang yang tidak memiliki AWK, hanya bergantung pada kemungkinan parsing asli Bash:
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.
sumber
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:
Bersulang.
sumber
jika Anda memiliki pstree dan perl pada sistem Anda, Anda dapat mencoba ini:
sumber
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
sumber
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.
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.
sumber
Saya mengembangkan solusi zhigang, xyuri dan solidsneck lebih lanjut:
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.
sumber
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.
Atau dalam satu baris:
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
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.
sumber
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.
Jika Anda tidak tahu pid Anda masih bisa bersarang lagi
sumber
sumber
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!
sumber
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,
dan perhatikan proses yang memiliki nama sebagai 'uji' di terminal lain menggunakan perintah berikut.
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,
dan perhatikan proses yang memiliki nama sebagai 'uji' di terminal lain menggunakan perintah berikut.
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,
Membunuh proses anak dalam skrip shell
sumber
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
sumber
Saya tahu itu sudah lama, tetapi itu adalah solusi yang lebih baik yang saya temukan:
sumber