আমি যখন সিটিআরএল + সি করব তখন কীভাবে শেল স্ক্রিপ্টে ব্যাকগ্রাউন্ড প্রক্রিয়াগুলি শেষ হয়ে যায় এবং অপেক্ষা করতে পারি?


24

আমি একটি শেল স্ক্রিপ্ট সেট আপ করার চেষ্টা করছি যাতে এটি পটভূমি প্রক্রিয়াগুলি চালায় এবং আমি যখন Ctrlcশেল স্ক্রিপ্টটি করি তখন এটি বাচ্চাদের হত্যা করে, তারপরে উপস্থিত হয়।

আমি যে সেরাটি নিয়ে আসতে পেরেছি তা হ'ল এটি। এটি প্রতীয়মান হয় যে kill 0 -INTঅপেক্ষাটি হওয়ার আগে স্ক্রিপ্টটিও হত্যা করে, তাই শিশুদের সম্পূর্ণ হওয়ার আগে শেল স্ক্রিপ্টটি মারা যায়।

আমি কীভাবে এই শেল স্ক্রিপ্টটি তৈরি করতে পারি বাচ্চাদের প্রেরণের পরে মারা যাওয়ার অপেক্ষায় INT?

#!/bin/bash
trap 'killall' INT

killall() {
    echo "**** Shutting down... ****"
    kill 0 -INT
    wait # Why doesn't this wait??
    echo DONE
}

process1 &
process2 &
process3 &

cat # wait forever


আমি "শেল ইন্টারসেপ্ট কিল সুইচ" অনুসন্ধান করে এই প্রশ্নটি পেয়েছি, ট্র্যাপ কমান্ডটি ভাগ করে নেওয়ার জন্য ধন্যবাদ, যখন অ্যাপ্লিকেশনটি বন্ধ জিইউআই বোতামের মাধ্যমে অ্যাপটি সঠিকভাবে প্রস্থান না করে তখন কোনও অ্যাপটি Ctrl + C এর সাথে প্রস্থান করার পরে একটি আদেশ কার্যকর করা খুব কার্যকর very
ব্যাপটেক্স

উত্তর:


22

আপনার killআদেশ পিছন দিকে।

অনেক ইউনিক্স কমান্ডের মতো, অন্যান্য যুক্তির আগে, বিয়োগ দিয়ে শুরু হওয়া বিকল্পগুলি অবশ্যই আগে আসবে।

যদি লিখি

kill -INT 0

এটি -INTবিকল্প হিসাবে দেখে এবং প্রেরণ SIGINTকরে 0( 0বর্তমান প্রক্রিয়া গোষ্ঠীর সমস্ত প্রক্রিয়াগুলির অর্থ একটি বিশেষ সংখ্যা)।

তবে লিখলে

kill 0 -INT

এটি দেখে 0, সিদ্ধান্ত নেয় যে আর কোনও বিকল্প নেই, তাই SIGTERMডিফল্টরূপে ব্যবহার করে। এবং এটি বর্তমান প্রক্রিয়া গোষ্ঠীতে প্রেরণ করে , যেমনটি আপনি করেছেন

kill -TERM 0 -INT    

(এটা এছাড়াও পাঠানোর চেষ্টা করবে SIGTERMকরার -INT, যা একটি বাক্য গঠন ত্রুটি কারণ হবে, কিন্তু এটা পাঠায় SIGTERMকরার 0প্রথম, এবং পায় না যে পর্যন্ত।)

সুতরাং আপনার প্রধান স্ক্রিপ্ট একটি হচ্ছে SIGTERMআগে এটি চালানোর জন্য পায় waitএবং echo DONE

যোগ

trap 'echo got SIGTERM' TERM

শীর্ষে, ঠিক পরে

trap 'killall' INT

এবং এটি প্রমাণ করতে এটি আবার চালান।

স্টিফেন চেজেলাস যেমন উল্লেখ করেছেন, আপনার পটভূমি শিশুরা ( process1ইত্যাদি) SIGINTডিফল্টরূপে উপেক্ষা করবে ।

যাই হোক না কেন, আমি মনে করি পাঠানো SIGTERMআরও অর্থবোধ করবে।

অবশেষে, আমি নিশ্চিত না যে kill -process groupপ্রথমে বাচ্চাদের কাছে যাওয়ার গ্যারান্টিযুক্ত কিনা । শাট ডাউন করার সময় সিগন্যালগুলি উপেক্ষা করা ভাল ধারণা হতে পারে।

সুতরাং এটি চেষ্টা করুন:

#!/bin/bash
trap 'killall' INT

killall() {
    trap '' INT TERM     # ignore INT and TERM while shutting down
    echo "**** Shutting down... ****"     # added double quotes
    kill -TERM 0         # fixed order, send TERM not INT
    wait
    echo DONE
}

./process1 &
./process2 &
./process3 &

cat # wait forever

ধন্যবাদ, এটি কাজ করে! যে সমস্যা হয়েছে বলে মনে হচ্ছে।
স্লিপহিড

9

দুর্ভাগ্যক্রমে, ব্যাকগ্রাউন্ডে শুরু হওয়া কমান্ডগুলি শাইন দ্বারা সাইন ইন করার জন্য সেট করা হয় এবং আরও খারাপ, তারা এটিকে এলোমেলো করতে পারে না trap। অন্যথায়, আপনাকে যা করতে হবে তা হ'ল

(trap - INT; exec process1) &
(trap - INT; exec process2) &
trap '' INT
wait

কারণ প্রসেস 1 এবং প্রসেস 2 আপনি সিআরটিএল-সি চাপলে সিগন্যালটি পাবেন কারণ তারা একই প্রক্রিয়া গোষ্ঠীর অংশ যা টার্মিনালের অগ্রভাগ প্রক্রিয়া গ্রুপ।

