বাশ-এ সন্তানের কাছে ফরোয়ার্ড করুন


86

আমার একটি বাশ স্ক্রিপ্ট রয়েছে যা এর সাথে একই দেখাচ্ছে:

#!/bin/bash
echo "Doing some initial work....";
/bin/start/main/server --nodaemon

এখন যদি স্ক্রিপ্টটিতে চলমান বাশ শেলটি একটি SIGTERM সিগন্যাল পায়, তবে এটি চলমান সার্ভারে একটি SIGTERM প্রেরণ করা উচিত (যা অবরুদ্ধ করে, তাই কোনও ফাঁদ সম্ভব নয়)। এটা কি সম্ভব?

উত্তর:


91

চেষ্টা করুন:

#!/bin/bash 

_term() { 
  echo "Caught SIGTERM signal!" 
  kill -TERM "$child" 2>/dev/null
}

trap _term SIGTERM

echo "Doing some initial work...";
/bin/start/main/server --nodaemon &

child=$! 
wait "$child"

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

শেলটি যখন পায় SIGTERM(বা সার্ভারটি স্বতঃস্ফূর্তভাবে প্রস্থান করে), waitকলটি ফিরে আসবে (সার্ভারের প্রস্থান কোডের সাথে বা একটি সংকেত প্রাপ্তির ক্ষেত্রে সিগন্যাল নম্বর + 128 সহ প্রস্থান করা হবে)। এরপরে, যদি শেলটি SIGTERM পেয়ে থাকে তবে এটি _termপ্রস্থান করার আগে SIGTERM ট্র্যাপ হ্যান্ডলার হিসাবে নির্দিষ্ট ফাংশনটি কল করবে (যাতে আমরা কোনও ক্লিনআপ করি এবং ব্যবহার করে সার্ভার প্রক্রিয়াটিতে ম্যানুয়ালি সিগন্যালটি প্রচার করি kill)।


ভাল লাগছে! আমি এটি চেষ্টা করব এবং যখন আমি এটি পরীক্ষা করব তখন প্রতিক্রিয়া জানাব।
লরেঞ্জ

7
কিন্তু এক্সিকিউটটি প্রদত্ত প্রোগ্রামের সাথে শেলটি প্রতিস্থাপন করে , waitতারপরের কলটির পরে কেন প্রয়োজন হবে তা সম্পর্কে আমি পরিষ্কার নই ?
ইরুভার

5
আমি মনে করি যে 1_CR এর পয়েন্টটি বৈধ। হয় আপনি কেবল ব্যবহার করেন exec /bin/start/main/server --nodaemon(সেক্ষেত্রে শেল প্রক্রিয়াটি সার্ভার প্রক্রিয়াটির সাথে প্রতিস্থাপিত হয় এবং আপনার কোনও সংকেত প্রচারের দরকার নেই) বা আপনি ব্যবহার করেন /bin/start/main/server --nodaemon &তবে execতা আসলে অর্থবহ নয়।
Andreas Veithen

2
যদি আপনি চান যে আপনার শেল স্ক্রিপ্টটি শিশুকে শেষ করার পরেই শেষ করা যায় তবে _term()ফাংশনে আপনাকে wait "$child"আবার করা উচিত । শেল স্ক্রিপ্টটি আবার চালু করার আগে মারা যাওয়ার অপেক্ষায় আপনার যদি আরও কিছু তত্ত্বাবধানের প্রক্রিয়া থাকে তবে বা যদি আপনি EXITকিছু সাফাইয়ের কাজ করতে গিয়ে আটকে থাকেন এবং কেবল শিশু প্রক্রিয়াটি শেষ হওয়ার পরে এটি চালানোর প্রয়োজন হয় তবে এটি প্রয়োজনীয় হতে পারে।
লিওরোকেল

1
অন্যান্য উত্তর পড়ুন হয় আপনি খুঁজছেন exec, বা আপনি ফাঁদ সেট আপ করতে চান ।
স্টুয়ার্ট পি। বেন্টলে

78

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

#!/bin/bash
echo "Doing some initial work....";
exec /bin/start/main/server --nodaemon

আপনি কোনো কারণে প্রায় শেল রাখা দরকার হয় তাহলে (অর্থাৎ। তোমার পরে সার্ভার বন্ধ কিছু পরিষ্করণ যা করতে হবে), আপনি সংমিশ্রণ ব্যবহার করা উচিত trap, waitএবং kill। দেখুন SensorSmith এর উত্তর


এটা সঠিক উত্তর! আরও অনেক সংক্ষিপ্ত এবং
ওপির

20

