वहाँ किसी भी कमांड त्रुटि पर मेरे bash स्क्रिप्ट ऑटो चलाने में एक समारोह है?


12

मैं एक शेल स्क्रिप्ट लिख रहा हूं जिसे कमांड का एक गुच्छा बनाने की जरूरत है और हर कमांड हर पिछले कमांड पर निर्भर करता है। यदि कोई भी कमांड विफल हो जाती है, तो पूरी स्क्रिप्ट विफल हो जाती है और मैं एक निकास फ़ंक्शन कहता हूं। मैं प्रत्येक कमांड के एग्जिट कोड की जांच कर सकता था लेकिन मैं सोच रहा था कि क्या कोई मोड है जो मुझे सक्षम कर सकता है या स्वचालित रूप से ऐसा करने के लिए बैश कर सकता है।

उदाहरण के लिए, इन आदेशों को लें:

cd foo || myfunc
rm a || myfunc
cd bar || myfunc
rm b || myfunc


क्या कोई ऐसा तरीका है जहाँ मैं किसी तरह इन कमांड्स को निष्पादित करने से पहले शेल को संकेत दे सकता हूँ कि यह myfunc को कॉल करे यदि उनमें से कोई भी विफल हो, ताकि इसके बजाय मैं कुछ क्लीनर लिख सकूं जैसे:

cd foo
rm a
cd bar
rm b

जवाबों:


13

यदि कोई कमांड शून्य से अधिक की स्थिति देता है और बाहर निकलने पर आपके फ़ंक्शन को निष्पादित करता है, तो आप अपनी स्क्रिप्ट को छोड़ने के लिए bash trap ERR का उपयोग कर सकते हैं ।

कुछ इस तरह:

myfunc() {
  echo 'Error raised. Exiting!'
}

trap 'myfunc' ERR

# file does not exist, causing error
ls asd
echo 123

ध्यान दें कि बैश ट्रैप ERR निहित है set -o errexitया set -eपोसिक्स नहीं है।

और ERRजाल निष्पादित नहीं है, तो विफल रहा है आदेश तुरंत निम्न आदेश सूची का हिस्सा है untilया whileकीवर्ड, निम्नलिखित परीक्षण का हिस्सा ifया elifआरक्षित शब्द, एक कमांड के हिस्से में मार डाला &&या ||सूची, या यदि आदेश की वापसी स्थिति का उपयोग किया जा रहा है उल्टे !


1

स्वीकृत उत्तर पर ए (शायद) सरल भिन्नता:

  1. set -e एक सूची के निष्पादन को निरस्त करने के लिए एक आदेश की विफलता के कारण का उपयोग करें ।
  2. बस अपने आदेशों को सूचीबद्ध करें।
  3. अपनी त्रुटि से निपटने के आदेश को निष्पादित करने के लिए एक if- then- elseकथन का उपयोग करें । यह आखिरी टुकड़ा थोड़ा मुश्किल है। घड़ी:
सेट
अगर
    cmd 1                         # उदा, सीडी foo
     cmd 2                         # उदा, rm एक
     cmd 3                         # उदा, सीडी बार
     cmd 4                         # उदा, rm b
फिर
    सेट + ई
    सफलता पर करने के लिए आदेश (यदि कोई हो)
अन्य
    सेट + ई
    myfunc
    अन्य आदेश विफलता पर (यदि कोई हो) 
फाई करने के लिए

मुश्किल बात यह है कि आप अपने आदेश रखा है में भागif की if- then- else, नहीं thenभाग या elseहिस्सा है। स्मरण करो कि कथन का वाक्य विन्यासif है

यदि  सूची ; फिर  सूची ; [एलिफ  सूची ; फिर  सूची ; ] ... [और  सूची ; ] फाई 
   ↑↑↑↑
set -eखोल है कि, अगर बताता है ( ) विफल रहता है, उस पर नहीं जाना चाहिए और निष्पादित ( ), और इतने पर लाइन नीचे। यदि यह शेल स्क्रिप्ट के सबसे बाहरी स्तर पर एक कमांड के साथ हुआ, तो शेल बाहर निकल जाएगा। हालांकि, बाद से · · · एक (मिश्रित) सूची एक निम्नलिखित है , उन चार आदेशों में से किसी की विफलता बस पूरी सूची विफल का कारण बनता है - जिसकी वजह से खंड निष्पादित किया जाना है। यदि सभी चार कमांड सफल होते हैं, तो क्लॉज निष्पादित किया जाता है।cmd1cd foocmd2rm acmd1cmd2cmd3cmd4ifelsethen

