2012-11-20 11 views
20

का उपयोग कब करें मैं कुछ समय पहले set -e पर आया हूं और मैं मानता हूं कि मैं इसे प्यार करता हूं। अब, कुछ समय बाद मैं कुछ बैश स्क्रिप्टिंग लिखने के लिए वापस आ गया हूं।सेट -e

मेरा प्रश्न अगर वहाँ कुछ सर्वोत्तम प्रथाओं जब set -e उपयोग करने के लिए कर रहे हैं और इसका इस्तेमाल करते हैं जब नहीं करने के लिए (.e.g। छोटे/बड़े लिपियों आदि में) या मैं नहीं बल्कि त्रुटियों को ट्रैक करने के cmd || exit 1 की तरह एक पैटर्न का उपयोग करना चाहिए है?

+0

यह भी देखें [सेट-ए 'क्या करता है, और इसे खतरनाक क्यों माना जा सकता है?] (Http://serverfault.com/q/143445/204345) सर्वर फॉल्ट पर। विशेष रूप से [डेबियन बग] (http://www.mail-archive.com/[email protected]/msg473314.html) मेरी राय में काफी गॉचा है। – Kontrollfreak

उत्तर

48

हाँ, आप हमेशा इसका इस्तेमाल करना चाहिए। लोग हर समय विजुअल बेसिक का मजाक उड़ाते हैं और कहते हैं कि यह वास्तविक प्रोग्रामिंग भाषा नहीं है, आंशिक रूप से इसके "त्रुटि फिर से शुरू करें" कथन के कारण। फिर भी वह खोल में डिफ़ॉल्ट है! set -e डिफ़ॉल्ट होना चाहिए था। आपदा की संभावना बहुत अधिक है।


स्थानों पर जहां यह ठीक है एक कमांड विफल करने के लिए, आप || true उपयोग कर सकते हैं

या यह रूप ||:, उदा छोटा है

grep Warning build.log ||: 

वास्तव में आप हर bash स्क्रिप्ट के शीर्ष पर एक कदम और आगे

set -eu 
set -o pipefail 

जाना चाहिए, और है।

-u यह एक त्रुटि बनाता है इस तरह के ${HSOTNAME} के रूप में एक गैर-मौजूद वातावरण चर संदर्भ के लिए, ${#} जाँच के साथ कुछ जिमनास्टिक की आवश्यकता होती है की कीमत पर इससे पहले कि आप संदर्भ ${1}, ${2}, और इतने पर।

pipefailmisspeled-command | sed -e 's/^WARNING: //' जैसी चीजें त्रुटियां उत्पन्न करता है।

+0

यहां हर किसी के पास इस सवाल के बारे में व्यक्तिगत प्राथमिकताएं हैं। आपका जवाब मेरे करीब है, इसलिए मैं इसे स्वीकार करता हूं। – dimba

0

जब यह विकल्प चालू होता है, तो एक सरल आदेश शैल त्रुटियों के परिणामों में सूचीबद्ध किसी भी कारण से विफल रहता है या बाहर निकलने की स्थिति मान> 0 देता है, और कुछ समय बाद, या बाद में यौगिक सूची का हिस्सा नहीं है, यदि कीवर्ड, और एक AND या OR सूची का हिस्सा नहीं है, और इससे पहले की पाइपलाइन नहीं है! आरक्षित शब्द, तो खोल तुरंत बाहर निकलेंगे।

+0

धन्यवाद, लेकिन मेरा सवाल यह है कि इसे इस्तेमाल करने की अनुशंसा की जाती है? उदाहरण के लिए, मुझे यह नहीं लगता कि यह इनिट स्क्रिप्ट्स (/etc/init.d/*) – dimba

+2

में उपयोग किया जाता है init.d स्क्रिप्ट बनाने के दौरान "set -e" का उपयोग करना खतरनाक होगा: सेट-ए का उपयोग करने से सावधान रहें init.d स्क्रिप्ट में। init.d स्क्रिप्ट को बाहर निकलने की स्थिति की आवश्यकता होती है जब deemons चल रहे हैं या init.d स्क्रिप्ट को निरस्त किए बिना बंद कर दिया गया है। इसलिए जब भी आप प्रोग्राम को निरस्त करने की परवाह नहीं करते हैं तो त्रुटि का उपयोग होता है, अन्यथा –

3

यदि आपका स्क्रिप्ट कोड त्रुटियों के लिए सावधानी से और उचित तरीके से जांच करता है, और उन्हें उचित तरीके से संभालता है, तो संभवतः आपको कभी भी set -e का उपयोग करने की आवश्यकता नहीं है या नहीं।

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

अधिक जटिल स्क्रिप्ट इन विधियों को जोड़ सकती हैं क्योंकि आप set +e का उपयोग अपने प्रभाव को फिर से बंद करने और स्पष्ट त्रुटि जांच पर वापस जाने के लिए कर सकते हैं।

ध्यान दें कि हालांकि set -e आईएफएफ किसी भी अपरीक्षित आदेश विफल रहता है बाहर निकलने के लिए खोल पैदा करने के लिए माना जाता है, यह इसे बंद करने के लिए फिर से जब अपने कोड से निपटने के रूप में वहाँ आसानी से अजीब मामलों हो सकता है अपने आप ही त्रुटि कर रही है बुद्धिमान है जहां एक कमांड एक गैर-शून्य निकास स्थिति लौटाएगा जिसकी आप अपेक्षा नहीं कर रहे हैं, और संभवतः ऐसे मामले भी जिन्हें आप परीक्षण में नहीं पकड़ सकते हैं, और जहां आपकी स्क्रिप्ट की अचानक घातक समाप्ति खराब स्थिति में कुछ छोड़ देगी। तो, set -e का उपयोग न करें, या इसे संक्षिप्त रूप से उपयोग करने के बाद इसे चालू करें, जब तक आप वास्तव में नहीं जानते कि आप इसे चाहते हैं।

ध्यान दें कि trap ERRtrap ERR के साथ त्रुटि त्रुटि पर कुछ करने के लिए अभी भी एक त्रुटि हैंडलर को परिभाषित कर सकता है जब set -e प्रभाव में है, क्योंकि यह अभी भी खोल से पहले चलाया जाएगा।

+4

मैं असहमत हूं। मुझे लगता है कि आपको डिफ़ॉल्ट रूप से 'set -e' का उपयोग करना चाहिए और यदि आपको वास्तव में आवश्यकता हो तो इसे हटा दें। आखिरी चीज जो आप चाहते हैं वह एक अनचाहे त्रुटि है जो आपकी स्क्रिप्ट से अधिक त्रुटियों या किसी प्रकार का गलत व्यवहार करने का कारण बनती है। –

+0

@ माइकवेलर अन्य राय सुनने में खुश हैं :) – dimba

+1

उत्पादन के उपयोग के लिए स्क्रिप्ट पढ़ने और लिखने के 25+ वर्षों के अनुभव से पता चलता है कि 'सेट-ई' शायद ही कभी उपयोगी है। –

3

आप प्यार यह !?

मेरी स्वयं के लिए, मैं एक विस्तृत में पसंद करते हैं, मेरी .bashrc इस तरह एक लाइन में होने:

trap '/usr/games/fortune /usr/share/games/fortunes/bofh-excuses' ERR 

(डेबियन पर: apt-get install fortunes-bofh-excuses :-)

लेकिन यह केवल मेरी प्राथमिकता है ;-)

अधिक गंभीरता से

lastErr() { 
    local RC=$? 
    history 1 | 
     sed ' 
    s/^ *[0-9]\+ *\(\(["'\'']\)\([^\2]*\)\2\|\([^"'\'' ]*\)\) */cmd: \"\3\4\", args: \"/; 
    s/$/", rc: '"$RC/" 
} 
trap "lastErr" ERR 

Gna 
bash: Gna : command not found 
cmd: "Gna", args: "", rc: 127 

Gna gna 
cmd: "Gna", args: "gna", rc: 127 

"Gna gna" foo 
cmd: "Gna gna", args: "foo", rc: 127 

ठीक है, वहाँ से आप:

trap "lastErr >>/tmp/myerrors" ERR 
"Gna gna" foo 

cat /tmp/myerrors 
cmd: "Gna gna", args: "foo", rc: 1 

या बेहतर:

lastErr() { 
local RC=$? 
history 1 | 
    sed ' 
    s/^ *[0-9]\+ *\(\(["'\'']\)\([^\2]*\)\2\|\([^"'\'' ]*\)\) */cmd: \"\3\4\", args: \"/; 
    s/$/", rc: '"$RC/ 
    s/^/$(date +"%a %d %b %T ")/" 
} 
"Gna gna" foo 

cat /tmp/myerrors 
cmd: "Gna gna", args: "foo", rc: 1 
Tue 20 Nov 18:29:18 cmd: "Gna gna", args: "foo", rc: 127 

... तुम भी $$, $PPID, $PWD या हो सकता है आपके जैसे अन्य जानकारियां जोड़ सकता है ..

+0

+1 टाइप करने के बजाय ग्रेग को $$$ का भुगतान क्यों करना चाहिए। बहुत अच्छी टिप्स – ghoti

संबंधित मुद्दे