آموزش اسکریپت نویسی

آموزش اسکریپت نویسی پوسته گنو-لینوکس

آموزش اسکریپت نویسی

آموزش اسکریپت نویسی پوسته گنو-لینوکس

Answers105

Answers105

واقعاً پاسخ درست برای هر تمرین «زیرا ‎set -e‎ نوعی قمار است» می‌باشد.

به هرحال، بعضی اشخاص توضیحات مفصل‌تری می‌خواهند. بنابراین، پیش بروید:


تمرین 1: چرا این مثال کار نمی‌کند؟

   1 #!/bin/bash
   2 set -e
   3 i=0
   4 let i++
   5 echo "i is $i"

set -e‎ موجب برون رفت می‌گردد، چون بر اساس مستندات، ‎ «اگر یک فرمان ساده(گرامر پوسته فوق را ببینید) با یک وضعیت غیر صفر خارج شود. در صورتیکه فرمان ناموفق بخشی از لیست فرمانهای بلافاصله پس از یک کلمه کلیدی while یا until، قسمتی از یک تست در ساختار یک if، قسمتی از یک لیست && یا ||، باشد یا اگر مقدار بازگشتی فرمان باشد که توسط ! معکوس گردیده، پوسته خارج نمی‌شود».

فرمان let یک فرمان ساده است، و بواسطه هیچ یک از موارد استثنای فوق واجد شرایط نمی‌شود. علاوه براین، ‎help let‎ به ما می‌گوید «اگر ارزش آخرین شناسه صفر ارزیابی شود، let یک و در غیر آنصورت صفر را برمی‌گرداند.» ‎i++‎ صفر ارزیابی می‌شود، بنابراین ‎let i++‎ وضعیت 1 را برمی‌گرداند و ماشه ‎set -e را می‌چکاند. اسکریپت به طور غیرعادی خاتمه می‌یابد. به علت اینکه ما یک را به متغیری افزوده‌ایم.


تمرین 2: چرا به نظر می‌رسد این یکی گاهی اوقات کار می‌کند؟ در کدام نگارش‌های bash کار می‌کند، و در کدام نگارش‌ها ناموفق می‌شود؟

   1 #!/bin/bash
   2 set -e
   3 i=0
   4 ((i++))
   5 echo "i is $i"

((...))‎ مطابق دستور زبان پوسته واجدشرایط یک فرمان ساده نمی‌باشد. بنابراین برای کشیدن ماشه انصراف ‎set -e‎ مطلوب نمی‌باشد، ولواینکه بازهم در این نمونه خاص وضعیت 1 را برمی‌گرداند(به دلیل آنکه ‎i++‎ در خلال تنظیم i به 1 خودش صفر ارزیابی می‌شود، و چون صفر در یک مضمون محاسباتی به عنوان false در نظر گرفته می‌شود).

به هرحال، این رفتار در ‎bash 4.1‎ تغییر کرد. تمرین 2 فقط در ‎bash 4.0‎ و قبل از آن کار می‌کند! در ‎bash 4.1‎، فرمان ‎((...))‎ برای انصراف ‎set -e‎ شناسایی می‌گردد، و تمرین چیزی چاپ نخواهد کرد، درست مانند تمرین 1.

این مطلب اشاره من در باره آنکه ‎set -e‎ غیر قابل اطمینان است را تقویت می‌کند. شما حتی نمی‌توانید برای نامتناقض رفتار نمودن آن در میان انتشارهای فرعی یک پوسته، به آن اعتماد کنید.


تمرین 3: چرا این اسکریپت‌ها عیناً مثل هم نیستند؟

   1 #!/bin/bash
   2 set -e
   3 test -d nosuchdir && echo no dir
   4 echo survived

   1 #!/bin/bash
   2 set -e
   3 f() { test -d nosuchdir && echo no dir; }
   4 f
   5 echo survived

در اسکریپت اول، فرمان test «بخشی از هر فرمان اجرا شده در یک لیست && یا || به غیر از فرمان متعاقب آخرین && یا || می‌باشد» (صفحه man در ‎Bash 4.2‎ )، بنابراین باعث نمی‌شود که پوسته خارج شود.

در اسکریپت دوم نیز که صحیح است، پوسته فوراً بعد از فرمان ‎test ...&&‎ خارج نمی‌شود. با این وجود، تابع f عدد 1 (عدم موفقیت) را به علت آنکه کد وضعیت آخرین فرمان اجرا شده در تابع بوده، برگشت می‌دهد. از این جهت فرمان ساده f در بدنه اصلی اسکریپت عدد 1 (شکست) را برگشت می‌دهد، که باعث می‌شود پوسته خارج شود.


تمرین 4: چرا این اسکریپت‌ها معادل هم نیستند؟

   1 set -e
   2 f() { test -d nosuchdir && echo no dir; }
   3 f
   4 echo survived

   1 set -e
   2 f() { if test -d nosuchdir; then echo no dir; fi; }
   3 f
   4 echo survived

اسکریپت اول این تمرین همانند اسکریپت دوم از تمرین 3 است. برای یک توضیح، پاسخ قبلی در مورد آن یکی را ببینید.

در اسکریپت دوم، یکی از روشهایی را مشاهده می‌کنیم که در آن if و && همان مورد نیستند، در مستندات تحت عنوان فرمان‌های مرکب، در تعریف if این جمله را پیدا می‌کنیم:

  • وضعیت خروج، وضعیت خروج آخرین فرمان اجرا شده، یا در صورتیکه هیچ شرط بررسی شده‌ای صحیح نباشد صفر است.

چون test صحیح نیست، و فرمانی اجرا نگردیده است، if باید صفر برگشت بدهد. یعنی if صفر برگشت می‌دهد، و پوسته خارج نمی‌شود.


پاسخ‌هایFAQ105 (آخرین ویرایش ‎2013-01-14 19:54:52‎ توسط GreyCat)