पृष्ठभूमि में चल रही एक शेल स्क्रिप्ट को मारना


12

मैंने inotifyt-tools के inotifywait उपयोगिता का उपयोग करके एक निर्देशिका की निगरानी करने के लिए एक शेल स्क्रिप्ट लिखी है। मैं चाहता हूं कि वह स्क्रिप्ट बैकग्राउंड में लगातार चले, लेकिन मैं चाहकर भी इसे रोक नहीं पा रहा हूं।

इसे लगातार चलाने के लिए, मैंने इस्तेमाल किया while true; इस तरह:

while true;
do #a set of commands that use the inotifywait utility
end

मैंने इसे एक फ़ाइल में सहेजा है /binऔर इसे निष्पादन योग्य बनाया है। इसे पृष्ठभूमि में चलाने के लिए, मैंने nohup <script-name> &टर्मिनल का उपयोग किया और बंद कर दिया।

मुझे नहीं पता कि मैं इस स्क्रिप्ट को कैसे रोकूं। मैंने यहां के जवाब और यहां बहुत ही बारीकी से संबंधित प्रश्न को देखा है

अद्यतन 1: नीचे दिए गए @InfectedRoot के उत्तर के आधार पर, मैं निम्नलिखित रणनीति का उपयोग करके अपनी समस्या को हल करने में सक्षम हूं। पहला उपयोग

ps -aux | grep script_name

और sudo kill -9 <pid>प्रक्रियाओं को मारने के लिए उपयोग करें। मुझे फिर आईडी के लिए फिर से pgrep inotifywaitउपयोग sudo kill -9 <pid>करना पड़ा ।

यह काम करता है लेकिन मुझे लगता है कि यह एक गन्दा दृष्टिकोण है, मैं एक बेहतर उत्तर की तलाश में हूँ।

अद्यतन 2: उत्तर में 2 प्रक्रियाओं की हत्या शामिल है । यह महत्वपूर्ण है क्योंकि स्क्रिप्ट को कमांड लाइन पर चलाने से 2 प्रक्रियाएं शुरू होती हैं, 1 स्क्रिप्ट खुद और 2, इनोटिफाई प्रक्रिया



2
केवल -9विकल्प killका उपयोग करके killउसे निकालने से गंदगी बाहर हो जाएगी।
श्री

1
वाहवाही। कुछ '$ $' को फिर से दंड कैश बॉक्स में प्राप्त करने के लिए, मैं इस बात पर जोर देना चाहूंगा कि -9विकल्प कुल मिलाकर killयहां होगा। : पी
वाक्य रचना

पूर्णता के लिए: दोनों प्रक्रियाओं को एक साथ मारने के लिए एक स्वच्छ दृष्टिकोण है: अलग-अलग प्रक्रियाओं को मारने के बजाय आप स्क्रिप्ट के प्रक्रिया समूह को एक बार में मारने के लिए मार सकते हैं। Pgid खोल स्क्रिप्ट मुख्य प्रक्रिया की पीआईडी के रूप में और करने के लिए एक ही है killयह आप एक ऋण के साथ pgid उपसर्ग: kill -- -<pgid>, kill -9 -<pgid>, आदि
cg909

जवाबों:


6

killallआदेशों को सुधारने, उपयोग करने और उन्हें संयोजित करने के लिए:

ps -aux | grep script_name
killall script_name inotifywait

या सब कुछ एक पंक्ति में करें:

killall `ps -aux | grep script_name | grep -v grep | awk '{ print $1 }'` && killall inotifywait

आपका उपरोक्त समाधान काम करता है लेकिन एक पंक्ति कमांड नहीं। कृपया आप इसकी जाँच कर सकते हैं। मुझे एक त्रुटि मिलती है: कोई प्रक्रिया नहीं
light94

@ light94 का Error: no processमतलब सिर्फ इतना होना चाहिए कि आप इसे पहले ही मार चुके हैं। आप इसे VLC और Geany की तरह दो अन्य प्रोग्राम खोलकर और इसके बजाय उनके साथ प्रयास करके इसका परीक्षण कर सकते हैं ।
cremefraiche

