जवाबों:
कुछ गंदगी को साफ करने के लिए trap
इस्तेमाल किया जा सकता है। यह एक विशिष्ट सिग्नल आने पर निष्पादित सामान की सूची प्रदान कर सकता है:
trap "echo hello" SIGINT
लेकिन यह भी इस्तेमाल किया जा सकता है कि कुछ बाहर निकलता है तो शेल बाहर निकलता है:
trap "killall background" EXIT
यह एक बिलिन है, इसलिए help trap
आपको जानकारी देगा (काम के साथ काम करता है)। यदि आप केवल बैकग्राउंड जॉब्स को मारना चाहते हैं, तो आप कर सकते हैं
trap 'kill $(jobs -p)' EXIT
सिंगल का उपयोग '
करने के लिए देखें, शेल को $()
तुरंत प्रतिस्थापित करने से रोकने के लिए ।
kill $(jobs -p)
डैश में काम नहीं करता है, क्योंकि यह एक सबशेल में कमांड प्रतिस्थापन को निष्पादित करता है (मैन डैश में कमांड
killall background
एक प्लेसहोल्डर होना चाहिए? background
मैन पेज में नहीं है ...
यह मेरे लिए काम करता है (टिप्पणीकारों के लिए धन्यवाद में सुधार):
trap "trap - SIGTERM && kill -- -$$" SIGINT SIGTERM EXIT
4.3.30(1)-release
OSX पर इस पर भाग गया , और यह भी Ubuntu पर पुष्टि की है । वहाँ एक obvoius wokaround है , हालांकि :)
-$$
। यह '- <PID> `जैसे मूल्यांकन करता है -1234
। किल मैनपेज // बिलियन मैनपेज में एक प्रमुख डैश भेजे जाने वाले सिग्नल को निर्दिष्ट करता है। हालांकि - शायद वह ब्लॉक करता है, लेकिन फिर प्रमुख डैश अन्यथा अनिर्धारित है। कोई मदद?
man 2 kill
, जो बताता है कि जब एक पीआईडी नकारात्मक है, तो प्रक्रिया समूह में सभी प्रक्रियाओं को प्रदान की गई आईडी ( en.wikipedia.org/wiki/Process_group ) के साथ सिग्नल भेजा जाता है । यह भ्रामक है कि इस में उल्लेख नहीं है man 1 kill
या man bash
, और प्रलेखन में एक बग माना जा सकता है।
अपडेट: https://stackoverflow.com/a/53714583/302079 इसमें एग्जिट स्टेटस और क्लीनअप फंक्शन जोड़कर सुधार करता है।
trap "exit" INT TERM
trap "kill 0" EXIT
क्यों कन्वर्ट INT
और TERM
बाहर निकलने के लिए? क्योंकि दोनों को kill 0
एक अनंत लूप में प्रवेश किए बिना ट्रिगर करना चाहिए ।
क्यों ट्रिगर kill 0
पर EXIT
? क्योंकि सामान्य स्क्रिप्ट निकास को ट्रिगर होना चाहिए kill 0
, भी।
क्यों kill 0
? क्योंकि नेस्टेड सबशेल्स को भी मारने की जरूरत है। यह पूरी प्रक्रिया के पेड़ को नीचे ले जाएगा ।
kill 0
इसका क्या मतलब है / करता है?
जाल 'मार $ (नौकरियों -p)' बाहर निकलें
मैं जोहान्स के उत्तर में केवल मामूली बदलाव करूंगा और नौकरियों का उपयोग करूंगा-मार को रनिंग प्रक्रियाओं तक सीमित कर दूंगा और सूची में कुछ और सिग्नल जोड़ दूंगा:
trap 'kill $(jobs -pr)' SIGINT SIGTERM EXIT
trap 'kill 0' SIGINT SIGTERM EXIT
समाधान में वर्णित @ tokland का जवाब वास्तव में अच्छा है, लेकिन नवीनतम बैश एक segmantation गलती के साथ दुर्घटनाओं जब इसे का उपयोग। ऐसा इसलिए है क्योंकि बैश, v। 4.3 से शुरू होकर, ट्रैप पुनरावृत्ति की अनुमति देता है, जो इस मामले में अनंत हो जाता है:
SIGINT
या SIGTERM
या EXIT
;kill 0
, जो SIGTERM
समूह में सभी प्रक्रियाओं को भेजता है, जिसमें स्वयं शेल भी शामिल है;यह जाल को मैन्युअल रूप से डी-रजिस्टर करके चारों ओर काम किया जा सकता है:
trap 'trap - SIGTERM && kill 0' SIGINT SIGTERM EXIT
अधिक फैंसी तरीका है, जो हटाए गए सिग्नल को प्रिंट करने और "समाप्त:" संदेश से बचने की अनुमति देता है:
#!/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 : न्यूनतम उदाहरण जोड़ा गया; stop
अनावश्यक संकेतों को हटाने और "समाप्त:" संदेशों को आउटपुट से छिपाने के लिए एवियोड डी-ट्रैपिंग में सुधार हुआ । सुझाव के लिए धन्यवाद ट्रेवर बॉयड स्मिथ !
stop()
आप सिग्नल नंबर के रूप में पहला तर्क प्रदान करते हैं लेकिन फिर आप हार्डकोड करते हैं कि सिग्नल किस तरह से निष्क्रिय किए जा रहे हैं। हार्डकोड के बजाय सिग्नल डीरेगिस्टर किए जा रहे हैं आप stop()
फ़ंक्शन में डेरेगिस्टर के लिए पहले तर्क का उपयोग कर सकते हैं (ऐसा करने से संभावित रूप से अन्य पुनरावर्ती सिग्नल (3 हार्डकोड के अलावा) बंद हो जाएंगे)।
SIGINT
, लेकिन kill 0
भेजता है SIGTERM
, जो एक बार फिर से फंस जाएगा। यह अनंत पुनरावृत्ति उत्पन्न नहीं करेगा, हालांकि, क्योंकि SIGTERM
दूसरी stop
कॉल के दौरान डी-फंस जाएगा ।
trap - $1 && kill -s $1 0
बेहतर काम करना चाहिए। मैं इस उत्तर का परीक्षण और अद्यतन करूंगा। अच्छे विचार के लिए धन्यवाद! :)
trap - $1 && kill -s $1 0
हम भी नहीं मार सकते हैं, क्योंकि हम साथ काम नहीं कर सकते EXIT
। लेकिन यह वास्तव में पर्याप्त है डी-ट्रैप TERM
, क्योंकि kill
यह संकेत डिफ़ॉल्ट रूप से भेजता है।
EXIT
, trap
सिग्नल-हैंडलर को केवल एक बार निष्पादित किया जाता है।
सुरक्षित पक्ष पर होने के लिए मुझे एक सफाई फ़ंक्शन को परिभाषित करना और जाल से कॉल करना बेहतर लगता है:
cleanup() {
local pids=$(jobs -pr)
[ -n "$pids" ] && kill $pids
}
trap "cleanup" INT QUIT TERM EXIT [...]
या पूरी तरह से समारोह से परहेज:
trap '[ -n "$(jobs -pr)" ] && kill $(jobs -pr)' INT QUIT TERM EXIT [...]
क्यों? क्योंकि बस का उपयोग करके trap 'kill $(jobs -pr)' [...]
एक मानता है कि वहाँ होगा जब जाल हालत का संकेत है पृष्ठभूमि में चल रहे रोजगार के अवसर हो। जब कोई काम नहीं होता है, तो निम्न (या समान) संदेश देखेंगे:
kill: usage: kill [-s sigspec | -n signum | -sigspec] pid | jobspec ... or kill -l [sigspec]
क्योंकि jobs -pr
खाली है - मैं उस 'जाल' (सजा का इरादा) में समाप्त हो गया।
[ -n "$(jobs -pr)" ]
मेरे बैश पर काम नहीं करता है। मैं GNU बैश, संस्करण 4.2.46 (2) -release (x86_64-redhat-linux-gnu) का उपयोग करता हूं। "मार: उपयोग" संदेश पॉप अप करता रहता है।
jobs -pr
यह इस तथ्य के साथ करना है कि पृष्ठभूमि प्रक्रियाओं के बच्चों के पीआईडी वापस नहीं करते हैं। यह पूरी प्रक्रिया के पेड़ को नहीं फाड़ता है, केवल जड़ों को काटता है।
लिनक्स, बीएसडी और मैकओएस एक्स के तहत काम करने वाला एक अच्छा संस्करण। पहले SIGTERM भेजने की कोशिश करता है, और अगर यह सफल नहीं होता है, तो 10 सेकंड के बाद प्रक्रिया को मारता है।
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
कृपया ध्यान दें कि नौकरियों में भव्य बच्चों की प्रक्रिया शामिल नहीं है।
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
जैसे https://stackoverflow.com/a/22644006/10082476 , लेकिन अतिरिक्त निकास-कोड के साथ
exit_code
से आता है INT TERM
जाल में?
जॉब्स -p सभी शेल में काम नहीं करता है यदि सब-शेल में कहा जाता है, संभवतः तब तक जब तक इसका आउटपुट किसी फ़ाइल में रीडायरेक्ट न हो जाए लेकिन पाइप न हो। (मुझे लगता है कि यह मूल रूप से केवल इंटरैक्टिव उपयोग के लिए इरादा था।)
निम्नलिखित के बारे में क्या:
trap 'while kill %% 2>/dev/null; do jobs > /dev/null; done' INT TERM EXIT [...]
डेबियन के डैश शेल के साथ "नौकरियों" के लिए कॉल की आवश्यकता होती है, जो कि लापता होने पर वर्तमान नौकरी ("%%") को अपडेट करने में विफल रहता है।
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
यदि आप इसे बाश (5.0.3) में चलाते हैं और समाप्त करने की कोशिश करते हैं, तो एक अनंत लूप लगता है। हालांकि, यदि आप इसे फिर से समाप्त करते हैं, तो यह काम करता है। यहां तक कि डैश (0.5.10.2-6) तक आपको इसे दो बार समाप्त करना होगा।
जब मैंने http://veithen.github.io/2014/11/16/sigterm-propagation.html से ज्ञान के साथ संयुक्त @ tokland के उत्तर का रूपांतरण किया, तो मैंने देखा कि trap
अगर मैं अग्रभूमि प्रक्रिया चला रहा हूं तो ट्रिगर नहीं होता है (पृष्ठभूमि के साथ नहीं &
):
#!/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
यह काम करने का उदाहरण:
$ 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
विविधता के लिए मैं https://stackoverflow.com/a/2173421/102484 की विविधता पोस्ट करूंगा , क्योंकि उस समाधान से मेरे वातावरण में "टर्मिनेटेड" संदेश जाता है:
trap 'test -z "$intrap" && export intrap=1 && kill -- -$$' SIGINT SIGTERM EXIT