लूप के परिणाम के आधार पर त्रुटि से बाहर निकलने के लिए मुझे यह स्क्रिप्ट कैसे मिल सकती है?


13

मेरे पास एक बैश स्क्रिप्ट है, जो set -o errexitइसलिए उपयोग होती है कि गलती से पूरी स्क्रिप्ट विफलता के बिंदु पर निकल जाती है।
स्क्रिप्ट एक curlकमांड चलाता है जो कभी-कभी इच्छित फ़ाइल को पुनर्प्राप्त करने में विफल रहता है - हालांकि जब ऐसा होता है तो स्क्रिप्ट त्रुटि से बाहर नहीं निकलती है।

मैंने एक forलूप जोड़ा है

  1. कुछ सेकंड के लिए रुकें और फिर curlकमांड को पुनः प्रयास करें
  2. falseलूप के लिए नीचे की ओर एक डिफ़ॉल्ट गैर-शून्य निकास स्थिति को परिभाषित करने के लिए उपयोग करें - यदि कर्ल कमांड सफल होता है - लूप टूट जाता है और अंतिम कमांड की निकास स्थिति शून्य होनी चाहिए।
#! /bin/bash

set -o errexit

# ...

for (( i=1; i<5; i++ ))
do
    echo "attempt number: "$i
    curl -LSso ~/.vim/autoload/pathogen.vim https://tpo.pe/pathogen.vim
    if [ -f ~/.vim/autoload/pathogen.vim ]
    then
        echo "file has been retrieved by curl, so breaking now..."
        break;
    fi

    echo "curl'ed file doesn't yet exist, so now will wait 5 seconds and retry"
    sleep 5
    # exit with non-zero status so main script will errexit
    false

done

# rest of script .....

समस्या तब होती है जब curlकमांड विफल हो जाता है, लूप पांच बार कमांड को फिर से प्राप्त करता है - यदि सभी प्रयास लूप फिनिश के लिए असफल होते हैं और मुख्य स्क्रिप्ट फिर से शुरू हो जाती है - इसके बजाय ट्रिगर करने के लिए errexit
यदि यह curlकथन विफल हो जाता है तो मुझे पूरी स्क्रिप्ट कैसे बाहर निकल सकती है?

जवाबों:


18

बदलने के:

done

साथ में:

done || exit 1

यह कोड से बाहर निकलने का कारण होगा यदि forलूप एक गैर-शून्य निकास कोड के साथ बाहर निकलता है।

सामान्य ज्ञान के बिंदु के रूप में, 1इन exit 1की जरूरत नहीं है। एक सामान्य exitकमांड अंतिम निष्पादित कमांड की निकास स्थिति के साथ बाहर निकल जाएगी जो falseडाउनलोड विफल होने पर (कोड = 1) होगा। यदि डाउनलोड सफल होता है, तो लूप का निकास कोड echoकमांड का निकास कोड है । echoआमतौर पर कोड = 0 के साथ बाहर निकलता है, सांकेतिक रूप से सफलता। उस स्थिति में, ||ट्रिगर नहीं होता है और exitकमांड निष्पादित नहीं होता है।

अंत में, ध्यान दें कि set -o errexitआश्चर्य से भरा हो सकता है। इसके पेशेवरों और विपक्षों की चर्चा के लिए, ग्रेग के FAQ # 105 देखें

प्रलेखन

से man bash:

के लिए ((expr1; expr2; expr3)); कर सूची; पहले किया गया था
, अंकगणितीय अभिव्यक्ति एक्सप्रे 1 का मूल्यांकन ARITHMETIC EVALUATION के तहत नीचे वर्णित नियमों के अनुसार किया गया है। अंकगणितीय अभिव्यक्ति expr2 तब बार-बार मूल्यांकन किया जाता है जब तक कि यह शून्य का मूल्यांकन नहीं करता है। हर बार expr2 एक गैर-शून्य मान का मूल्यांकन करता है, सूची निष्पादित की जाती है और अंकगणितीय अभिव्यक्ति expr3 का मूल्यांकन किया जाता है। यदि किसी भी अभिव्यक्ति को छोड़ दिया जाता है, तो यह व्यवहार करता है जैसे कि यह 1 का मूल्यांकन करता है । रिटर्न मान उस सूची में अंतिम कमांड की निकास स्थिति है जिसे निष्पादित किया गया है, या गलत है यदि कोई भी अभिव्यक्ति अमान्य है। [महत्व दिया]


क्या आपको लगता है trueकि ब्रेक स्टेटमेंट को स्पष्ट करने और लूप के निकास मान को सुनिश्चित करने से पहले इसे रखना एक अच्छा विचार होगा ?
राबर्टएल

1
मुझे लगता है कि स्पष्ट रूप से निहित से बेहतर है । इसीलिए मैंने लिखा कि exit 1जब सिर्फ मैदान exitने काम किया होगा। हालांकि, यह शैली का सवाल है और दूसरों की अपनी राय हो सकती है।
जॉन 1024

1
अच्छी तरह से काम करता है! धन्यवाद :) व्यक्तिगत रूप से मैं exitएक सादे निकास के रूप में पढ़ूंगा - जो स्क्रिप्ट को अपने आप में समाप्त करता है। exit 1 मुझे किसी अन्य प्रक्रिया (यानी errexit) के लिए एक "संकेत" के रूप में पढ़ा जाएगा - कि इसे "परिणाम" के आधार पर स्क्रिप्ट को समाप्त करना चाहिए exit 1। - इसलिए मैं साथ चला गया, exitलेकिन स्पष्टीकरण के लिए धन्यवाद
the_velour_fog