या तो मामले में, आपको जो पहली चीज करनी चाहिए, वह eविकल्प को अक्षम (चालू) करना है set +e। अन्यथा, यदि कोई आदेश myfuncविफल रहता है , तो स्क्रिप्ट पानी से बाहर निकल सकती है।

set -eहै निर्दिष्ट और POSIX विनिर्देशन में वर्णित


0

अपना शब्द लिया " प्रत्येक कमांड प्रत्येक पिछली कमांड पर निर्भर करता है। यदि कोई भी कमांड विफल हो जाती है तो पूरी स्क्रिप्ट विफल हो जानी चाहिए " सचमुच, मुझे लगता है कि आपको त्रुटियों के इलाज के लिए किसी विशेष फ़ंक्शन की आवश्यकता नहीं है।

आपको बस &&ऑपरेटर और ||ऑपरेटर के साथ अपने कमांड को चेन करना है , जो आपने लिखा था।

उदाहरण के लिए यह श्रृंखला टूट जाएगी और "कुछ गलत हो गया" को प्रिंट करेगा यदि पिछली कोई भी कमांड टूट गई (बैश बाएं से दाएं पढ़ता है)

cd foo && rm a && cd bar && rm b || echo "something went wrong"

वास्तविक उदाहरण (मैंने एक वास्तविक डेमो के लिए dir foo, a, dir बार और फ़ाइल b को बनाया):

gv@debian:/home/gv/Desktop/PythonTests$ cd foo && rm a && cd bar && rm bb || echo "something is wrong"
rm: cannot remove 'bb': No such file or directory
something is wrong #mind the error in the last command

gv@debian:/home/gv/Desktop/PythonTests$ cd foo && rm aa && cd bar && rm b || echo "something is wrong"
rm: cannot remove 'aa': No such file or directory
something is wrong #mind the error in second command in the row

और अंत में यदि सभी कमांड सफलतापूर्वक निष्पादित हो गए हैं (कोड 0 से बाहर निकलें), स्क्रिप्ट अभी चलती है:

gv@debian:/home/gv/Desktop/PythonTests$ cd foo && rm a && cd bar && rm b || echo "something is wrong"
gv@debian:/home/gv/Desktop/PythonTests/foo/bar$ 
# mind that the error message is not printed since all commands were successful.

यह याद रखना महत्वपूर्ण है कि && अगली कमांड के उपयोग के साथ निष्पादित किया जाता है यदि पिछली कमांड कोड 0 के साथ बाहर निकलती है जो बैश के लिए सफलता का मतलब है।

यदि कोई कमांड चेन में गलत आती है तो कमांड / स्क्रिप्ट / जो कुछ भी हो || निष्पादित किया जाएगा।

और सिर्फ रिकॉर्ड के लिए, यदि आपको ब्रेक की गई कमांड के आधार पर अलग-अलग कार्य करने की आवश्यकता है, तो आप इसे क्लासिक स्क्रिप्ट के साथ भी कर सकते हैं, $?जिसके मान की मॉनिटरिंग पिछले कमांड के निकास कोड की रिपोर्ट करती है (यदि कमांड सफलतापूर्वक निष्पादित हो जाती है तो शून्य हो जाता है) या अन्य सकारात्मक संख्या अगर कमांड विफल हुआ)

उदाहरण:

for comm in {"cd foo","rm a","cd bbar","rm b"};do  #mind the error in third command
eval $comm
    if [[ $? -ne 0 ]];then 
        echo "something is wrong in command $comm"
        break
    else 
    echo "command $comm executed succesful"
    fi
done

आउटपुट:

command cd foo executed succesfull
command rm a executed succesfull
bash: cd: bbar: No such file or directory
something is wrong in command cd bbar

युक्ति: आप "bash: cd: bbar: No no file ..." संदेश को लागू करके दबा सकते हैं eval $comm 2>/dev/null

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.