ध्यान दें: zsh
"खराब पैटर्न" के बारे में शिकायत करेंगे यदि आप इसे यहां के अधिकांश उदाहरणों के लिए "इनलाइन टिप्पणियों" को स्वीकार करने के लिए कॉन्फ़िगर नहीं करते हैं और उन्हें प्रॉक्सी शेल के माध्यम से नहीं चलाते हैं जैसा मैंने किया है sh <<-\CMD
।
ठीक है, इसलिए, जैसा कि मैंने उपरोक्त टिप्पणियों में कहा था, मुझे विशेष रूप से बैश केset -E
बारे में नहीं पता है , लेकिन मुझे पता है कि पॉसिक्स संगत गोले यदि आप चाहें तो एक मूल्य का परीक्षण करने का एक सरल साधन प्रदान करते हैं:
sh -evx <<-\CMD
_test() { echo $( ${empty:?error string} ) &&\
echo "echo still works"
}
_test && echo "_test doesnt fail"
# END
CMD
sh: line 1: empty: error string
+ echo
+ echo 'echo still works'
echo still works
+ echo '_test doesnt fail'
_test doesnt fail
ऊपर आप देखेंगे कि हालांकि मैं इस्तेमाल किया parameter expansion
परीक्षण करने के लिए ${empty?} _test()
अभी भी return
है एक पास - के रूप में दिखाई है में पिछले echo
यह तब होता है कारण विफल मूल्य मारता है $( command substitution )
subshell है कि यह शामिल है, लेकिन इसकी मूल खोल - _test
इस समय - ट्रकिंग रहती है। और echo
परवाह नहीं करता - केवल सेवा करने के लिए यह बहुत खुश एक \newline; echo
है नहीं एक परीक्षण।
लेकिन इस पर विचार करें:
sh -evx <<-\CMD
_test() { echo $( ${empty:?error string} ) &&\
echo "echo still works" ; } 2<<-INIT
${empty?function doesnt run}
INIT
_test ||\
echo "this doesnt even print"
# END
CMD
_test+ sh: line 1: empty: function doesnt run
चूँकि मैंने अब _test()'s
पूर्व-निर्धारित पैरामीटर के साथ इनपुट को फीड किया है, INIT here-document
इसलिए _test()
फ़ंक्शन बिल्कुल भी चलाने का प्रयास नहीं करता है। क्या अधिक है कि sh
खोल स्पष्ट रूप से भूत को पूरी तरह से छोड़ देता है और echo "this doesnt even print"
प्रिंट भी नहीं करता है।
संभवतः वह नहीं है जो आप चाहते हैं।
ऐसा इसलिए होता है क्योंकि ${var?}
शैली पैरामीटर-विस्तार को लापता पैरामीटर की स्थिति में छोड़ने के लिए डिज़ाइन किया गया हैshell
, यह इस तरह से काम करता है :
${parameter:?[word]}
संकेत त्रुटि यदि Null
या Unset.
पैरामीटर अशांत या अशक्त है, expansion of word
या (यह दर्शाता है कि यह संदेश अप्रभावित है यदि शब्द छोड़ा गया है) written to standard error
और होगा shell exits with a non-zero exit status
। अन्यथा, का मूल्य parameter shall be substituted
। एक इंटरैक्टिव शेल से बाहर निकलने की आवश्यकता नहीं है।
मैं पूरे दस्तावेज़ को कॉपी / पेस्ट नहीं करूंगा, लेकिन यदि आप किसी ऐसे set but null
मान के लिए विफलता चाहते हैं जो आप फ़ॉर्म का उपयोग करते हैं:
${var
: error message }
साथ :colon
ऊपर के रूप में। यदि आप null
सफल होने के लिए एक मूल्य चाहते हैं , तो बृहदान्त्र को छोड़ दें। आप इसे नकार भी सकते हैं और केवल सेट वैल्यू के लिए असफल हो सकते हैं, जैसा कि मैं एक पल में दिखाता हूं।
का एक और रन _test():
sh <<-\CMD
_test() { echo $( ${empty:?error string} ) &&\
echo "echo still works" ; } 2<<-INIT
${empty?function doesnt run}
INIT
echo "this runs" |\
( _test ; echo "this doesnt" ) ||\
echo "now it prints"
# END
CMD
this runs
sh: line 1: empty: function doesnt run
now it prints
यह सभी प्रकार के त्वरित परीक्षणों के साथ काम करता है, लेकिन ऊपर आप देखेंगे कि _test()
, विफलताओं के बीच से भागते हैं pipeline
, और वास्तव में इसकी command list
उप-समयावधि पूरी तरह से विफल हो जाती है, क्योंकि फ़ंक्शन के भीतर कोई भी कमांड न तो चलती है और न ही निम्नलिखित echo
चलती है। हालांकि यह भी दिखाया गया है कि यह आसानी से परीक्षण किया जा सकता है क्योंकि echo "now it prints"
अब प्रिंट करता है।
शैतान विवरण में है, मुझे लगता है। उपरोक्त मामले में, जो शेल बाहर निकलता है वह स्क्रिप्ट नहीं है , _main | logic | pipeline
लेकिन ( subshell in which we ${test?} ) ||
थोड़ा सैंडबॉक्सिंग के लिए कहा जाता है।
और यह स्पष्ट नहीं हो सकता है, लेकिन अगर आप केवल विपरीत मामले, या केवल set=
मूल्यों के लिए पास करना चाहते हैं, तो यह काफी सरल है:
sh <<-\CMD
N= #N is NULL
_test=$N #_test is also NULL and
v="something you would rather do without"
( #this subshell dies
echo "v is ${v+set}: and its value is ${v:+not NULL}"
echo "So this ${_test:-"\$_test:="} will equal ${_test:="$v"}"
${_test:+${N:?so you test for it with a little nesting}}
echo "sure wish we could do some other things"
)
( #this subshell does some other things
unset v #to ensure it is definitely unset
echo "But here v is ${v-unset}: ${v:+you certainly wont see this}"
echo "So this ${_test:-"\$_test:="} will equal NULL ${_test:="$v"}"
${_test:+${N:?is never substituted}}
echo "so now we can do some other things"
)
#and even though we set _test and unset v in the subshell
echo "_test is still ${_test:-"NULL"} and ${v:+"v is still $v"}"
# END
CMD
v is set: and its value is not NULL
So this $_test:= will equal something you would rather do without
sh: line 7: N: so you test for it with a little nesting
But here v is unset:
So this $_test:= will equal NULL
so now we can do some other things
_test is still NULL and v is still something you would rather do without
उपरोक्त उदाहरण POSIX पैरामीटर प्रतिस्थापन के सभी 4 रूपों और उनके विभिन्न :colon null
या not null
परीक्षणों का लाभ उठाता है । उपरोक्त लिंक में अधिक जानकारी है, और यहां यह फिर से है ।
और मुझे लगता है कि हमें अपने _test
कार्य को भी दिखाना चाहिए , है ना? हम सिर्फ empty=something
अपने फ़ंक्शन के लिए एक पैरामीटर के रूप में घोषणा करते हैं (या किसी भी समय पहले से):
sh <<-\CMD
_test() { echo $( echo ${empty:?error string} ) &&\
echo "echo still works" ; } 2<<-INIT
${empty?tested as a pass before function runs}
INIT
echo "this runs" >&2 |\
( empty=not_empty _test ; echo "yay! I print now!" ) ||\
echo "suspiciously quiet"
# END
CMD
this runs
not_empty
echo still works
yay! I print now!
यह ध्यान दिया जाना चाहिए कि यह मूल्यांकन अकेले खड़ा है - इसे विफल करने के लिए कोई अतिरिक्त परीक्षण की आवश्यकता नहीं है। कुछ और उदाहरण:
sh <<-\CMD
empty=
${empty?null, no colon, no failure}
unset empty
echo "${empty?this is stderr} this is not"
# END
CMD
sh: line 3: empty: this is stderr
sh <<-\CMD
_input_fn() { set -- "$@" #redundant
echo ${*?WHERES MY DATA?}
#echo is not necessary though
shift #sure hope we have more than $1 parameter
: ${*?WHERES MY DATA?} #: do nothing, gracefully
}
_input_fn heres some stuff
_input_fn one #here
# shell dies - third try doesnt run
_input_fn you there?
# END
CMD
heres some stuff
one
sh: line :5 *: WHERES MY DATA?
और इसलिए अंत में हम मूल प्रश्न पर वापस आते हैं: कैसे एक $(command substitution)
उपधारा में त्रुटियों को संभालना है ? सच्चाई यह है - दो तरीके हैं, लेकिन न तो प्रत्यक्ष है। समस्या का मूल शेल के मूल्यांकन की प्रक्रिया है - शेल के मूल्यांकन की प्रक्रिया में शेल विस्तार ( $(command substitution)
पहले) वर्तमान शेल कमांड के निष्पादन की तुलना में होता है - जो तब होता है जब आपकी त्रुटियां पकड़ी जा सकती हैं और फंस सकती हैं।
सेशन के अनुभवों का मुद्दा यह है कि जब तक मौजूदा शेल त्रुटियों के लिए मूल्यांकन करता है, $(command substitution)
तब तक सब-सब पहले ही हटा दिया गया है - कोई त्रुटि नहीं है।
तो दो तरीके क्या हैं? या तो आप इसे स्पष्ट $(command substitution)
रूप से परीक्षणों के साथ उपधारा के भीतर करते हैं जैसा कि आप इसके बिना करेंगे, या आप इसके परिणामों को वर्तमान शेल चर में अवशोषित करेंगे और इसके मूल्य का परीक्षण करेंगे।
विधि 1:
echo "$(madeup && echo \: || echo '${fail:?die}')" |\
. /dev/stdin
sh: command not found: madeup
/dev/stdin:1: fail: die
echo $?
126
विधि 2:
var="$(madeup)" ; echo "${var:?die} still not stderr"
sh: command not found: madeup
sh: var: die
echo $?
1
यह प्रति पंक्ति घोषित चर की संख्या की परवाह किए बिना विफल हो जाएगा:
v1="$(madeup)" v2="$(ls)" ; echo "${v1:?}" "${v2:?}"
sh: command not found: madeup
sh: v1: parameter not set
और हमारा रिटर्न मान स्थिर रहता है:
echo $?
1
अब TRAP:
trap 'printf %s\\n trap resurrects shell!' ERR
v1="$(madeup)" v2="$(printf %s\\n shown after trap)"
echo "${v1:?#1 - still stderr}" "${v2:?invisible}"
sh: command not found: madeup
sh: v1: #1 - still stderr
trap
resurrects
shell!
shown
after
trap
echo $?
0
echo $( made up name )
साथ प्रतिस्थापित करना$( made up name )
। हालांकि मेरे पास कोई स्पष्टीकरण नहीं है।