1
यदि आपकी स्क्रिप्ट त्रुटि की स्थिति के कारण बाहर निकल रही है, तो आपको कॉल करना चाहिएexit 1 । वह बिल्कुल प्रभावित नहीं करता है errexit। यह केवल कॉलिंग प्रोग्राम को बताता है कि कुछ गलत हुआ। falseआदेश एक बयान में शामिल हैं: exit(1)। यूनिक्स कमांड का 99.9% सफलता पर 0 और त्रुटि पर गैर-शून्य रिटर्न करता है। आपका भी होना चाहिए।
रॉबर्टएल

2

यदि आपने errexitसेट किया है, तो falseकथन को स्क्रिप्ट को तुरंत बाहर निकलने का कारण होना चाहिए। curlकमांड फेल हो गई तो वही बात ।

आप उदाहरण के लिए स्क्रिप्ट हैं, जैसा कि लिखा गया है, curlपहली बार असफल होने के बाद बाहर निकलना चाहिए falseअगर एरेक्सिट सेट होता है।

यह देखने के लिए कि यह कैसे काम करता है (मैं -eसेट करने के लिए शॉर्टहैंड का उपयोग करता हूं errexit:

$ ( set -e;  false; echo still here )
$

$ ( set +e;  false; echo still here )
still here
$

इसलिए यदि curlकमांड एक से अधिक बार निष्पादित होती है, तो यह स्क्रिप्ट errexitसेट नहीं होती है।


1
set -eउससे अधिक सूक्ष्म है। यह लूप में पहली असफल कमांड के बाद बाहर नहीं निकलेगा। आप यह साबित कर सकते हैं कि (set -e; for (( i=1; i<5; i++ )); do echo $i; false; done || echo "FAIL"; )कोड falseचार बार चलता है और चल रहा है। अधिक जानकारी के लिए set -e, ग्रेग के FAQ # 105 देखें
जॉन 1024 24

@ जॉन 1024 धन्यवाद। यह एक नीचे और नीचे जा रहा है।
राबर्टएल

@ जॉन 1024 लेकिन मुझे लगता है कि सबूत अभी भी errexitनिर्धारित नहीं है। कृपया प्रश्न में स्क्रिप्ट पर तर्क लागू करें। इसे चलाएं: (set -e; for (( i=1; i<5; i++ )); do echo $i; false; done ; echo still here ) हां परीक्षण रिटर्न मानों के साथ if while || &&एर्ग्रेक्सिट को ट्रिगर नहीं करता है। मूल लिपि ||लूप के लिए नहीं थी ।
राबर्ट

मैंने अभी देखा कि मैंने set -o errexitअपने उदाहरण कोड में कमांड नहीं दिखाया था , अब इसे जोड़ दिया है - और मेरे लिए यह अपेक्षा के अनुरूप त्रुटि नहीं थी। मुझे falseलूप के लिए अंतिम कमांड के रूप में रखने की आवश्यकता थी , फिर पास के लूप के साथ done || exit [1]- फिर यह अच्छी तरह से काम करता था!
the_velour_fog

@RobertL मैं आपकी बात देखता हूं।
जॉन 1024

1

set -o errexit छोरों और उपधाराओं में मुश्किल हो सकता है, क्योंकि आपको प्रक्रिया से बाहर का रास्ता पास करना होगा।

एक लूप को तोड़ना (सामान्य ऑपरेशन में भी) को बुरा अभ्यास माना जाता है। आप दो स्थितियों के लिए लूप के बजाय एक समय-लूप पसंद करने के लिए मुझे पुराने स्कूल में बुला सकते हैं, लेकिन मुझे पढ़ना बेहतर लगता है:

i=1
RET=-1
while [ $i -le 5 ] && [ $RET -ne 0 ]; do
    [ $i -eq 1 ] || sleep 5
    echo "attempt number: "$i
    curl -LSso ~/.vim/autoload/pathogen.vim https://tpo.pe/pathogen.vim
    RET=$?
    i=$((i+1))
done
exit $RET

0

यदि errexitसेट किया गया है और curlकमांड विफल रहता है तो स्क्रिप्ट विफल कर्ल कमांड के ठीक बाद समाप्त हो जाती है। बैश मैनुअल में ऐसा कोई संकेत नहीं है जो set -eकंपाउंड कमांड में किसी एकल के किसी भी असफल रिटर्न की स्थिति की अनदेखी करता हो। यह केवल तभी मामला होगा जब कंपाउंड कमांड को ऐसे संदर्भ में निष्पादित किया set -eजाता है जहां अनदेखी की जाती है।
https://www.gnu.org/software/bash/manual/bash.html#The-Set-Builtin

रॉबर्टएल द्वारा पोस्ट किए गए थोड़े अनुकूलित उदाहरण का प्रयास करें। यह गलत आदेश के बाद पहली बार पुनरावृति पर रुकता है:

( set -e; for (( i=1; i<5; i++ )); do echo $i; false; echo "${i}. iteration done"; done ; echo "loop done" )

0

आप बस कर्ल कमांड में --फ़ेल विकल्प को जोड़ सकते हैं, इससे आपकी समस्या का समाधान हो जाएगा, स्क्रिप्ट विफल हो जाएगी और त्रुटि पर बाहर निकल जाएगी यदि कर्ल कमांड विफल हो जाती है, यदि जेनकिंस पाइपलाइन में कर्ल का उपयोग करते समय बहुत उपयोगी हो:

curl -LSso --fail ~/.vim/autoload/pathogen.vim https://tpo.pe/pathogen.vim
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.