अरे @cremefraiche, जैसा कि ईयरलर ने कहा है कि आपका कोड काम करता है .. लेकिन मैं वैकल्पिक समाधानों की खोज कर रहा हूं और सबसे आम समाधान मैं देख रहा हूं कि किल <pid> का उपयोग करें। चूंकि, मेरी स्क्रिप्ट उस तरीके से समाप्त नहीं होती है, अगर मेरा कोड अनुचित है तो मैं थोड़ा चिंतित हूं? क्या आप कृपया मेरा मार्गदर्शन कर सकते हैं?
light94

आप में grep -v grepबदलकर बचा सकते हैं । grep script_namegrep -e "[s]cript_name"
नौचमाल

3

पृष्ठभूमि नौकरियों का उपयोग कर सूची

# jobs

फिर नौकरी की पूर्व संख्या चुनें और चलाएं

उदाहरण

# fg 1 

यहाँ छवि विवरण दर्ज करें

अग्रभूमि में लाएगा।

फिर CTRL + C का उपयोग करके इसे मारें या स्क्रिप्ट का पीआईडी ​​खोजने के लिए आसान तरीका

ps -aux | grep script_name

यहाँ छवि विवरण दर्ज करें

फिर पीड़ का उपयोग करके मारना

sudo kill -9 pid_number_here

2
पहला विकल्प मेरे मामले के लिए मान्य नहीं है क्योंकि मैं स्क्रिप्ट को बताने के बाद शेल को बंद कर देता हूं और मुझे लगता है कि जॉब कमांड केवल उसी शेल के लिए काम करता है। इसके अलावा, मैंने दूसरे विकल्प की कोशिश की और यह प्रक्रिया को मारता है लेकिन जब मैं potrep inotifywait करता हूं, तब भी मैं इसे एक प्रक्रिया के रूप में देख सकता हूं।
light94

जॉब्स शेल को बंद करने पर भी आपको जॉब की लिस्ट देंगे। फिर भी यह प्रक्रिया पूरी हो जाएगी।
बेबिन लोन्स्टन

2
मैंने इसे आजमाया लेकिन ऐसा नहीं हुआ।
light94

@ light94 आप सही कह रहे हैं। यहां अक्सर ऐसा हुआ कि jobsकमांड वास्तव में केवल शेल में चलने वाली नौकरियों को प्रदर्शित करता है । एक बार जब मैंने एक निश्चित टर्मिनल विंडो को बंद कर दिया, तो उन्हें एक्सेस करने का एकमात्र तरीका था ps(उस के लिए ऊपर देखें)। तो यह सुनिश्चित करने के लिए है कि आप इसे नहीं बना रहे हैं।
वाक्यविन्यास

2

आप प्रक्रिया नाम / पीआईडी पाने के लिए ps+ का उपयोग कर सकते हैं grepया कर सकते हैं ; बाद में प्रक्रिया नाम को मारने के लिए / pid को मारने के लिए उपयोग करें। सभी का पालन करना चाहिए।pgrepkillallpkillkill

killall $(ps aux | grep script_name | grep -v grep | awk '{ print $1 }') && killall inotifywait
(ps -ef | grep script_name | grep -v grep | awk '{ print $1 }' | xargs killall) && killall inotifywait
(ps -ef | grep script_name | grep -v grep | awk '{ print $2 }' | xargs kill) && killall inotifywait
(pgrep -x script_name | xargs kill) && pkill -x inotifywait
pkill -x script_name && pkill -x inotifywait

सबसे महत्वपूर्ण बात यह है कि आपको यह सुनिश्चित करना चाहिए कि आप केवल सटीक प्रक्रिया (तों) को मारें जिसे आप मारने की उम्मीद कर रहे हैं।

pkill/ सटीक नाम के बजाय pgrepएक पैटर्न से मेल खाता है , इसलिए अधिक खतरनाक है; यहां सटीक नाम से मिलान करने के लिए जोड़ा गया है।-x

इसके अलावा, उपयोग करते समय pgrep/ pkillआपको आवश्यकता हो सकती है

  • -fपूर्ण कमांड लाइन से मेल खाता है (जैसे ps auxकरता है)
  • -a प्रक्रिया का नाम भी मुद्रित करें।

उपरोक्त निष्पादित करने के बाद, मुझे प्रत्येक में एक उपयोग त्रुटि मिलती है। मैं स्क्रिप्टिंग की जगह पेस्ट कर रहा हूं। मुझे आउटपुट के रूप में मार के लिए उपयोग मिलता है
light94

Script_name चल रहा है? यह मेरे लिए काम करता है (डेबियन जेसी)
होंगक्सु चेन

