नीचे एक स्क्रिप्ट का उदाहरण दिया गया है, जो try/catch/finally
बैश में लागू होती है।
इस प्रश्न के अन्य उत्तरों की तरह, एक उपप्रकार से बाहर निकलने के बाद अपवादों को पकड़ा जाना चाहिए।
उदाहरण लिपियाँ एक अनाम फीफो बनाकर शुरू होती हैं, जिसका उपयोग स्ट्रिंग संदेशों को निकटतम ब्लॉक के अंत command exception
या throw
अंत तक करने के लिए किया जाता है try
। यहां संदेशों को पंद्रह से हटा दिया जाता है और एक सरणी चर में रखा जाता है। स्थिति को आदेशों के माध्यम से लौटाया जाता है return
और exit
एक अलग चर में रखा जाता है। एक catch
ब्लॉक में प्रवेश करने के लिए , यह स्थिति शून्य नहीं होनी चाहिए। एक catch
ब्लॉक में प्रवेश करने के लिए अन्य आवश्यकताओं को मापदंडों के रूप में पारित किया जाता है। यदि किसी catch
ब्लॉक का अंत हो जाता है, तो स्थिति शून्य पर सेट हो जाती है। यदि finally
ब्लॉक का अंत हो गया है और स्थिति अभी भी गैर-शून्य है, तो संदेशों और स्थिति वाले एक निहित थ्रो को निष्पादित किया जाता है। स्क्रिप्ट में फ़ंक्शन को कॉल करने की आवश्यकता होती है trycatchfinally
जिसमें एक अनहेल्ड अपवाद हैंडलर होता है।
trycatchfinally
कमांड का सिंटैक्स नीचे दिया गया है।
trycatchfinally [-cde] [-h ERR_handler] [-k] [-o debug_file] [-u unhandled_handler] [-v variable] fifo function
-c
विकल्प अपवाद संदेशों को कॉल स्टैक कहते हैं। विकल्प डिबग आउटपुट सक्षम बनाता है। विकल्प आदेश अपवाद सक्षम बनाता है। विकल्प उपयोगकर्ता अपने स्वयं के आदेश अपवाद संचालक स्थानापन्न करने की अनुमति देता है। विकल्प डिबग आउटपुट के लिए कॉल स्टैक कहते हैं। विकल्प डिफ़ॉल्ट आउटपुट फ़ाइल है जो बदल देता है । विकल्प उपयोगकर्ता अपने स्वयं के बिना क्रिया का अपवाद हैंडलर स्थानापन्न करने की अनुमति देता है। विकल्प हालांकि कमान प्रतिस्थापन के उपयोग के मूल्यों वापस पारित करने के लिए विकल्प अनुमति देता है। फीफो फ़ाइल नाम है।
फ़ंक्शन को एक उपप्रकार के रूप में कहा जाता है ।
-d
-e
-h
-k
-o
/dev/fd/2
-u
-v
fifo
function
trycatchfinally
नोट: cdko
स्क्रिप्ट को सरल बनाने के लिए विकल्पों को हटा दिया गया था।
catch
कमांड का सिंटैक्स नीचे दिया गया है।
catch [[-enoprt] list ...] ...
विकल्प नीचे परिभाषित किए गए हैं। पहली सूची का मूल्य स्थिति है। सब्सक्राइब वैल्यू संदेश हैं। यदि सूचियों की तुलना में अधिक संदेश हैं, तो शेष संदेशों को अनदेखा कर दिया जाता है।
-e
साधन [[ $value == "$string" ]]
(मूल्य सूची में कम से कम एक स्ट्रिंग से मेल खाना चाहिए)
-n
का अर्थ है [[ $value != "$string" ]]
(मूल्य सूची में तार किसी से मेल नहीं कर सकते हैं)
-o
का अर्थ है [[ $value != $pattern ]]
(मूल्य सूची में पैटर्न में से किसी से मेल नहीं कर सकते हैं)
-p
का अर्थ है [[ $value == $pattern ]]
(मान है सूची में कम से कम एक पैटर्न से मेल खाने के लिए) का
-r
अर्थ है [[ $value =~ $regex ]]
(मूल्य को सूची में कम से कम एक विस्तारित नियमित अभिव्यक्ति से मेल खाना है) का
-t
अर्थ है [[ ! $value =~ $regex ]]
(मूल्य सूची में विस्तारित नियमित अभिव्यक्तियों में से किसी से भी मेल नहीं खा सकता है)
try/catch/finally
स्क्रिप्ट नीचे दी गई है। इस उत्तर के लिए स्क्रिप्ट को सरल बनाने के लिए, अधिकांश त्रुटि जाँच को हटा दिया गया था। इससे आकार में 64% की कमी आई। इस स्क्रिप्ट की एक पूरी प्रति मेरे अन्य उत्तर में मिल सकती है ।
shopt -s expand_aliases
alias try='{ common.Try'
alias yrt='EchoExitStatus; common.yrT; }'
alias catch='{ while common.Catch'
alias hctac='common.hctaC; done; }'
alias finally='{ common.Finally'
alias yllanif='common.yllaniF; }'
DefaultErrHandler() {
echo "Orginal Status: $common_status"
echo "Exception Type: ERR"
}
exception() {
let "common_status = 10#$1"
shift
common_messages=()
for message in "$@"; do
common_messages+=("$message")
done
}
throw() {
local "message"
if [[ $# -gt 0 ]]; then
let "common_status = 10#$1"
shift
for message in "$@"; do
echo "$message" >"$common_fifo"
done
elif [[ ${#common_messages[@]} -gt 0 ]]; then
for message in "${common_messages[@]}"; do
echo "$message" >"$common_fifo"
done
fi
chmod "0400" "$common_fifo"
exit "$common_status"
}
common.ErrHandler() {
common_status=$?
trap ERR
if [[ -w "$common_fifo" ]]; then
if [[ $common_options != *e* ]]; then
common_status="0"
return
fi
eval "${common_errHandler:-} \"${BASH_LINENO[0]}\" \"${BASH_SOURCE[1]}\" \"${FUNCNAME[1]}\" >$common_fifo <$common_fifo"
chmod "0400" "$common_fifo"
fi
if [[ common_trySubshell -eq BASH_SUBSHELL ]]; then
return
else
exit "$common_status"
fi
}
common.Try() {
common_status="0"
common_subshell="$common_trySubshell"
common_trySubshell="$BASH_SUBSHELL"
common_messages=()
}
common.yrT() {
local "status=$?"
if [[ common_status -ne 0 ]]; then
local "message=" "eof=TRY_CATCH_FINALLY_END_OF_MESSAGES_$RANDOM"
chmod "0600" "$common_fifo"
echo "$eof" >"$common_fifo"
common_messages=()
while read "message"; do
[[ $message != *$eof ]] || break
common_messages+=("$message")
done <"$common_fifo"
fi
common_trySubshell="$common_subshell"
}
common.Catch() {
[[ common_status -ne 0 ]] || return "1"
local "parameter" "pattern" "value"
local "toggle=true" "compare=p" "options=$-"
local -i "i=-1" "status=0"
set -f
for parameter in "$@"; do
if "$toggle"; then
toggle="false"
if [[ $parameter =~ ^-[notepr]$ ]]; then
compare="${parameter#-}"
continue
fi
fi
toggle="true"
while "true"; do
eval local "patterns=($parameter)"
if [[ ${#patterns[@]} -gt 0 ]]; then
for pattern in "${patterns[@]}"; do
[[ i -lt ${#common_messages[@]} ]] || break
if [[ i -lt 0 ]]; then
value="$common_status"
else
value="${common_messages[i]}"
fi
case $compare in
[ne]) [[ ! $value == "$pattern" ]] || break 2;;
[op]) [[ ! $value == $pattern ]] || break 2;;
[tr]) [[ ! $value =~ $pattern ]] || break 2;;
esac
done
fi
if [[ $compare == [not] ]]; then
let "++i,1"
continue 2
else
status="1"
break 2
fi
done
if [[ $compare == [not] ]]; then
status="1"
break
else
let "++i,1"
fi
done
[[ $options == *f* ]] || set +f
return "$status"
}
common.hctaC() {
common_status="0"
}
common.Finally() {
:
}
common.yllaniF() {
[[ common_status -eq 0 ]] || throw
}
caught() {
[[ common_status -eq 0 ]] || return 1
}
EchoExitStatus() {
return "${1:-$?}"
}
EnableThrowOnError() {
[[ $common_options == *e* ]] || common_options+="e"
}
DisableThrowOnError() {
common_options="${common_options/e}"
}
GetStatus() {
echo "$common_status"
}
SetStatus() {
let "common_status = 10#$1"
}
GetMessage() {
echo "${common_messages[$1]}"
}
MessageCount() {
echo "${#common_messages[@]}"
}
CopyMessages() {
if [[ ${#common_messages} -gt 0 ]]; then
eval "$1=(\"\${common_messages[@]}\")"
else
eval "$1=()"
fi
}
common.GetOptions() {
local "opt"
let "OPTIND = 1"
let "OPTERR = 0"
while getopts ":cdeh:ko:u:v:" opt "$@"; do
case $opt in
e) [[ $common_options == *e* ]] || common_options+="e";;
h) common_errHandler="$OPTARG";;
u) common_unhandled="$OPTARG";;
v) common_command="$OPTARG";;
esac
done
shift "$((OPTIND - 1))"
common_fifo="$1"
shift
common_function="$1"
chmod "0600" "$common_fifo"
}
DefaultUnhandled() {
local -i "i"
echo "-------------------------------------------------"
echo "TryCatchFinally: Unhandeled exception occurred"
echo "Status: $(GetStatus)"
echo "Messages:"
for ((i=0; i<$(MessageCount); i++)); do
echo "$(GetMessage "$i")"
done
echo "-------------------------------------------------"
}
TryCatchFinally() {
local "common_errHandler=DefaultErrHandler"
local "common_unhandled=DefaultUnhandled"
local "common_options="
local "common_fifo="
local "common_function="
local "common_flags=$-"
local "common_trySubshell=-1"
local "common_subshell"
local "common_status=0"
local "common_command="
local "common_messages=()"
local "common_handler=$(trap -p ERR)"
[[ -n $common_handler ]] || common_handler="trap ERR"
common.GetOptions "$@"
shift "$((OPTIND + 1))"
[[ -z $common_command ]] || common_command+="=$"
common_command+='("$common_function" "$@")'
set -E
set +e
trap "common.ErrHandler" ERR
try
eval "$common_command"
yrt
catch; do
"$common_unhandled" >&2
hctac
[[ $common_flags == *E* ]] || set +E
[[ $common_flags != *e* ]] || set -e
[[ $common_flags != *f* || $- == *f* ]] || set -f
[[ $common_flags == *f* || $- != *f* ]] || set +f
eval "$common_handler"
}
नीचे एक उदाहरण है, जो मानता है कि उपरोक्त स्क्रिप्ट नाम की फ़ाइल में संग्रहीत है simple
। makefifo
फ़ाइल स्क्रिप्ट में वर्णित होता है इस सवाल का जवाब । यह धारणा बनती है कि नाम वाली फ़ाइल 4444kkkkk
मौजूद नहीं है, इसलिए अपवाद हो सकता है। ls 4444kkkkk
कमांड से त्रुटि संदेश आउटपुट स्वचालित रूप से उपयुक्त catch
ब्लॉक के अंदर दबा हुआ है ।
#!/bin/bash
#
if [[ $0 != ${BASH_SOURCE[0]} ]]; then
bash "${BASH_SOURCE[0]}" "$@"
return
fi
source simple
source makefifo
MyFunction3() {
echo "entered MyFunction3" >&4
echo "This is from MyFunction3"
ls 4444kkkkk
echo "leaving MyFunction3" >&4
}
MyFunction2() {
echo "entered MyFunction2" >&4
value="$(MyFunction3)"
echo "leaving MyFunction2" >&4
}
MyFunction1() {
echo "entered MyFunction1" >&4
local "flag=false"
try
(
echo "start of try" >&4
MyFunction2
echo "end of try" >&4
)
yrt
catch "[1-3]" "*" "Exception\ Type:\ ERR"; do
echo 'start of catch "[1-3]" "*" "Exception\ Type:\ ERR"'
local -i "i"
echo "-------------------------------------------------"
echo "Status: $(GetStatus)"
echo "Messages:"
for ((i=0; i<$(MessageCount); i++)); do
echo "$(GetMessage "$i")"
done
echo "-------------------------------------------------"
break
echo 'end of catch "[1-3]" "*" "Exception\ Type:\ ERR"'
hctac >&4
catch "1 3 5" "*" -n "Exception\ Type:\ ERR"; do
echo 'start of catch "1 3 5" "*" -n "Exception\ Type:\ ERR"'
echo "-------------------------------------------------"
echo "Status: $(GetStatus)"
[[ $(MessageCount) -le 1 ]] || echo "$(GetMessage "1")"
echo "-------------------------------------------------"
break
echo 'end of catch "1 3 5" "*" -n "Exception\ Type:\ ERR"'
hctac >&4
catch; do
echo 'start of catch' >&4
echo "failure"
flag="true"
echo 'end of catch' >&4
hctac
finally
echo "in finally"
yllanif >&4
"$flag" || echo "success"
echo "leaving MyFunction1" >&4
} 2>&6
ErrHandler() {
echo "EOF"
DefaultErrHandler "$@"
echo "Function: $3"
while read; do
[[ $REPLY != *EOF ]] || break
echo "$REPLY"
done
}
set -u
echo "starting" >&2
MakeFIFO "6"
TryCatchFinally -e -h ErrHandler -o /dev/fd/4 -v result /dev/fd/6 MyFunction1 4>&2
echo "result=$result"
exec >&6-
उपरोक्त स्क्रिप्ट का उपयोग करके परीक्षण किया गया था GNU bash, version 3.2.57(1)-release (x86_64-apple-darwin17)
। आउटपुट, इस स्क्रिप्ट को चलाने से, नीचे दिखाया गया है।
starting
entered MyFunction1
start of try
entered MyFunction2
entered MyFunction3
start of catch "[1-3]" "*" "Exception\ Type:\ ERR"
-------------------------------------------------
Status: 1
Messages:
Orginal Status: 1
Exception Type: ERR
Function: MyFunction3
ls: 4444kkkkk: No such file or directory
-------------------------------------------------
start of catch
end of catch
in finally
leaving MyFunction1
result=failure
एक अन्य उदाहरण जो नीचे दिखाए गए स्क्रिप्ट के साथ throw
फ़ंक्शन MyFunction3
को प्रतिस्थापित करके बनाया जा सकता है ।
MyFunction3() {
echo "entered MyFunction3" >&4
echo "This is from MyFunction3"
throw "3" "Orginal Status: 3" "Exception Type: throw"
echo "leaving MyFunction3" >&4
}
throw
कमांड का सिंटैक्स नीचे दिया गया है। यदि कोई पैरामीटर मौजूद नहीं है, तो चर में संग्रहीत स्थिति और संदेशों का उपयोग किया जाता है।
throw [status] [message ...]
आउटपुट, संशोधित स्क्रिप्ट निष्पादित करने से, नीचे दिखाया गया है।
starting
entered MyFunction1
start of try
entered MyFunction2
entered MyFunction3
start of catch "1 3 5" "*" -n "Exception\ Type:\ ERR"
-------------------------------------------------
Status: 3
Exception Type: throw
-------------------------------------------------
start of catch
end of catch
in finally
leaving MyFunction1
result=failure