আমার শেল স্ক্রিপ্টটি প্রস্থান করলে আমি কীভাবে পটভূমি প্রক্রিয়াগুলি / চাকুরীগুলিকে হত্যা করব?


193

আমার শীর্ষ-স্তরের স্ক্রিপ্টটি যখন প্রস্থান করা হবে তখন আমি জগাখিচুড়ি পরিষ্কার করার জন্য একটি উপায় খুঁজছি।

বিশেষত যদি আমি ব্যবহার করতে চাই set -e, তবে আমি স্ক্রিপ্টটি প্রস্থান করলে পটভূমি প্রক্রিয়াটি মরে যেতে চাই।

উত্তর:


186

কিছু গণ্ডগোল পরিষ্কার করতে, trapব্যবহার করা যেতে পারে। এটি নির্দিষ্ট সংকেত এলে সম্পাদিত সামগ্রীর তালিকা সরবরাহ করতে পারে:

trap "echo hello" SIGINT

তবে শেলটি বেরিয়ে আসলে কিছু কার্যকর করতে ব্যবহার করা যেতে পারে:

trap "killall background" EXIT

এটি একটি অন্তর্নির্মিত, তাই help trapআপনাকে তথ্য দেবে ( ব্যাশের সাথে কাজ করে)। আপনি যদি কেবল পটভূমির কাজগুলিই হত্যা করতে চান তবে আপনি এটি করতে পারেন

trap 'kill $(jobs -p)' EXIT

একা ব্যবহার 'করার জন্য সতর্কতা অবলম্বন করুন, শেলটি $()অবিলম্বে প্রতিস্থাপন থেকে রোধ করতে ।


তাহলে কীভাবে কেবল বাচ্চাকে মেরে ফেলবেন ? (বা আমি কী স্পষ্ট কিছু মিস করছি)
এলমার্কো


4
kill $(jobs -p)ড্যাশে কাজ করে না, কারণ এটি একটি
সাবহেলে

8
হয় killall backgroundএকটি স্থানধারক হতে অনুমিত? backgroundম্যান পেজে নেই ...
ইভান বেন

170

এটি আমার পক্ষে কাজ করেছে (মন্তব্যকারীদের কাছে উন্নত ধন্যবাদ):

trap "trap - SIGTERM && kill -- -$$" SIGINT SIGTERM EXIT
  • kill -- -$$পুরো প্রক্রিয়া গোষ্ঠীতে একটি সংকেত প্রেরণ করে , এভাবে বংশধরদেরও হত্যা করা হয়।

  • EXITব্যবহার করার সময় নির্দিষ্ট সংকেত কার্যকর set -e(আরও বিশদ এখানে )।


1
সামগ্রিকভাবে ভাল কাজ করা উচিত, তবে শিশু প্রক্রিয়াগুলি প্রক্রিয়া গ্রুপগুলি পরিবর্তন করতে পারে। অন্যদিকে এটিতে কাজের নিয়ন্ত্রণের প্রয়োজন হয় না এবং অন্যান্য সমাধানের ফলে কিছু নাতি-নাতনী প্রক্রিয়াও মিস হয়ে যেতে পারে।
মাইকেলেলজট

5
দ্রষ্টব্য, "কিল 0" একটি প্যারেন্ট বাশ স্ক্রিপ্টকেও মেরে ফেলবে। আপনি কেবল বর্তমান স্ক্রিপ্টের শিশুদের হত্যা করতে "হত্যা - - AS বাশপিড" ব্যবহার করতে চাইতে পারেন। আপনার বাশ সংস্করণে যদি আপনার কাছে $ BASHPID না থাকে তবে আপনি BASHPID = $ (sh -c 'প্রতিধ্বনি $ পিপিআইডি') রফতানি করতে পারবেন
অ্যাসাইক্লিক

2
সুন্দর এবং পরিষ্কার সমাধানের জন্য আপনাকে ধন্যবাদ! দুর্ভাগ্যক্রমে, এটি 4.3 বাশকে বিভক্ত করে, যা ফাঁদ পুনরাবৃত্তির অনুমতি দেয়। আমি 4.3.30(1)-releaseএটি ওএসএক্স-এ চালিয়েছি এবং এটি উবুন্টুতেও নিশ্চিত হয়ে গেছে । একটি ওভোভিয়াস ওকারাউন্ড রয়েছে , যদিও :)
স্কোজিন