আন্ড্রেস ভীথেন উল্লেখ করেছেন যে আপনার যদি কল থেকে ফিরে আসতে হবে না (যেমন ওপি'র উদাহরণে) কেবল execকমান্ডের মাধ্যমে কল করা যথেষ্ট ( @ স্টুয়ার্ট পি। বেন্টলির উত্তর )। অন্যথায় "traditional trap 'kill $CHILDPID' TERMতিহ্যবাহী " (@ কিওংলমের উত্তর) একটি শুরু, তবে ট্র্যাপটি waitহ্যান্ডলারটি চালানোর পরে কলটি আসলে ফিরে আসে যা শিশু প্রক্রিয়াটি আসলে প্রস্থান হওয়ার আগেই হতে পারে। সুতরাং একটি "অতিরিক্ত" কল waitপরামর্শ দেওয়া হয় ( @ ব্যবহারকারী 1463361 এর উত্তর )।

যদিও এটি একটি উন্নতি হিসাবে এটি এখনও একটি রেসের শর্ত রয়েছে যার অর্থ প্রক্রিয়াটি কখনই প্রস্থান করতে পারে না (যদি না সিগনালার TERM সংকেত প্রেরণে পুনরায় চেষ্টা না করে)। দুর্বলতার উইন্ডোটি ট্র্যাপ হ্যান্ডলারের নিবন্ধকরণ এবং সন্তানের পিআইডি রেকর্ড করার মধ্যে রয়েছে।

নিম্নলিখিত যে দুর্বলতা (পুনঃব্যবহারের জন্য কার্যাদি মধ্যে প্যাকেজড) অপসারণ করে।

prep_term()
{
    unset term_child_pid
    unset term_kill_needed
    trap 'handle_term' TERM INT
}

handle_term()
{
    if [ "${term_child_pid}" ]; then
        kill -TERM "${term_child_pid}" 2>/dev/null
    else
        term_kill_needed="yes"
    fi
}

wait_term()
{
    term_child_pid=$!
    if [ "${term_kill_needed}" ]; then
        kill -TERM "${term_child_pid}" 2>/dev/null 
    fi
    wait ${term_child_pid}
    trap - TERM INT
    wait ${term_child_pid}
}

# EXAMPLE USAGE
prep_term
/bin/something &
wait_term

2
দুর্দান্ত কাজ - আমি এখানে জবাব দেওয়ার জন্য আমার উত্তরের লিঙ্কটি আপডেট করেছি (এর উপরে আরও বিস্তৃত সমাধান হওয়া সত্ত্বেও, আমি এখনও কিছুটা আপ্লুত হয়েছি যে স্ট্যাক এক্সচেঞ্জ ইউআই আমাকে স্ক্রিপ্ট ঠিক করার জন্য কুওনলমের উত্তরে আমাকে জমা দেয় না আসলে এটি যা করা উচিত তা করুন এবং ওপি-র পরে সমস্ত ব্যাখ্যামূলক পাঠ্য লিখুন যিনি কিছুটা ছোটখাটো পুনরায় সম্পাদনা করেছিলেন তাও বুঝতে পারেননি )।
স্টুয়ার্ট পি। বেন্টলে

2
@ স্টুয়ার্টপি.বেন্টলে, ধন্যবাদ আমি ছিল এই প্রয়োজনীয় দুটি (চলবে না) উত্তর এবং একটি বহিস্থিত রেফারেন্স একত্রিতকরনের বিস্মিত, এবং তারপর আমি race অবস্থা পিছু নিয়েছিলাম। আমি আমার রেফারেন্সগুলিকে লিঙ্কগুলিতে আপগ্রেড করব যা আমি অতিরিক্ত কিছু অতিরিক্ত কুডো দিতে পারি।
সেন্সরসমিত

3

প্রদত্ত সমাধান আমার পক্ষে কাজ করে না কারণ অপেক্ষা কমান্ডটি আসলে শেষ হওয়ার আগে প্রক্রিয়াটি মারা গিয়েছিল। আমি এই নিবন্ধটি পেয়েছি http://veithen.github.io/2014/11/16/sigterm-propagation.html , আমার আবেদনের ক্ষেত্রে শেষ স্নিপেটটি কাস্টম শ রানার দিয়ে ওপেনশিফটে শুরু হয়েছিল। Sh স্ক্রিপ্টটি প্রয়োজনীয় কারণ আমার জাভা প্রক্রিয়াটির পিআইডি 1 হ'ল থ্রেড ডাম্প পাওয়ার ক্ষমতা অর্জন করা দরকার।

trap 'kill -TERM $PID' TERM INT
$JAVA_EXECUTABLE $JAVA_ARGS &
PID=$!
wait $PID
trap - TERM INT
wait $PID
EXIT_STATUS=$?
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.