দ্রষ্টব্য: 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 '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 )
আকাঙ্ক্ষিত আচরণ উৎপন্ন হয়। যদিও আমার কাছে এর কোন ব্যাখ্যা নেই।