हाँ, यह चल रहा है। और आपका समाधान लगभग @cremefraiche समाधान के समान है, इसलिए मैंने उम्मीद की थी कि यह उसी तरह काम करेगा: /
light94

हां, मैं ऐसा करने के संभावित तरीकों का संक्षेप में वर्णन कर रहा था, विशेष रूप से जोड़ना pgrep/ pkill। अगर वह अभी भी गलत हो जाता है तो आप pgrepबिना -x की कोशिश कर सकते हैं । मूल रूप से मुझे नहीं लगता कि एक लाइन कमांड के भीतर इस प्रक्रिया को मारना अच्छा है, बिना यह जांचे कि क्या अन्य प्रक्रियाएं मेल खाती हैं।
होंगक्सु चेन

1

जैसा कि आप शायद बता सकते हैं कि ऐसा करने के बहुत सारे तरीके हैं।

अपने "UPDATE # 2" के बारे में - आम तौर पर बोलना, माता-पिता के बच्चे के पदानुक्रम में किसी भी प्रक्रिया को समाप्त करना आम तौर पर सभी संबंधित प्रक्रियाओं को समाप्त कर देगा। लेकिन इसके कई अपवाद भी हैं। आदर्श रूप से, आप एक प्रक्रिया के पेड़ में अंतिम 'बच्चे' को समाप्त करना चाहते हैं, फिर इस बच्चे के माता-पिता को बाहर निकलना चाहिए अगर उनके पास चलाने के लिए कोई अन्य कार्य नहीं है। लेकिन अगर आप किसी माता-पिता को मारते हैं, तो संकेत को बच्चों को छोड़ दिया जाना चाहिए जब माता-पिता की मृत्यु हो जाती है और बच्चों को भी बाहर निकलना चाहिए - लेकिन ऐसे मामले हैं जहां बच्चे प्रक्रिया संकेत (जाल या इसी तरह के तंत्र के माध्यम से) को अनदेखा कर सकते हैं और जारी रख सकते हैं चलाने के लिए एक 'इनिट' प्रक्रिया (या इसी तरह) द्वारा विरासत में मिला होगा। लेकिन प्रक्रिया व्यवहार का यह विषय जटिल हो सकता है और मैं इसे वहां छोड़ दूँगा ...

एक विधि मुझे पसंद है अगर मैं एक नियंत्रण स्क्रिप्ट का उपयोग नहीं करना चाहता (अगला वर्णित है) प्रक्रिया शुरू करने और प्रबंधित करने के लिए 'स्क्रीन' उपयोगिता का उपयोग करना है। 'स्क्रीन' कमांड सुविधाओं से भरपूर है और इसमें कुछ समय लग सकता है। मैं आपको पूर्ण विवरण के लिए 'स्क्रीन' मैन पेज पढ़ने के लिए प्रोत्साहित करता हूँ। पृष्ठभूमि में एक प्रक्रिया शुरू करने के लिए एक त्वरित उदाहरण कमांड होगा:

स्क्रीन -d -m / path / to / program

यह 'स्क्रीन' सत्र के अंदर "/ पथ / टू / प्रोग्राम" शुरू करेगा।

आप कमांड के साथ अपना रनिंग सेशन देख सकते हैं:

स्क्रीन-हील्स

और किसी भी समय आप कमांड के साथ अपने रनिंग प्रोग्राम को फिर से कनेक्ट कर सकते हैं:

स्क्रीन -r

और फिर इसे ^ C या जो भी हो, समाप्त करें।

अपनी प्रक्रिया में अपनी प्रक्रिया से पुन: कनेक्ट और डिस्कनेक्ट करने में सक्षम होने के अलावा, यह है कि 'स्क्रीन' किसी भी स्टडआउट () को कैप्चर करेगा जो आपके प्रोग्राम का उत्पादन कर सकता है।