4
আমি বেশ বুঝতে পারি না -$$। এটি '- <PID> to যেমন মূল্যায়ন করে -1234। কিল ম্যানপেজে // বিল্টইন ম্যানপেজে একটি শীর্ষস্থানীয় ড্যাশ প্রেরণের জন্য সংকেত নির্দিষ্ট করে। যাইহোক - সম্ভবত এটি অবরুদ্ধ করে, তবে তারপরে নেতৃত্বের ড্যাশটি অন্যথায় শর্তহীন is কোন সাহায্য?
ইভান বেন

4
@ ইভেনবেইন: চেক করুন man 2 kill, যা ব্যাখ্যা করে যে যখন কোনও পিআইডি নেতিবাচক থাকে তখন প্রদত্ত আইডি ( en.wikedia.org/wiki/Process_group ) সহ প্রক্রিয়া গোষ্ঠীর সমস্ত প্রক্রিয়াতে সংকেত প্রেরণ করা হয় । এটি বিভ্রান্তিকর যে এটিতে man 1 killবা উল্লেখ করা হয়নি man bashএবং ডকুমেন্টেশনে একটি বাগ হিসাবে বিবেচিত হতে পারে।
ব্যবহারকারী001

111

আপডেট: 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? কারণ নেস্টেড সাবশেলগুলি পাশাপাশি হত্যা করা দরকার। এটি পুরো প্রক্রিয়া গাছটি নামিয়ে ফেলবে ।


3
দেবিয়ান সম্পর্কে আমার মামলার একমাত্র সমাধান।
মাইন্ডলেস রেঞ্জার

3
জোহানেস শ্যাউবের উত্তর বা টোকল্যান্ডের দ্বারা প্রদত্ত কেউই আমার শেল স্ক্রিপ্টটি শুরু করার পটভূমি প্রক্রিয়াগুলি (ডেবিয়ানে) হত্যা করতে সক্ষম হয় নি। এই সমাধান কাজ করে। আমি জানি না কেন এই উত্তরটি বেশি প্রচারিত হয় না। ঠিক কী kill 0বোঝায় / করায় সে সম্পর্কে আপনি আরও প্রসারিত করতে পারেন?
জোশ

7
এটি দুর্দান্ত, তবে আমার
পিতামাত্ত শেলটিকেও

5
এই সমাধানটি আক্ষরিকভাবে ওভারকিল। হত্যা 0 (আমার স্ক্রিপ্টের ভিতরে) আমার পুরো এক্স সেশনটি নষ্ট করে দিয়েছে! সম্ভবত কিছু ক্ষেত্রে 0 কে হত্যা কার্যকর হতে পারে তবে এটি সাধারণ সমাধান নয় এবং এটি ব্যবহারের খুব ভাল কারণ না থাকলে যদি সম্ভব হয় তবে এড়ানো উচিত change এটি একটি স্ক্রিপ্টের ব্যাকগ্রাউন্ড জব নয়, প্যারেন্ট শেল বা এমনকি পুরো এক্স সেশনটিকে মেরে ফেলতে পারে এমন একটি সতর্কতা যুক্ত করা ভাল হবে!
লিসানরো রায়েন

3
যদিও এটি কিছু পরিস্থিতিতে একটি আকর্ষণীয় সমাধান হতে পারে, @ বিডিজটিজ দ্বারা চিহ্নিত হিসাবে এটি পুরো প্রক্রিয়া গোষ্ঠীকে হত্যা করবে যার মধ্যে প্রবর্তন প্রক্রিয়া অন্তর্ভুক্ত রয়েছে (অর্থাত্ বেশিরভাগ ক্ষেত্রে প্যারেন্ট শেল)। আপনি যখন কোনও আইডিই এর মাধ্যমে স্ক্রিপ্ট চালাচ্ছেন তখন অবশ্যই আপনি চান এমন কিছু নয়।
ম্যাটপেন

21

ফাঁদ 'কিল $ (জব -২)' প্রস্থান করুন

আমি জোহানেসের উত্তরে কেবলমাত্র সামান্য পরিবর্তন করব এবং চাকরির ব্যবহারটি চলমান প্রক্রিয়াগুলিতে সীমাবদ্ধ করতে এবং তালিকায় আরও কয়েকটি সংকেত যোগ করতে:

trap 'kill $(jobs -pr)' SIGINT SIGTERM EXIT

বন্ধ করা চাকরি গুলোকেও মেরে ফেলবে না কেন? ব্যাশ-এ সিগিন্ট এবং সিগনটার্মের ক্ষেত্রেও এক্সিট ফাঁদ চালানো হবে, সুতরাং এই জাতীয় সংকেতের ক্ষেত্রে ট্র্যাপটি দু'বার কল করা হবে।
জার্নো

