Yanıtlar:
Biraz karışıklığı temizlemek trap
için kullanılabilir. Belirli bir sinyal geldiğinde yürütülen şeylerin bir listesini sağlayabilir:
trap "echo hello" SIGINT
ancak kabuk çıkarsa bir şeyi yürütmek için de kullanılabilir:
trap "killall background" EXIT
Bu bir yerleşiktir, bu yüzden help trap
size bilgi verecektir (bash ile çalışır). Yalnızca arka plandaki işleri öldürmek istiyorsanız,
trap 'kill $(jobs -p)' EXIT
'
Kabuğun $()
hemen yerine geçmesini önlemek için tekli kullanmaya dikkat edin.
kill $(jobs -p)
alt kabukta komut ikamesi yürüttüğü için tire içinde çalışmaz (bkz. man
killall background
bir yer tutucu olması gerekiyordu? background
adam sayfasında değil ...
Bu benim için çalışıyor (yorumcular sayesinde geliştirildi):
trap "trap - SIGTERM && kill -- -$$" SIGINT SIGTERM EXIT
4.3.30(1)-release
OSX'te çalıştırdım ve Ubuntu'da da onaylandı . Yine de bir obvoius wokaround var :)
-$$
. '- <PID> `olarak değerlendirilir örn -1234
. Kill manpage // builtin manpage'de, önde gelen bir çizgi gönderilecek sinyali belirtir. Bununla birlikte - muhtemelen bunu engeller, ancak daha sonra önde gelen çizgi başka türlü belgelenmez. Herhangi bir yardım?
man 2 kill
Bir PID negatif olduğunda, sinyalin işlem grubundaki tüm işlemlere sağlanan kimliğe ( en.wikipedia.org/wiki/Process_group ) gönderildiğini açıklayan Check . Bunun belirtilmemesi man 1 kill
veya man bash
belgelerinde bir hata olarak düşünülmesi kafa karıştırıcıdır .
Güncelleme: https://stackoverflow.com/a/53714583/302079 çıkış durumu ve bir temizleme işlevi ekleyerek bunu iyileştirir.
trap "exit" INT TERM
trap "kill 0" EXIT
Neden dönüşüm INT
ve TERM
çıkış? Çünkü her ikisi de kill 0
sonsuz döngüye girmeden tetiklemelidir .
Neden tetik kill 0
üzerinde EXIT
? Çünkü normal komut dosyası çıkışları da tetiklenmelidir kill 0
.
Neden kill 0
? Çünkü iç içe geçmiş alt kabukların da öldürülmesi gerekiyor. Bu işlem ağacının tamamını kapatacaktır .
kill 0
anlama geldiği / ne anlama geldiği hakkında daha fazla bilgi verebilir misiniz ?
tuzağı 'kill $ (jobs -p)' EXIT
Johannes'in cevabında sadece küçük değişiklikler yapardım ve kill'i çalışan süreçlerle sınırlamak ve listeye birkaç sinyal daha eklemek için işler -pr kullanırım:
trap 'kill $(jobs -pr)' SIGINT SIGTERM EXIT
trap 'kill 0' SIGINT SIGTERM EXIT
Açıklanan çözüm @ tokland cevabı gerçekten güzel, ama son Bash bir segmantation arıza ile çöküyor onu kullanırken. Çünkü Bash, v. 4.3'ten başlayarak, bu durumda sonsuz olan tuzak özyinelemesine izin verir:
SIGINT
veya SIGTERM
veya EXIT
;kill 0
gönderen, yakalanır SIGTERM
;Bu, tuzağın manuel olarak kaydedilmesiyle çözülebilir:
trap 'trap - SIGTERM && kill 0' SIGINT SIGTERM EXIT
Alınan sinyalin yazdırılmasını sağlayan ve "Sonlandırıldı:" iletilerini önleyen daha süslü yol:
#!/usr/bin/env bash
trap_with_arg() { # from https://stackoverflow.com/a/2183063/804678
local func="$1"; shift
for sig in "$@"; do
trap "$func $sig" "$sig"
done
}
stop() {
trap - SIGINT EXIT
printf '\n%s\n' "recieved $1, killing children"
kill -s SIGINT 0
}
trap_with_arg 'stop' EXIT SIGINT SIGTERM SIGHUP
{ i=0; while (( ++i )); do sleep 0.5 && echo "a: $i"; done } &
{ i=0; while (( ++i )); do sleep 0.6 && echo "b: $i"; done } &
while true; do read; done
UPD : minimal örnek eklendi; stop
gereksiz sinyallerin ayrılmasını önleme ve "Sonlandırıldı:" iletilerini çıkıştan gizleme işlevi geliştirildi . Öneriler için Trevor Boyd Smith'e teşekkürler !
stop()
ilk bağımsız değişkeni sinyal numarası olarak sağlarsınız, ancak daha sonra hangi sinyallerin kaydının kaldırıldığını kodlarsınız. kayıttan kaldırılan sinyallerin sabit kodundan ziyade, stop()
fonksiyonda kayıttan çıkmak için ilk argümanı kullanabilirsiniz .
SIGINT
, ancak bir kez daha tuzağa düşecek kill 0
gönderir SIGTERM
. Bu sonsuz bir özyineleme üretmeyecektir, çünkü SIGTERM
ikinci stop
çağrı sırasında tuzağa düşecektir .
trap - $1 && kill -s $1 0
daha iyi çalışmalıdır. Bu cevabı test edip güncelleyeceğim. Güzel fikir için teşekkürler! :)
trap - $1 && kill -s $1 0
öldüremeyeceğimiz için de çalışmaz EXIT
. Ancak tuzağa düşürmek gerçekten yeterlidir TERM
, çünkü kill
bu sinyali varsayılan olarak gönderir.
EXIT
, trap
sinyal işleyici her zaman sadece bir kez yürütülür.
Güvenli tarafta olmak için bir temizleme fonksiyonu tanımlamak ve onu tuzaktan çağırmak daha iyi olur:
cleanup() {
local pids=$(jobs -pr)
[ -n "$pids" ] && kill $pids
}
trap "cleanup" INT QUIT TERM EXIT [...]
veya işlevden tamamen kaçınmak:
trap '[ -n "$(jobs -pr)" ] && kill $(jobs -pr)' INT QUIT TERM EXIT [...]
Neden? Çünkü sadece trap 'kill $(jobs -pr)' [...]
birini kullanarak , tuzak koşulu bildirildiğinde arka plan işlerinin çalışacağını varsayar . Hiç iş olmadığında, aşağıdaki (veya benzeri) bir mesaj görüntülenir:
kill: usage: kill [-s sigspec | -n signum | -sigspec] pid | jobspec ... or kill -l [sigspec]
çünkü jobs -pr
boş - Ben bu 'tuzak' ile sona erdi (cinas amaçlanan).
[ -n "$(jobs -pr)" ]
senaryosu bash üzerinde çalışmıyor. GNU bash, sürüm 4.2.46 (2) -release (x86_64-redhat-linux-gnu) kullanıyorum. "Kill: use" mesajı görüntülenmeye devam ediyor.
jobs -pr
Arka plan süreçlerinin çocuklarının PID'lerini geri döndürmemesi gerçeğiyle ilgili olduğundan şüpheleniyorum . Tüm işlem ağacını yıkmaz, sadece kökleri keser.
Linux, BSD ve MacOS X altında çalışan güzel bir sürüm. İlk önce SIGTERM göndermeye çalışır ve başarılı olmazsa işlemi 10 saniye sonra öldürür.
KillJobs() {
for job in $(jobs -p); do
kill -s SIGTERM $job > /dev/null 2>&1 || (sleep 10 && kill -9 $job > /dev/null 2>&1 &)
done
}
TrapQuit() {
# Whatever you need to clean here
KillJobs
}
trap TrapQuit EXIT
İşlerin büyük çocuk süreçlerini içermediğini lütfen unutmayın.
function cleanup_func {
sleep 0.5
echo cleanup
}
trap "exit \$exit_code" INT TERM
trap "exit_code=\$?; cleanup_func; kill 0" EXIT
# exit 1
# exit 0
Gibi https://stackoverflow.com/a/22644006/10082476 ancak katma exit-koduyla
exit_code
geliyor INT TERM
?
jobs -p, bir alt kabukta çağrılırsa, tümünün çıktısı bir dosyaya yönlendirilmez, ancak bir boruya yönlendirilmezse, tüm kabuklarda çalışmaz. (Başlangıçta yalnızca etkileşimli kullanım için tasarlandığını varsayıyorum.)
Aşağıdakiler ne olacak:
trap 'while kill %% 2>/dev/null; do jobs > /dev/null; done' INT TERM EXIT [...]
"İşler" çağrısı Debian'ın mevcut işi ("%%") eksikse güncellemeyen çizgi kabuğunda gereklidir.
trap 'echo in trap; set -x; trap - TERM EXIT; while kill %% 2>/dev/null; do jobs > /dev/null; done; set +x' INT TERM EXIT; sleep 100 & while true; do printf .; sleep 1; done
Bash (5.0.3) 'te çalıştırırsanız ve sonlandırmaya çalışırsanız, sonsuz bir döngü varmış gibi görünür. Ancak, tekrar sonlandırırsanız çalışır. Dash (0.5.10.2-6) ile bile iki kez sonlandırmanız gerekir.
Bir ön plan işlemi çalıştırdığımda tetiklenmediğini fark ettiğimde , http://veithen.github.io/2014/11/16/sigterm-propagation.html bilgisiyle birleştirilen @ tokland'ın cevabına uyum sağladım. trap
(arka planla belirtilmemiş &
):
#!/bin/bash
# killable-shell.sh: Kills itself and all children (the whole process group) when killed.
# Adapted from http://stackoverflow.com/a/2173421 and http://veithen.github.io/2014/11/16/sigterm-propagation.html
# Note: Does not work (and cannot work) when the shell itself is killed with SIGKILL, for then the trap is not triggered.
trap "trap - SIGTERM && echo 'Caught SIGTERM, sending SIGTERM to process group' && kill -- -$$" SIGINT SIGTERM EXIT
echo $@
"$@" &
PID=$!
wait $PID
trap - SIGINT SIGTERM EXIT
wait $PID
Çalışma örneği:
$ bash killable-shell.sh sleep 100
sleep 100
^Z
[1] + 31568 suspended bash killable-shell.sh sleep 100
$ ps aux | grep "sleep"
niklas 31568 0.0 0.0 19640 1440 pts/18 T 01:30 0:00 bash killable-shell.sh sleep 100
niklas 31569 0.0 0.0 14404 616 pts/18 T 01:30 0:00 sleep 100
niklas 31605 0.0 0.0 18956 936 pts/18 S+ 01:30 0:00 grep --color=auto sleep
$ bg
[1] + 31568 continued bash killable-shell.sh sleep 100
$ kill 31568
Caught SIGTERM, sending SIGTERM to process group
[1] + 31568 terminated bash killable-shell.sh sleep 100
$ ps aux | grep "sleep"
niklas 31717 0.0 0.0 18956 936 pts/18 S+ 01:31 0:00 grep --color=auto sleep
Sadece çeşitlilik için https://stackoverflow.com/a/2173421/102484 varyasyonunu göndereceğim , çünkü bu çözüm ortamımda "Sonlandırıldı" iletisine yol açıyor:
trap 'test -z "$intrap" && export intrap=1 && kill -- -$$' SIGINT SIGTERM EXIT