लेकिन इन मामलों में मेरी व्यक्तिगत प्राथमिकता एक नियंत्रण कार्यक्रम है जो एक प्रक्रिया की शुरुआत और ठहराव का प्रबंधन करता है। यह कुछ हद तक जटिल हो सकता है और कुछ यकीनन जटिल स्क्रिप्टिंग की आवश्यकता होती है। और किसी भी स्क्रिप्ट की तरह, इसे करने के दर्जनों अच्छे तरीके हैं। मैंने एप्लिकेशन को प्रारंभ करने और रोकने के लिए नियमित रूप से उपयोग की जाने वाली विधि का एक बैश उदाहरण शामिल किया है। यदि आपका कार्य सरल है, तो आप इसे सीधे नियंत्रण स्क्रिप्ट में सम्मिलित कर सकते हैं - या आपके पास यह नियंत्रण स्क्रिप्ट किसी अन्य बाहरी प्रोग्राम को कॉल कर सकती है। ध्यान दें कि यह उदाहरण प्रक्रिया के प्रबंधन के संदर्भ में व्यापक नहीं है। मैंने इस तरह के परिदृश्यों की संभावना को छोड़ दिया है: यह सुनिश्चित करना कि जब आप "स्टार्ट" विकल्प का उपयोग करते हैं तो स्क्रिप्ट पहले से ही नहीं चल रही है, यह पुष्टि करते हुए कि चल रही पीआईडी ​​वास्तव में आपके द्वारा शुरू की गई प्रक्रिया है (जैसे आपकी स्क्रिप्ट hasn ' t की मृत्यु हो गई और उसी PID का उपयोग करके एक और प्रक्रिया शुरू की गई), और यह पुष्टि करते हुए कि स्क्रिप्ट वास्तव में पहले 'मार' अनुरोध पर प्रतिक्रिया (बाहर) हुई। इन सभी जांचों को करना जटिल हो सकता है और मैं उदाहरण को बहुत लंबा और जटिल नहीं बनाना चाहता। आप अपने शेल स्क्रिप्टिंग का अभ्यास करने के लिए उदाहरण को संशोधित करना चाह सकते हैं।

निम्नलिखित प्रोग्राम को "प्रोग्रामक्टल" नामक फ़ाइल में सहेजें, इसे कमांड के साथ निष्पादन योग्य बनाएं:

chmod 755 प्रोग्रामैक्टल

फिर फ़ाइल को संपादित करें और "myscript" से शुरू होने वाले केस-सेक्शन में अपना कोड / स्क्रिप्ट जोड़ें।

एक बार सब कुछ जगह में होने के बाद, "प्रोग्रामक्टल" वर्तमान निर्देशिका में है, तो आप अपने कार्यक्रम को इसके साथ शुरू कर सकते हैं:

./programctl प्रारंभ

और इसके साथ बंद करो:

./programctl स्टॉप

चीयर्स।

#!/bin/bash
# Description:  A wrapper script used to stop/start another script.

#--------------------------------------
# Define Global Environment Settings:
#--------------------------------------

# Name and location of a persistent PID file

PIDFILE="/tmp/tmpfile-$LOGNAME.txt"

#--------------------------------------
# Check command line option and run...
# Note that "myscript" should not
# provided by the user.
#--------------------------------------

case $1
in
    myscript)
        # This is where your script would go.
        # If this is a routine 'bash' shell script, you can enter
        # the script below as illustrated in the example.  
        # Or you could simply provide the path and parameters
        # to another script such as /dir/name/command -options

        # Example of an embedded script:

        while true
        do
            # do something over and over...
            sleep 1
        done

        # Example of an external script:

        /usr/local/bin/longrun -x
    ;;

    start)
        # Start your script in the background.
        # (Note that this is a recursive call to the wrapper
        #  itself that effectively runs your script located above.)
        $0 myscript &

        # Save the backgound job process number into a file.
        jobs -p > $PIDFILE

        # Disconnect the job from this shell.
        # (Note that 'disown' command is only in the 'bash' shell.)
        disown %1

        # Print a message indicating the script has been started
        echo "Script has been started..."
    ;;

    stop)
        # Read the process number into the variable called PID
        read PID < $PIDFILE

        # Remove the PIDFILE
        rm -f $PIDFILE

        # Send a 'terminate' signal to process
        kill $PID

        # Print a message indicating the script has been stopped
        echo "Script has been stopped..."
    ;;

    *)
        # Print a "usage" message in case no arguments are supplied
        echo "Usage: $0 start | stop"
    ;;
esac

मैंने आपके द्वारा सुझाई गई "स्क्रीन" विधि की कोशिश की और यह खूबसूरती से काम करती है। मैं अभी दूसरी विधि की कोशिश नहीं कर रहा हूं। जवाब के लिए धन्यवाद।
light94
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.