14

trap 'kill 0' SIGINT SIGTERM EXITসমাধান বর্ণিত @ tokland এর উত্তর সত্যিই চমৎকার, কিন্তু সর্বশেষ ব্যাশ একটি segmantation দোষ সঙ্গে বিপর্যস্ত যখন এটি ব্যবহার করে। কারণ বাশ, ভি। ৪.৩ থেকে শুরু করে ফাঁদ পুনরাবৃত্তি করার অনুমতি দেয়, যা এই ক্ষেত্রে অসীম হয়ে ওঠে:

  1. শেল প্রক্রিয়া পুনরুদ্ধার SIGINTবা SIGTERMবা EXIT;
  2. সিগন্যাল আটকা পড়ে, কার্যকর করে kill 0, যা SIGTERMশেল নিজেই সহ গ্রুপে সমস্ত প্রক্রিয়াগুলিতে প্রেরণ করে;
  3. 1 :) এ যান

এই ফাঁদটি ম্যানুয়ালি করে নিবন্ধভুক্ত করে কাজ করা যেতে পারে:

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

ইউপিডি : সংক্ষিপ্ত উদাহরণ যুক্ত; 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সিগন্যাল-হ্যান্ডলারটি সর্বদা কেবল একবারই কার্যকর করা হয়।
ট্রেভর বয়েড স্মিথ

9

নিরাপদে থাকাকালীন পরিষ্কার-পরিচ্ছন্নতার ফাংশনটি সংজ্ঞায়িত করা এবং ফাঁদ থেকে কল করা ভাল বলে মনে করি:

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)" ]কেসটি আমার বাশে কাজ করে না। আমি জিএনইউ ব্যাশ, সংস্করণ 4.2.46 (2) -রিলেজ (x86_64-redhat-linux-gnu) ব্যবহার করি। "হত্যা: ব্যবহার" বার্তাটি পপ আপ করে রাখে।
ডুউ ভ্যান ডের লেস্ট

আমার সন্দেহ হয় যে jobs -prএটি ব্যাকগ্রাউন্ড প্রক্রিয়াগুলির বাচ্চাদের পিআইডি ফিরিয়ে দেয় না এর সাথে করা উচিত । এটি পুরো প্রক্রিয়া গাছটি ছিন্ন করে না, কেবল শিকড়গুলি ছাঁটাই করে।
ডুউ ভ্যান ডের লেস্ট

2

একটি দুর্দান্ত সংস্করণ যা লিনাক্স, বিএসডি এবং ম্যাকোস এক্স এর অধীনে কাজ করে First

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

দয়া করে মনে রাখবেন যে চাকরিতে গ্র্যান্ড বাচ্চাদের প্রক্রিয়া অন্তর্ভুক্ত নয়।



1

অন্য বিকল্পটি হ'ল স্ক্রিপ্টটি নিজেকে প্রক্রিয়া গ্রুপের নেতা হিসাবে সেট করে এবং প্রস্থান করার সময় আপনার প্রক্রিয়া গোষ্ঠীতে একটি কিলপ্যাগ আটকে।


প্রক্রিয়া গ্রুপ লিডার হিসাবে আপনি প্রক্রিয়াটি কীভাবে সেট করবেন? "কিলপজি" কী?
জার্নো

0

সুতরাং স্ক্রিপ্ট লোড স্ক্রিপ্ট। killallস্ক্রিপ্টটি শেষ হওয়ার সাথে সাথে কার্যকর করা একটি (বা আপনার ওএসে যা কিছু আছে) কমান্ডটি চালান ।


0

জবস -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) আপনাকে এটি দুটিবার শেষ করতে হবে।
জার্নো

0

Http://veithen.github.io/2014/11/16/sigterm-propagation.html থেকে জ্ঞানের সাথে মিলিয়ে আমি @ টোকল্যান্ডের উত্তরটির একটি রূপান্তর করেছি যখন আমি লক্ষ্য করেছি যে 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

0

কেবলমাত্র বৈচিত্র্যের জন্য আমি https://stackoverflow.com/a/2173421/102484 এর ভিন্নতা পোস্ট করব , কারণ এই সমাধানটি আমার পরিবেশে "সমাপ্ত" বার্তা নিয়ে যায়:

trap 'test -z "$intrap" && export intrap=1 && kill -- -$$' SIGINT SIGTERM EXIT
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.