यदि कोई कमांड विफल हो जाए तो कैसे बाहर निकलें?


222

मैं शेल-स्क्रिप्टिंग में एक नॉब हूं। यदि कोई आदेश विफल होता है तो मैं एक संदेश प्रिंट करना और अपनी स्क्रिप्ट से बाहर निकलना चाहता हूं। मैंने कोशिश की:

my_command && (echo 'my_command failed; exit)

लेकिन यह काम नहीं करता है। यह स्क्रिप्ट में इस लाइन के बाद निर्देशों को निष्पादित करता रहता है। मैं उबंटू और बैश का उपयोग कर रहा हूं।


5
क्या आपने अशुद्ध उद्धरण को सिंटैक्स त्रुटि के रूप में बताया है जो विफल / निकास का कारण होगा? यदि नहीं, तो आपको अपने उदाहरण में उद्धरण बंद करना चाहिए।
होब्स

जवाबों:


406

प्रयत्न:

my_command || { echo 'my_command failed' ; exit 1; }

चार बदलाव:

  • बदलें &&करने के लिए||
  • के { }स्थान पर उपयोग करें( )
  • के ;बाद परिचय exitऔर
  • {पहले और बाद के रिक्त स्थान}

चूंकि आप संदेश को प्रिंट करना चाहते हैं और केवल तभी बाहर निकलते हैं जब कमांड विफल हो जाता है (गैर-शून्य मान के साथ बाहर निकलता है) आपको एक की आवश्यकता ||नहीं है &&

cmd1 && cmd2

cmd2जब cmd1सफल होगा (निकास मान 0) चलेगा । जहाँ तक

cmd1 || cmd2

विफल cmd2होने पर चलेगा cmd1(निकास मान शून्य नहीं)।

उपयोग करने ( )से उनके अंदर का कमांड उप-शेल में चलता है और exitवहां से कॉल करने से आप सब-शेल से बाहर निकल सकते हैं और आपका मूल शेल नहीं, इसलिए निष्पादन आपके मूल शेल में जारी रहता है।

इस उपयोग को दूर करने के लिए { }

अंतिम दो परिवर्तनों को बैश द्वारा आवश्यक है।


4
यह "उलटा" प्रतीत होता है। यदि कोई फ़ंक्शन "सफल होता है" तो यह 0 पर वापस आ जाता है और यदि यह "विफल" हो जाता है, तो यह गैर-शून्य देता है इसलिए && का मूल्यांकन तब किया जा सकता है जब पहली छमाही में गैर-शून्य वापस आ जाता है। इसका मतलब यह नहीं है कि उपरोक्त उत्तर गलत है - नहीं यह सही नहीं है। && और || स्क्रिप्ट में सफलता के आधार पर काम करते हैं, न कि रिटर्न वैल्यू पर।
कैशबैक

7
यह उलटा लगता है, लेकिन इसे पढ़िए और यह समझ में आता है: "इस कमांड को (सफलतापूर्वक) करें" या "इस त्रुटि को प्रिंट करें और बाहर निकलें"
simpleuser

2
इसके पीछे तर्क यह है कि भाषा शॉर्ट-सर्किट मूल्यांकन (SCE) का उपयोग करती है। SCE के साथ, f अभिव्यक्ति "p OR q" के रूप की है, और p का मूल्यांकन सत्य है, फिर q को देखने का कोई कारण नहीं है। यदि अभिव्यक्ति "पी एंड क्यू" के रूप की है, और पी का मूल्यांकन गलत होने के लिए किया जाता है, तो क्यू को देखने का कोई कारण नहीं है। इसका कारण दो गुना है: 1) इसका तेज, स्पष्ट कारणों के लिए और 2) यह कुछ प्रकार की त्रुटियों से बचा जाता है (उदाहरण के लिए: "यदि x! = 0 और 10 / x> 5" दुर्घटनाग्रस्त हो जाएगा यदि कोई SCE नहीं है! )। कमांड लाइन में इस तरह उपयोग करने की क्षमता एक खुश साइड-इफेक्ट है।
user2635263

2
मैं STDERR को { (>&2 echo 'my_command failed') ; exit 1; }
गूँजने

127

