منبع اصلی نوشتار زیر در این لینک قرار دارد

اشکالزدایی

ادامه یادداشت قبل


راهنمای آموزشی  BashGuide   مؤلف  Lhunath

6. اشکالزدایی

خیلی وقتها، خودتان را مستأصل می‌بینید که چرا، اسکریپت شما آنگونه عمل نمی‌کند، که شما می‌خواهید. حل این مسئله همواره، موضوع درک عمومی و شیوه‌های اشکال‌یابی است.

تشخیص مشکل

بدون آنکه دقیقاً بدانید مشکل چیست، به احتمال بسیار زیاد، خیلی زود نمی‌توانید چاره‌سازی نمایید. بنابراین مطمئن شوید، که به طور دقیق می‌دانید چه چیز اشتباه است. علائم و پیغام‌های خطا را بررسی و ارزیابی کنید.

سعی کنید مشکل را به صورت یک جمله با قاعده بیان کنید. چون اگر بخواهید از دیگران در حل مشکل کمک بگیرید نیز، این کار خیلی ضروری می‌باشد. شما که نمی‌خواهید آنها تمام اسکریپت شما را بازنویسی نمایند، همینطور هم نمی‌خواهید آنها سرتاسر اسکریپت شما را بازبینی یا آنرا اجرا کنند تاببینند که چه مشکلی پیش می‌اید. نه، شما لازم است مسئله را کاملاً برای خودتان و هر کسی که بخواهد کمکتان کند، روشن سازید. وگرنه لازمه‌اش، منتظرماندن تا زمانی است که نوع بشر وسایل تله‌پاتی را اختراع کند.


حداقل‌سازی کد اصلی

اگر اشکال‌یابی اسکریپت را شروع می‌کنید، به خودتان الهام خدایی اهدا نکنید، مورد دیگری که باید انجام دهید، کوشش جهت حداقل‌سازی کد اصلی برای مجزا نمودن مسئله می‌باشد.

نگران حفظ توانایی اسکریپت خود نباشید. تنها چیزی که باید باقی نگاه دارید، منطق قطعه کد اصلی است، که به نظر مشکل آفرین می‌باشد.

اغلب، بهترین روش آنست که اسکریپت خود را در یک فایل جدید کپی نموده و شروع به حذف نمودن هر آن چیزی که به نظر می‌رسد نامربوط است، بنمایید. به طور جایگزین، می‌توانید یک اسکریپت جدید که کاری مشابه همان کد انجام می‌دهد، بسازید، و ساختار را تا ایجاد دوباره مشکل ادامه دهید.

به مجرد اینکه، موردی که مشکل ایجاد نموده را حذف کردید، دست بکشید(یا موردی که اضافه نمودنش دوباره آن مشکل را ظاهر می‌کند)، شما کشف کرده‌اید که مشکل در کجا قرار دارد. حتی اگر به طور دقیق به آن نرسیده‌اید، حداقل دیگر به یک اسکریپت حجیم خیره نمی‌شوید، بلکه امیدوارانه، با کوتوله‌ای نه بیش از 3 تا 7 سطر، مواجه هستید.

