2008-09-18 10 views
316

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

+2

मैं यह सोचते हैं उत्तर आप बैश का उपयोग कर रहे हैं, लेकिन अगर यह एक बहुत ही अलग खोल है आप अपनी पोस्ट में निर्दिष्ट कर सकते हैं? –

उत्तर

402

प्रत्येक आदेश के बाद, बाहर निकलने के कोड हो सकता है $? वैरिएबल में मिला है ताकि आपके पास कुछ ऐसा हो:

ls -al file.ext 
rc=$?; if [[ $rc != 0 ]]; then exit $rc; fi 

आप के बाद से $? केवल आप पाइप में अंतिम तत्व की वापसी कोड देता है तो, कोड में पाइप्ड आदेशों की सावधान रहना चाहिए:

ls -al file.ext | sed 's/^/xx: /" 

त्रुटि कोड नहीं होगा अगर फाइल नहीं करता है ' टी मौजूद है (क्योंकि sed पाइपलाइन का हिस्सा वास्तव में काम करता है, 0 लौटा रहा है)।

bash खोल वास्तव में एक सरणी प्रदान करता है जो उस मामले में सहायता कर सकता है, जो कि PIPESTATUS है।

pax> false | true ; echo ${PIPESTATUS[0]} 
1 

ध्यान दें कि यह आप false आदेश, नहीं पूरे पाइप लाइन का परिणाम हो रही है: यह सरणी पाइपलाइन घटकों से प्रत्येक के लिए एक तत्व है, कि तुम ${PIPESTATUS[0]} की तरह अलग-अलग उपयोग कर सकते हैं नहीं है। तुम भी कार्रवाई करने के लिए पूरी सूची प्राप्त कर सकते हैं आप मनचाहे ढंग से:

true | true | false | true | false 
rcs=${PIPESTATUS[*]}; rc=0; for i in ${rcs}; do rc=$(($i > $rc ? $i : $rc)); done 
echo $rc 

यह माध्यम से चला जाता:

pax> false | true | false; echo ${PIPESTATUS[*]} 
1 0 1 

आप, आप की तरह कुछ इस्तेमाल कर सकते हैं एक पाइप लाइन से सबसे बड़ी त्रुटि कोड प्राप्त करना चाहता है तो बदले में PIPESTATUS तत्वों में से प्रत्येक, इसे rc में संग्रहीत करता है यदि यह पिछले rc मान से अधिक था।

+37

पोर्टेबल कोड की केवल एक पंक्ति में वही सुविधा: 'ls -al file.ext || $ से बाहर निकलें? '([[]] पोर्टेबल नहीं है) – MarcH

+18

मार्क, मुझे लगता है कि आप पाएंगे कि' [[]] '' bash' में सुंदर पोर्टेबल है, जो प्रश्न टैग किया गया है :-) आश्चर्यजनक रूप से पर्याप्त है, 'ls'' command.com' में काम नहीं करता है, इसलिए यह पोर्टेबल नहीं है, विशेष रूप से मुझे पता है, लेकिन यह आपके द्वारा प्रस्तुत तर्क का एक ही प्रकार है। – paxdiablo

+35

