ফাঁদ ব্যবহার করা সর্বদা একটি বিকল্প নয়। উদাহরণস্বরূপ, আপনি যদি কোনও ধরণের পুনরায় ব্যবহারযোগ্য ফাংশন লিখে থাকেন যা ত্রুটি পরিচালনার প্রয়োজন হয় এবং যে কোনও স্ক্রিপ্ট থেকে ফোন করা যেতে পারে (সহায়ক ফাংশন দিয়ে ফাইলটি সস করার পরে), ফাংশনটি বাইরের স্ক্রিপ্টের প্রস্থান সময় সম্পর্কে কিছুই ধরে নিতে পারে না, যা ফাঁদ ব্যবহার খুব কঠিন করে তোলে। ট্র্যাপগুলি ব্যবহারের আর একটি অসুবিধা হ'ল খারাপ সংশ্লেষযোগ্যতা, কারণ আপনি পূর্ববর্তী ট্র্যাপগুলি ওভাররাইট করার ঝুঁকিপূর্ণ যা কলার শৃঙ্খলে আগে সেট আপ করা যেতে পারে।
একটি ছোট্ট কৌশল আছে যা ফাঁদ ছাড়াই সঠিক ত্রুটি পরিচালনার জন্য ব্যবহার করা যেতে পারে। আপনি ইতিমধ্যে অন্যান্য উত্তরগুলি থেকে জানেন set -e
যে আপনি কমান্ডগুলির ||
পরে যদি অপারেটর ব্যবহার করেন তবে সেগুলি কাজ করে না , এমনকি যদি আপনি সেগুলি সাবশেলে চালানও; উদাহরণস্বরূপ, এটি কাজ করবে না:
#!/bin/sh
# prints:
#
# --> outer
# --> inner
# ./so_1.sh: line 16: some_failed_command: command not found
# <-- inner
# <-- outer
set -e
outer() {
echo '--> outer'
(inner) || {
exit_code=$?
echo '--> cleanup'
return $exit_code
}
echo '<-- outer'
}
inner() {
set -e
echo '--> inner'
some_failed_command
echo '<-- inner'
}
outer
তবে ||
ক্লিনআপের আগে বাইরের ফাংশন থেকে ফিরে আসা রোধ করার জন্য অপারেটরের প্রয়োজন। কৌশলটি পটভূমিতে অভ্যন্তরীণ কমান্ডটি চালানো এবং তারপরে তাত্ক্ষণিকভাবে অপেক্ষা করুন wait wait
Builtin ভেতরের কমান্ডের প্রস্থান কোড ফিরে আসবে, এবং এখন আপনি ব্যবহার করছেন ||
পরে wait
, না ভেতরের ফাংশন, তাই set -e
আধুনিক ভিতরে সঠিকভাবে কাজ করে:
#!/bin/sh
# prints:
#
# --> outer
# --> inner
# ./so_2.sh: line 27: some_failed_command: command not found
# --> cleanup
set -e
outer() {
echo '--> outer'
inner &
wait $! || {
exit_code=$?
echo '--> cleanup'
return $exit_code
}
echo '<-- outer'
}
inner() {
set -e
echo '--> inner'
some_failed_command
echo '<-- inner'
}
outer
এখানে জেনেরিক ফাংশন যা এই ধারণার উপর নির্ভর করে। আপনি local
কীওয়ার্ডগুলি সরিয়ে ফেললে সমস্ত পসিক্স-সামঞ্জস্যপূর্ণ শেলগুলিতে কাজ করা উচিত , অর্থাত্ সমস্তগুলি local x=y
কেবলমাত্র দিয়ে প্রতিস্থাপন করুন x=y
:
# [CLEANUP=cleanup_cmd] run cmd [args...]
#
# `cmd` and `args...` A command to run and its arguments.
#
# `cleanup_cmd` A command that is called after cmd has exited,
# and gets passed the same arguments as cmd. Additionally, the
# following environment variables are available to that command:
#
# - `RUN_CMD` contains the `cmd` that was passed to `run`;
# - `RUN_EXIT_CODE` contains the exit code of the command.
#
# If `cleanup_cmd` is set, `run` will return the exit code of that
# command. Otherwise, it will return the exit code of `cmd`.
#
run() {
local cmd="$1"; shift
local exit_code=0
local e_was_set=1; if ! is_shell_attribute_set e; then
set -e
e_was_set=0
fi
"$cmd" "$@" &
wait $! || {
exit_code=$?
}
if [ "$e_was_set" = 0 ] && is_shell_attribute_set e; then
set +e
fi
if [ -n "$CLEANUP" ]; then
RUN_CMD="$cmd" RUN_EXIT_CODE="$exit_code" "$CLEANUP" "$@"
return $?
fi
return $exit_code
}
is_shell_attribute_set() { # attribute, like "x"
case "$-" in
*"$1"*) return 0 ;;
*) return 1 ;;
esac
}
ব্যবহারের উদাহরণ:
#!/bin/sh
set -e
# Source the file with the definition of `run` (previous code snippet).
# Alternatively, you may paste that code directly here and comment the next line.
. ./utils.sh
main() {
echo "--> main: $@"
CLEANUP=cleanup run inner "$@"
echo "<-- main"
}
inner() {
echo "--> inner: $@"
sleep 0.5; if [ "$1" = 'fail' ]; then
oh_my_god_look_at_this
fi
echo "<-- inner"
}
cleanup() {
echo "--> cleanup: $@"
echo " RUN_CMD = '$RUN_CMD'"
echo " RUN_EXIT_CODE = $RUN_EXIT_CODE"
sleep 0.3
echo '<-- cleanup'
return $RUN_EXIT_CODE
}
main "$@"
উদাহরণ চলছে:
$ ./so_3 fail; echo "exit code: $?"
--> main: fail
--> inner: fail
./so_3: line 15: oh_my_god_look_at_this: command not found
--> cleanup: fail
RUN_CMD = 'inner'
RUN_EXIT_CODE = 127
<-- cleanup
exit code: 127
$ ./so_3 pass; echo "exit code: $?"
--> main: pass
--> inner: pass
<-- inner
--> cleanup: pass
RUN_CMD = 'inner'
RUN_EXIT_CODE = 0
<-- cleanup
<-- main
exit code: 0
এই পদ্ধতিটি ব্যবহার করার সময় আপনার কেবলমাত্র সচেতন হওয়া দরকার তা হ'ল শেল ভেরিয়েবলের সমস্ত পরিবর্তনগুলি আপনি যে কমান্ডটি run
দিয়েছিলেন তা কলিং ফাংশনে প্রচার করবে না, কারণ কমান্ডটি একটি সাবসিলে চলে।