exitएक उपखंड में निष्पादन एक नुकसान है:
#!/bin/bash
function calc { echo 42; exit 1; }
echo $(calc)
स्क्रिप्ट 42 प्रिंट करता है, रिटर्न कोड के साथ सब्मिट से बाहर निकलता है 1, और स्क्रिप्ट के साथ जारी रहता है। यहां तक कि कॉल की जगह लेने से भी echo $(CALC) || exit 1मदद नहीं मिलती है क्योंकि रिटर्न कोड की वापसी कोड की echoपरवाह किए बिना 0 है calc। और calcपहले निष्पादित किया जाता है echo।
और भी अधिक गूढ़ता निम्नलिखित लिपि की तरह बिलिन exitमें लपेटकर प्रभाव को विफल कर रही है local। जब मैंने इनपुट मान को सत्यापित करने के लिए एक फ़ंक्शन लिखा, तो मैं इस समस्या से लड़खड़ा गया। उदाहरण:
मैं एक फाइल बनाना चाहता हूं, जिसका नाम है "ईयर महीने डे।लॉग", यानी 20141211.logआज के लिए। दिनांक एक उपयोगकर्ता द्वारा इनपुट है जो उचित मूल्य प्रदान करने में विफल हो सकता है। इसलिए, मेरे फ़ंक्शन में fnameमैं dateउपयोगकर्ता इनपुट की वैधता को सत्यापित करने के लिए वापसी मूल्य की जांच करता हूं :
#!/bin/bash
doit ()
{
local FNAME=$(fname "$1") || exit 1
touch "${FNAME}"
}
fname ()
{
date +"%Y%m%d.log" -d"$1" 2>/dev/null
if [ "$?" != 0 ] ; then
echo "fname reports \"Illegal Date\"" >&2
exit 1
fi
}
doit "$1"
अछा लगता है। स्क्रिप्ट को नाम दें s.sh। यदि उपयोगकर्ता स्क्रिप्ट को कॉल करता है ./s.sh "Thu Dec 11 20:45:49 CET 2014", तो फ़ाइल 20141211.logबनाई जाती है। यदि, हालांकि, उपयोगकर्ता प्रकार ./s.sh "Thu hec 11 20:45:49 CET 2014", तो स्क्रिप्ट आउटपुट:
fname reports "Illegal Date"
touch: cannot touch ‘’: No such file or directory
रेखा का fname…कहना है कि उप इनपुट में खराब इनपुट डेटा का पता लगाया गया है। लेकिन रेखा exit 1के अंत में local …कभी ट्रिगर नहीं किया जाता है क्योंकि localनिर्देश हमेशा लौटता है 0। ऐसा इसलिए है क्योंकि इसके बादlocal इसे निष्पादित किया जाता है और इस तरह इसके रिटर्न कोड को अधिलेखित कर दिया जाता है। और उसके कारण, स्क्रिप्ट जारी है और एक खाली पैरामीटर के साथ आह्वान करती है । यह उदाहरण सरल है, लेकिन एक वास्तविक एप्लिकेशन में बैश का व्यवहार काफी भ्रामक हो सकता है। मुझे पता है, असली प्रोग्रामर स्थानीय लोगों का उपयोग नहीं करते हैं $(fname)touch
यह स्पष्ट करने के लिए: इसके बिना local, स्क्रिप्ट अवैध रूप से गर्भपात करती है जब एक अवैध तारीख दर्ज की जाती है।
फिक्स लाइन को विभाजित करना है
local FNAME
FNAME=$(fname "$1") || exit 1
अजीब व्यवहार localबश के आदमी पृष्ठ के भीतर प्रलेखन के अनुरूप है : "वापसी की स्थिति 0 है जब तक कि स्थानीय किसी फ़ंक्शन के बाहर उपयोग नहीं किया जाता है, एक अमान्य नाम की आपूर्ति की जाती है, या नाम एक पठनीय चर है।"
हालांकि बग नहीं होने के कारण मुझे लगता है कि बैश का व्यवहार उल्टा है। मैं निष्पादन के अनुक्रम से अवगत हूं, localएक टूटे हुए असाइनमेंट को मुखौटा नहीं करना चाहिए, फिर भी।
मेरे प्रारंभिक उत्तर में कुछ गलतियाँ थीं। Mikeserv के साथ एक खुलासा और गहन चर्चा के बाद (उसके लिए धन्यवाद) मैं उन्हें ठीक करने के लिए गया था।