উপরের কোডটি pdksh এবং zsh এর সাথে কাজ করবে যা সে ক্ষেত্রে POSIX অনুসারে নয়।

অন্যান্য শেলগুলির সাথে, আপনাকে সাইন্টের জন্য ডিফল্ট হ্যান্ডলারটি পুনরুদ্ধার করতে অন্য কিছু ব্যবহার করতে হবে:

perl -e '$SIG{INT}=DEFAULT; exec "process1"' &

বা SIGTERM এর মতো আলাদা সিগন্যাল ব্যবহার করুন।


2

যারা কেবল একটি প্রক্রিয়াটি হত্যা করতে চান এবং এটি মারা যাওয়ার জন্য অপেক্ষা করেন, তবে অনির্দিষ্টকালের জন্য নয় :

এটি প্রতি সিগন্যাল প্রকারে সর্বোচ্চ 60 সেকেন্ড অপেক্ষা করে।

সতর্কতা: এই উত্তর কোনওভাবেই কোনও কিল সংকেত ফাঁদে ফেলে এবং প্রেরণের সাথে সম্পর্কিত নয়।

# close_app_sub GREP_STATEMENT SIGNAL DURATION_SEC
# GREP_STATEMENT must not match itself!
close_app_sub() {
    APP_PID=$(ps -x | grep "$1" | grep -oP '^\s*\K[0-9]+' --color=never)
    if [ ! -z "$APP_PID" ]; then
        echo "App is open. Trying to close app (SIGNAL $2). Max $3sec."
        kill $2 "$APP_PID"
        WAIT_LOOP=0
        while ps -p "$APP_PID" > /dev/null 2>&1; do
            sleep 1
            WAIT_LOOP=$((WAIT_LOOP+1))
            if [ "$WAIT_LOOP" = "$3" ]; then
                break
            fi
        done
    fi
    APP_PID=$(ps -x | grep "$1" | grep -oP '^\s*\K[0-9]+' --color=never)
    if [ -z "$APP_PID" ]; then return 0; else return "$APP_PID"; fi
}

close_app() {
    close_app_sub "$1" "-HUP" "60"
    close_app_sub "$1" "-TERM" "60"
    close_app_sub "$1" "-SIGINT" "60"
    close_app_sub "$1" "-KILL" "60"
    return $?
}

close_app "[f]irefox"

নাম বা যুক্তি দিয়ে হত্যা করার জন্য এটি অ্যাপ্লিকেশন নির্বাচন করে। গ্রেপ নিজেই মিলে যাওয়ার জন্য অ্যাপের নামের প্রথম অক্ষরের জন্য বন্ধনী রাখুন।

কিছু পরিবর্তন, আপনি সরাসরি পিআইডি বা বিবৃতি pidof process_nameপরিবর্তে একটি সহজ ব্যবহার করতে পারেন ps

কোডের বিশদ: চূড়ান্ত গ্রেপ হ'ল পিছনের স্থান ছাড়াই পিআইডি পাওয়া।


1

আপনি যা চান তা যদি কিছু ব্যাকগ্রাউন্ড প্রক্রিয়া পরিচালনা করতে হয় তবে ব্যাশ জব কন্ট্রোল বৈশিষ্ট্যগুলি ব্যবহার করবেন না কেন?

$ gedit &
[1] 2581
$ emacs &
[2] 2594
$ jobs
[1]-  Running                 gedit &
[2]+  Running                 emacs &
$ jobs -p
2581
2594
$ kill -2 `jobs -p`
$ jobs
[1]-  Interrupt               gedit
[2]+  Done                    emacs

0

তাই আমি পাশাপাশি এটি সঙ্গে tinkered। বাশে, আপনি ফাংশনগুলি সংজ্ঞায়িত করতে পারেন এবং সেগুলির সাথে অভিনব জিনিসগুলি করতে পারেন। আমার সহকর্মীরা এবং আমি ব্যবহার করি terminator, সুতরাং ব্যাচ মৃত্যুদন্ড কার্যকর করার জন্য আমরা সাধারণত আউটপুট দেখতে চাইলে টার্মিনেটর উইন্ডোগুলির একটি পুরো গোছা তৈরি করি ( tmuxট্যাবগুলির চেয়ে কম মার্জিত , তবে আপনি আরও জিইআই-এর মতো ইন্টারফেস হাহা ব্যবহার করতে পারেন)।

আমি যে সেটআপটি নিয়ে এসেছি তা এখানে রয়েছে, সেই সাথে আপনি চালাতে পারেন এমন সামগ্রীর উদাহরণ:

#!/bin/bash
custom()
{
    terun 'something cool' 'yes'
    run 'xclock'
    terun 'echoes' 'echo Hello; echo Goodbye; read'
    func()
    {
        local i=0
        while :
        do
            echo "Iter $i"
            let i+=1
            sleep 0.25
        done
    }
    export -f func
    terun 'custom func' 'func'
}

# [ Setup ]
run()
{
    "$@" &
    # Give process some time to start up so windows are sequential
    sleep 0.05
}
terun()
{
    run terminator -T "$1" -e "$2"
}
finish()
{
    procs="$(jobs -p)"
    echo "Kill: $procs"
    # Ignore process that are already dead
    kill $procs 2> /dev/null
}
trap 'finish' 2

custom

echo 'Press <Ctrl+C> to kill...'
wait

এটি চলছে

$ ./program_spawner.sh 
Press <Ctrl+C> to kill...
^CKill:  9835
9840
9844
9850
$ 

@ ম্যাক্সিম সম্পাদনা করুন , আপনার পরামর্শটি সবেমাত্র দেখেছেন, এটি এটিকে আরও টন সহজ করে তুলেছে! ধন্যবাদ!

আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.