मुझे पता है कि यह प्राचीन है, लेकिन यह ध्यान दिया जाना चाहिए कि आप पहली कमांड के लिए सरणी 'PIPESTATUS' (यानी, '$ {PIPESTATUS [0]}' के माध्यम से पाइप में आदेशों का निकास कोड प्राप्त कर सकते हैं,' $ { PIPESTATUS [1]} 'दूसरे के लिए, या' $ {PIPESTATUS [*]} 'सभी निकास स्टैटी की एक सूची के लिए। – DevSolar

8

बैश में यह आसान है, बस उन्हें एक साथ बाँध & & साथ:

command1 && command2 && command3 

तुम भी नेस्टेड उपयोग कर सकते हैं निर्माण करता है, तो:

if command1 
    then 
     if command2 
      then 
       do_something 
      else 
       exit 
     fi 
    else 
     exit 
fi 
44

"set -e" शायद ऐसा करने का सबसे आसान तरीका है। बस अपने कार्यक्रम में किसी भी आदेश से पहले इसे डाल दें।

+22

यह क्या करता है? कृपया दस्तावेज़ों के लिए कोई लिंक कृपया? –

+5

@SwaroopCH 'set -e' आपकी स्क्रिप्ट निरस्त हो जाएगी यदि आपकी स्क्रिप्ट में कोई भी आदेश त्रुटि स्थिति से बाहर निकलता है और आपने इस त्रुटि को संभाल नहीं लिया है। – Andrew

195

यदि आप $ के साथ काम करना चाहते हैं, तो आपको $ प्रत्येक के बाद प्रत्येक कमांड के बाद इसे जांचना होगा? प्रत्येक आदेश बाहर निकलने के बाद अद्यतन किया जाता है। इसका अर्थ यह है कि यदि आप पाइपलाइन निष्पादित करते हैं, तो आपको पाइपलाइन में अंतिम प्रक्रिया का एक्ज़िट कोड प्राप्त होगा।

एक और दृष्टिकोण यह करने के लिए है:

set -e 
set -o pipefail 

आप खोल स्क्रिप्ट के शीर्ष पर इस डालें, तो वह पार्टी की तरह दिखता है आप के लिए इस का ख्याल रखना होगा। जैसा कि पिछले पोस्टर ने नोट किया था, "सेट-ए" किसी भी साधारण कमांड पर किसी त्रुटि के साथ बाहर निकलने के लिए बाश का कारण बन जाएगा। "सेट-पाइपफेल" एक पाइपलाइन में किसी भी कमांड पर त्रुटि के साथ बाहर निकलने के लिए बाश का कारण बन जाएगा।

इस समस्या पर थोड़ी अधिक चर्चा के लिए here या here देखें। Here सेट बिल्टिन पर बैश मैनुअल अनुभाग है।

+4

यह वास्तव में शीर्ष उत्तर होना चाहिए: यह 'PIPESTATUS' का उपयोग करना और हर जगह निकास कोडों की जांच करना बहुत आसान है। – candu

+0

'#!/Bin/bash -e' एक शेल स्क्रिप्ट शुरू करने का एकमात्र तरीका है। आप हमेशा 'foo || जैसी चीजों का उपयोग कर सकते हैं handle_error $? 'अगर आपको वास्तव में बाहर निकलने की स्थिति की जांच करने की आवश्यकता है। –

24

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

 
command1 || exit; 
command2 || exit; 

बैश चरम $ में अंतिम आदेश के निकास कोड को भी संग्रहीत करेगा?

17
बैश के लिए

:

# this will trap any errors or commands with non-zero exit status 
# by calling function catch_errors() 
trap catch_errors ERR; 

# 
# ... the rest of the script goes here 
# 

function catch_errors() { 
    # do whatever on errors 
    # 
    # 
    echo "script aborted, because of errors"; 
    exit 0; 
} 
+16

शायद "बाहर निकलें" नहीं होना चाहिए, क्योंकि इससे सफलता का संकेत मिलता है। – nobar

+3

exit_code = $?; गूंज "त्रुटियों के कारण, छोड़ा गया स्क्रिप्ट"; बाहर निकलें $ exit_code – RaSergiy

+1

@ एचएएल 9 001 क्या आपके पास इसका सबूत है? आईबीएम दस्तावेज [अन्यथा कहता है] (http://www.ibm.com/developerworks/aix/library/au-usingtraps/#list4)। –

20

http://cfaj.freeshell.org/shell/cus-faq-2.html#11

  1. मैं cmd1|cmd2

    प्रथम में cmd1 के निकास कोड कैसे मिलता है, ध्यान दें कि cmd1 बाहर निकलें कोड गैर-शून्य हो सकता है और अभी भी त्रुटि नहीं है। यह

    cmd | head -1 
    

    आप cmd1, की एक 141 (या ksh93 साथ 269) से बाहर निकलें स्थिति का निरीक्षण कर सकते हैं में उदाहरण के लिए होता है, लेकिन क्योंकि cmd एक SIGPIPE संकेत द्वारा बाधित किया गया था जब head -1 एक पंक्ति को पढ़ने के बाद समाप्त हो गया।

    एक पाइप लाइन cmd1 | cmd2 | cmd3

    एक के तत्वों में से बाहर निकलने की स्थिति जानने के लिए। zsh के साथ:

    निकास कोड पाइपस्टैटस विशेष सरणी में प्रदान किए जाते हैं। cmd1 बाहर निकलने के कोड, $pipestatus[1] में है $pipestatus[3] में cmd3 बाहर निकलें कोड है, ताकि $? हमेशा $pipestatus[-1] के समान है।

    बी। बैश के साथ:

    निकास कोड PIPESTATUS विशेष सरणी में प्रदान किए जाते हैं। cmd1 बाहर निकलने के कोड, ${PIPESTATUS[0]} में है ${PIPESTATUS[2]} में cmd3 बाहर निकलें कोड है, ताकि $? हमेशा ${PIPESTATUS: -1} के समान है।

    ...

    अधिक जानकारी के लिए निम्न link देखते हैं।

18
[ $? -eq 0 ] || exit $?; # exit for none-zero return code 
+2

क्या यह 'निकास $' 'नहीं होना चाहिए? (कोई माता-पिता नहीं)? – malthe

4
# 
#------------------------------------------------------------------------------ 
# run a command on failure exit with message 
# doPrintHelp: doRunCmdOrExit "$cmd" 
# call by: 
# set -e ; doRunCmdOrExit "$cmd" ; set +e 
#------------------------------------------------------------------------------ 
doRunCmdOrExit(){ 
    cmd="[email protected]" ; 

    doLog "DEBUG running cmd or exit: \"$cmd\"" 
    msg=$($cmd 2>&1) 
    export exit_code=$? 

    # if occured during the execution exit with error 
    error_msg="Failed to run the command: 
     \"$cmd\" with the output: 
     \"$msg\" !!!" 

    if [ $exit_code -ne 0 ] ; then 
     doLog "ERROR $msg" 
     doLog "FATAL $msg" 
     doExit "$exit_code" "$error_msg" 
    else 
     #if no errors occured just log the message 
     doLog "DEBUG : cmdoutput : \"$msg\"" 
     doLog "INFO $msg" 
    fi 

} 
#eof func doRunCmdOrExit 
+1

'$ * 'का उपयोग करने के लिए शायद ही कभी कोई कारण है; रिक्त स्थान और वाइल्डकार्ड को संरक्षित करने के लिए '" $ @ "का उपयोग करें। –