अन्य जवाबों ने प्रत्यक्ष प्रश्न को अच्छी तरह से कवर किया है, लेकिन आप का उपयोग करने में भी रुचि हो सकती है set -e। इसके साथ, कोई भी आदेश जो विफल रहता है ( ifपरीक्षणों जैसे विशिष्ट संदर्भों के बाहर ) स्क्रिप्ट को समाप्त करने का कारण होगा। कुछ स्क्रिप्ट के लिए, यह बहुत उपयोगी है।


3
दुर्भाग्य से, यह बहुत खतरनाक है - set -eजब यह काम करता है और कब नहीं करता है, इसके बारे में नियमों का एक लंबा और रहस्यमय सेट है। (यदि कोई चलाता है if yourfunction; then ..., तो set -eकभी भी उसके अंदर आग नहीं जाएगी और न ही yourfunctionवह कॉल करेगा, क्योंकि उस कोड को "चेक किया गया" माना जाता है। BashFAQ # 105 के अभ्यास खंड को देखें , इस और अन्य नुकसानों पर चर्चा करते हुए (जिनमें से कुछ केवल विशिष्ट शेल संस्करणों पर लागू होते हैं, इसलिए आपको अपनी स्क्रिप्ट चलाने के लिए उपयोग की जाने वाली प्रत्येक रिलीज़ के विरुद्ध परीक्षण करना सुनिश्चित करना होगा)।
चार्ल्स डफी

67

ध्यान दें, प्रत्येक कमांड की निकास स्थिति को शेल चर $ में संग्रहीत किया जाता है?, जिसे आप कमांड चलाने के तुरंत बाद जांच सकते हैं। एक गैर-शून्य स्थिति विफलता को इंगित करती है:

my_command
if [ $? -eq 0 ]
then
    echo "it worked"
else
    echo "it failed"
fi

10
इसे केवल my_command द्वारा प्रतिस्थापित किया जा सकता है, यहां परीक्षण कमांड का उपयोग करने की कोई आवश्यकता नहीं है।
बार्ट सास

5
+1 क्योंकि मुझे लगता है कि आपको इस विकल्प को सूचीबद्ध करने के लिए दंडित नहीं किया जाना चाहिए - यह मेज पर होना चाहिए - हालांकि यह थोड़े बदसूरत है और मेरे अनुभव में परीक्षण की प्रकृति को ध्यान दिए बिना बीच में एक और कमांड चलाना बहुत आसान है (शायद मैं ' m सिर्फ बेवकूफ)।
टोनी डेलरो सिप

1
@BartSas यदि कमांड लंबी है, तो इसे अपनी लाइन पर रखना बेहतर है। यह स्क्रिप्ट को अधिक पठनीय बनाता है।
माइकल

@ मायकिल, नहीं तो यह लाइनों पर निर्भरता पैदा करता है, जहाँ आपको यह जानना आवश्यक है कि लाइन A पर क्या हुआ है इससे पहले कि आप लाइन B को समझ सकें (या इससे भी बदतर, यह जानने की आवश्यकता है कि लाइन B में क्या होने वाला है इससे पहले कि आप जानते हैं कि यह कुछ जोड़ना सुरक्षित है लाइन ए के अंत के बाद नया)। मैंने देखा है कई बार किसी को जोड़ा एक echo "Just finished step A", जानते हुए भी कि कि नहीं echoअधिलेखित कर दिया $?है कि जा रहा था बाद में जांच की जानी।
चार्ल्स डफी

67

यदि आप अपनी स्क्रिप्ट में सभी आदेशों के लिए वह व्यवहार चाहते हैं, तो बस जोड़ें

  set -e 
  set -o pipefail

स्क्रिप्ट की शुरुआत में। विकल्प की यह जोड़ी बैश दुभाषिया को बाहर निकलने के लिए कहती है जब भी कोई कमांड गैर-शून्य निकास कोड के साथ वापस आती है।

यह आपको बाहर निकलने के संदेश को प्रिंट करने की अनुमति नहीं देता है, हालांकि।


8
आप trapbash अंतर्निहित कमांड का उपयोग करके बाहर निकलने पर कमांड चला सकते हैं ।
गाविन स्मिथ

यह XY प्रश्न का उत्तर है।
jwg

5
यह समझाने के लिए दिलचस्प हो सकता है कि जोड़े के बजाय स्वतंत्र रूप से कमांड क्या करते हैं। विशेष रूप से set -o pipefailवांछित व्यवहार नहीं हो सकता है। फिर भी इसे इंगित करने के लिए धन्यवाद!
एंटोनी पिंसर्ड

3
set -eसभी विश्वसनीय, सुसंगत या पूर्वानुमेय नहीं है! खुद को समझाने के लिए, BashFAQ # 105 के अभ्यास खंड की समीक्षा करें , या तालिका में विभिन्न गोले के व्यवहारों की तुलना- inmm.de/~mascheck/various/set-e
चार्ल्स डफी

14

मैंने निम्नलिखित मुहावरे को हैक किया है:

echo "Generating from IDL..."
idlj -fclient -td java/src echo.idl
if [ $? -ne 0 ]; then { echo "Failed, aborting." ; exit 1; } fi

echo "Compiling classes..."
javac *java
if [ $? -ne 0 ]; then { echo "Failed, aborting." ; exit 1; } fi

echo "Done."

प्रत्येक कमांड को एक सूचनात्मक प्रतिध्वनि के साथ तरजीह दें, और उसी
if [ $? -ne 0 ];...पंक्ति के साथ प्रत्येक कमांड का पालन करें । (बेशक, आप चाहें तो उस त्रुटि संदेश को संपादित कर सकते हैं।)


इसे एक फ़ंक्शन के रूप में परिभाषित किया जा सकता है, इस प्रकार इसका पुनः उपयोग किया जा सकता है।
एरिक वांग

1
'अगर [$? —ने ०]; तब ... Fi 'लिखने का एक जटिल तरीका है' ||
केविन क्लाइन

if ! javac *.java; then ...- आखिर परेशान क्यों $??
चार्ल्स डफी

चार्ल्स - क्योंकि मैं :) सबसे अच्छे रूप में एक औसत दर्जे का बैश scripter हूँ
अनुदान बिर्चमिएर

10

बशर्ते my_commandकैनोनिकली डिज़ाइन किया गया हो, यानी 0 रिटर्न जब सफल हो जाता है, तो &&आप जो चाहते हैं उसके ठीक विपरीत होता है। आप चाहते हैं ||

यह भी ध्यान दें कि (मेरे लिए यह सही नहीं है, लेकिन मैं कोशिश नहीं कर सकता कि मैं कहाँ हूँ। मुझे बताओ।

my_command || {
    echo 'my_command failed' ;
    exit 1; 
}

IIRC, आपको {} के अंदर प्रत्येक पंक्तियों के बाद अर्धविराम की आवश्यकता है
एलेक्स हावान्स्की

9
@ एलेक्स: यदि वे अलग लाइन पर नहीं हैं।
अगली सूचना तक रोक दिया गया।

5

यदि आप निकास त्रुटि स्थिति को संरक्षित करना चाहते हैं, और प्रति पंक्ति एक कमांड के साथ एक पठनीय फ़ाइल का उपयोग कर सकते हैं:

my_command1 || exit $?
my_command2 || exit $?

हालांकि, यह किसी भी अतिरिक्त त्रुटि संदेश को प्रिंट नहीं करेगा। लेकिन कुछ मामलों में, त्रुटि वैसे ही विफल कमांड द्वारा मुद्रित की जाएगी।


1
इसके होने का कोई कारण नहीं है exit $?; बस इसका डिफ़ॉल्ट मान के रूप में exitउपयोग करता है $?
चार्ल्स डफी

@CharlesDuffy को नहीं पता था। बहुत बढ़िया, तो यह और भी सरल है!
एलेक्सपिरिन

3

trapखोल builtin पकड़ने संकेत, और अन्य उपयोगी स्थिति में विफल आदेश निष्पादन (यानी, एक गैर शून्य वापसी की स्थिति) सहित अनुमति देता है। इसलिए यदि आप स्पष्ट रूप से हर एक कमांड के रिटर्न स्टेटस का परीक्षण नहीं करना चाहते हैं trap "your shell code" ERRऔर शेल कोड किसी भी समय एक गैर-शून्य स्थिति देता है तो निष्पादित किया जाएगा। उदाहरण के लिए:

trap "echo script failed; exit 1" ERR

ध्यान दें कि विफल आदेशों को पकड़ने के अन्य मामलों की तरह, पाइपलाइनों को विशेष उपचार की आवश्यकता होती है; ऊपर नहीं पकड़ा जाएगा false | true

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