المتغيرات المحلية في باش: محلي مقابل subshell
سؤال
بقدر ما أعرف أن هناك طريقتان لإنشاء متغيرات محلية في وظيفة bash: إنشاء subshell أو إعلان كل متغير كمحلية.
فمثلا:
# using local
function foo
{
local count
for count in $(seq 10)
do
echo $count
done
}
أو
# using subshell
function foo
{
(
for count in $(seq 10)
do
echo $count
done
)
}
من الممكن أن يكون الإصدار باستخدام subshell أبسط في الكتابة لأنك لا تضطر إلى الاهتمام بإعلان جميع المتغيرات المحلية (ناهيك عن البيئة) التي تم إنشاؤها/تصديرها بواسطة أدوات مثل getopts). لكنني يمكن أن أتخيل أن إنشاء فرعي له النفقات العامة.
إذن ما هو النهج الأفضل؟ ما هي إيجابيات/سلبيات؟
المحلول
ينطوي إنشاء قشرة فرعية fork()
, ، لذلك بالتأكيد لديها النفقات العامة مقارنة مع متغير محلي. على الرغم من أن القواعد الفرعية رخيصة-فأنت لا تقلق بشأن تكلفتها عندما تحتاج إلى واحدة-فهي ليست حرة.
إذا كان البرنامج النصي الخاص بك يستخدم بشكل كبير والأداء مهم حقًا (لذلك سيكون لديك المئات من المستخدمين جميعهم يقومون بتشغيله في نفس الوقت ، عدة مرات في اليوم) ، فقد تقلق بشأن تكلفة أداء القشرة الفرعية. OTOH ، إذا قمت بتشغيله مرة واحدة في الشهر والبرنامج النصي ككل يعمل لمدة تقل عن 10 ثوانٍ ، فربما لن تفعل ذلك.
ومع ذلك ، فيما يتعلق بالوضوح ، من الأفضل أن تكون صريحًا وإعلان المتغيرات-فهو يقلل من خطر كسر النص لأن شخصًا ما يأتي ويقول "من الواضح أن هذا القشرة الفرعية غير مطلوبة" (وهو في الحقيقة ليس " T ؛ أرغب في إزالة القطع الفرعية من وظائفك).
انظر إلى تطور البرامج النصية بيرل. لقد بدأوا كجزء حرة للجميع مع وجود متغيرات إلى الوجود عند الطلب. لقد أصبحوا تدريجياً أكثر صرامة ، مع وجود أسلوب عادي الآن لتسجيل جميع المتغيرات. إلى حد ما ، اتبعت القذائف مسارًا مشابهًا - ولكن ليس بدقة مثل Perl. AWK هي أيضا دراسة حالة مثيرة للاهتمام. تستخدم وظائفها المتغيرات العالمية ما لم تكن وسيطات إلى الوظيفة ، مما يؤدي إلى كتابة وظائف مع 3 وسيطات نشطة (على سبيل المثال) و 5 وسيطات غير نشطة تحدد بشكل فعال المتغيرات المحلية. إنه غريب الأطوار قليلاً ، على الرغم من أنه "يعمل".
نصائح أخرى
الآن ، التأكد من أن جميع الوظائف تعلن دائمًا أن جميع المتغيرات محلية ، أمر صعب للغاية.
أعتقد أن هذا معرض للخطأ ويفضل دائمًا استخدام الوظائف الفرعية:
f() (
echo "we are a subshell"
)
لا حاجة لإعلان المتغيرات المحلية - ولكن أيضًا لا توجد طريقة لتغيير المتغيرات العالمية. وهو أمر جيد في رأيي!
إحدى النتائج الإضافية هي أنك تحتاج دائمًا إلى التحقق من رمز الإرجاع / الخروج لهذه الوظائف والتصرف وفقًا لذلك! هذا ، لأنه لا يمكنك الخروج من البرنامج النصي من داخل وظيفة Subshell!
f() (
echo "Trying to exit"
exit 1
)
f
echo "Did not exit"
هذا لن يخرج من البرنامج النصي الخاص بك. تحتاج إلى القيام بذلك بهذه الطريقة:
f() (
echo "Trying to exit"
exit 1
)
f || exit $?
echo "Did not exit"
هذا سوف يخرج