برای مثال، اگر اسکریپتی دارید که باز کردن فایلهای تصویری موجود در شاخه image را برحسب تاریخ برای شما انجام می‌دهد، و بنا به دلایلی، تکرار روی فایلهای دایرکتوری را نمی‌توانید به طور صحیح پیش ببرید، کافی است اسکریپت را تا اندازه این قطعه کُد کاهش بدهید:

    for image in $(ls -R \"$imgFolder\"); do
        echo \"$image\"
    done

اسکریپت واقعی شما به مراتب پیچیده‌تر از این خواهد بود، و درون حلقه for آن نیز طولانی‌تر خواهد بود. اما اصل مشکل این کُد است. وقتی مشکل را به این اندازه محدود کنید، ممکن است دیدن آنکه با چه مشکلی مواجه هستید، آسانتر باشد. دستور echo اجزاء نام فایلها را بیرون می‌دهد، به نظر می‌رسد تمام فضاهای سفید با کاراکتر سطرجدید تعویض گردیده‌اند. باید اینطور باشد، زیرا echo برای هرقسمت از نام فایل که منتهی به فضای سفید است، اجرا می‌شود، نه برای هر نام تصویر(در نتیجه، به نظر می‌رسد، خروجی نام فایلهایی که دارای فضای سفید می‌باشند، تفکیک شده‌اند). با این کُد کاهش یافته، دیدن آنکه مسبب واقعی، جمله for است که خروجی ls را به کلمات تفکیک نموده، آسانتر است. هرگز ls را در اسکریپتها به کار نبرید، مگر آنکه بخواهید خروجی آنرا به کاربر نمایش بدهید.

ما نمی‌توانیم glob بازگشتی به کار ببریم(مگر در bash نگارش 4)، بنابراین باید دستور find را برای به دست آوردن نام فایلها به کار بگیریم. یک راه اصلاح آن، چنین خواهد بود:

    find \"$imgFolder\" -print0 | while IFS= read -r -d \'\' image; do
        echo \"$image\"
    done

اکنون که مشکل را در این مثال کوچک برطرف نموده‌اید، برگشتن و ترکیب کردن آن با اسکریپ اصلی آسان است.


فعال نمودن وضعیت اشکال‌یابی BASH

اگر بازهم خطای روش‌هایتان را نمی‌بینید، شاید وضعیت اشکال‌یابی BASH برای دیدن مشکل در میان کُد به شما کمک نماید.

موقعی که BASH با گزینه ‎-x‎ اجرا می‌شود، این وضعیت فعال می‌گردد، هر دستوری را قبل از اجرا در خروجی چاپ می‌کند. همینطورهم ، بعد از هر بسط و گسترشی که انجام شده است. در نتیجه، به طور دقیق می‌توانید ببینید با اجرای هر سطر کُد، چه اتفاقی رخ می‌دهد. به نقل‌قول‌های استفاده شده خیلی دقیق توجه نمایید. BASH نقل‌قولها را برای نشان دادن آنکه دقیقاً کدام رشته به عنوان یک شناسه منفرد عبور داده شده، به کار می‌برد.

سه روش برای فعال کردن این وضعیت موجود است.

  • اجرای اسکریپت به صورت ‎ bash -x‎:

          $ bash -x ./mybrokenscript
  • ویرایش سرآیند اسکریپت:
          #!/bin/bash -x
          [.. script ..]
    
  • یا:
          #!/usr/bin/env bash
          set -x
    
  • یا اضافه نمودن ‎set -x‎ در جایی از کُد برای فعال کردن این حالت، منحصراً برای قطعه معینی از کُد:

          [..کدهای بی ارتباط..]
          set -x
          [..قطعه کد مرتبط..]
          set +x
          [..کدهای بی ارتباط..]
  • اگر ‎set -x‎ شما مقدار زیادی خروجی دارد، ویژگی دلپذیر bash نگارش 4.1 و بالاتر، متغیر BASH_XTRACEFD است. این متغیر امکان تعیین یک توصیف‌گر فایل برای هدایت خروجی اشکال‌های ‎set -x‎ به آن را فراهم می‌کند. در نسخه‌های قدیمی‌تر bash، همواره این خروجی به stderr می‌رفت، و اگر جدا کردن آن از خروجی معمولی ناممکن نبود، ولی دشوار بود. این هم یک روش دلپسند برای کاربرد آن:

        # ‎ را در یک فایل کپی می‌کند set -x ‎بخش 
        # ‎با یک نام فایل به عنوان 1$ آنرا فعال می‌کند‎
        # اگر پارامتری وجود نداشته باشد آن را غیر فعال می‌کند
        # ‎شماره  4 نباید در جای دیگری از اسکریپت استفاده شده باشد fd ‎
        setx_output()
        {
            if [[ $1 ]]; then 
               exec 4>>\"$1\"
               BASH_XTRACEFD=4
               set -x
            else
               set +x
               exec 4>&-
            fi
        }

اگر اسکریپت‌های پیچیده و آشفته‌ای دارید، شاید تغییر محتوی متغیر PS4 قبل از برقراری اشکال‌یابی با ‎ -x را سودمند بیابید:

      export PS4=\'+$BASH_SOURCE:$LINENO:$FUNCNAME: \'


Step your code

اگر خروجی اشکال‌یابی از نظر شما خیلی سریع عبور می‌کند، می‌توانید کُد-مرحله‌ای را فعال کنید. کُد زیر از DEBUG دستور trap برای اطلاع به کاربر در باره دستوری که اجرا خواهد شد و انتظار برای تایید پیشرفت، استفاده می‌کند. این کُد را در محلی از اسکریپت خود که می‌خواهید مرحله‌ای بشود، قرار دهید:

    trap \'(read -p \"[$BASH_SOURCE:$LINENO] $BASH_COMMAND?\")\' DEBUG


اشکالزدای BASH

پروژه اشکالزدای Bash یک اشکال‌یاب gdb-مانند، در آدرس /http://bashdb.sourceforge.net است.

اشکال‌یاب فوق به شما کمک می‌کند در سرتاسر اسکریپت حرکت نموده و اشکالهای آن را پیگردی و پیدا کنید.


بازخوانی مستندات

اگر هنوز به نظر می‌رسد اسکریپت برایتان قابل قبول نیست، شاید ادراک شما از روش انجام کارها اشتباه است. به مستندات(یا این راهنما) رجوع کنید، برای ارزیابی آن که آیا فرمانها درست همانگونه که شما در مورد آنها می‌اندیشید کارمی‌کنند، یا دستور زبان کاربرد آنها همانطور است که شما فکر می‌کنید. بسیاری اوقات، اشخاص در باره چگونگی کارکرد for ، عملکرد تفکیک کلمه، یا اینکه چگونه باید از نقل‌قولها استفاده کنند، درک ناقصی دارند.

نکته‌ها را حفظ کنید و تکرارهای راهنمایی این آموزش را خوب به خاطر بسپارید. اینها غالباً برای پرهیز از مشکلات در اسکریپت‌ها به شما کمک می‌کنند.

من این مطلب را در بخش اسکریپهای این راهنما نیز اشاره کرده‌ام، اما تکرار آن در اینجا هم با ارزش است. اول از همه، اطمینان حاصل کنید که سرآیند اسکریپت شما به راستی ‎#! /bin/bash‎ است. اگر از قلم افتاده یا اگر موردی مانند این ‎#! /bin/sh‎ است، پس شما سزاوار مشکلاتی که دارید، هستید. چون به آن معنی است که احتمالاً حتی از BASH برای اجرای اسکریپت خود استفاده نمی‌کنید. به طور وضوح علت مشکل همانست. همچنین، اطمینان حاصل کنید که کاراکترهای رفتن سر سطر(CF) در انتهای سطرها ندارید. این به سبب اسکریپتهایی است که در ویندوز نوشته شده‌اند. می‌توانید به آسانی به طور مساعدی اینها را به این صورت پاک کنید:

  •     $ tr -d \'\\r\' < myscript > tmp && mv tmp myscript


پرسش و پاسخها و Pitfallها را بخوانید

صفحه‌های پرسش و پاسخهای رایج و دام‌های Bash تصورات غلط معمول و مشکلاتی که دیگران در اسکریپت‌های BASH با آنها روبرو شده‌اند را شرح می‌دهند. احتمال بسیار دارد، مشکل شما به شکلی در آنجا تشریح شده باشد.

برای اینکه قادر به یافتن مشکل خود در آنجا باشید، باید مسئله را به طور کاملاً واضح شناسایی کرده باشید. شما باید بدانید که در جستجوی چه چیزی می‌باشید.


از ما در IRC بپرسید

در 24 ساعت هفت روز هفته، اکثراً افرادی در کانال ‎#bash‎ حضور دارند. این کانال در شبکه freenode IRC مستقر است. برای رسیدن به ما، لازم است یک سرویس‌گیرنده IRC داشته باشید. از طریق آن به ‎irc.freenode.net‎ و ‎/join #bash ارتباط برقرار نمایید.

مطمئن شوید که می‌دانید مشکل واقعی چیست و آنرا به صورت مرحله‌ای روی کاغذ بیاورید، به طوری که خوب بتوانید آنرا شرح بدهید. ما دوست نداریم در مورد مسائل حدس بزنیم. با توضیح آنکه اسکریپت شما چه کاری باید انجام بدهد شروع کنید.

نکته دیگر، لطفاً قبل از ورود به ‎#bash‎ صفحه : XyProblem را ملاحظه نمایید.


پایان راهنمای BashGuide