• ثبت نام
  • ورود
  • 49624 - 021 تلفن
  • ثبت نام
  • ورود
  • 49624 - 021 تلفن

اسکریپت نویسی پیشرفته لینوکس – عیب یابی

AdvancedLinuxShell-8-novinhost.org

AdvancedLinuxShell-8-novinhost.org

اسکریپت نویسی پیشرفته لینوکس برای وبمستر ها – قسمت ۸ – عیب یابی اسکریپت

شل لینوکس سیستم عیب یابی قدرتمندی ندارد (حد اقل به پای ویژوال استودیو نمیرسد!) اما دستوراتی دارد که به شما در عیب یابی اسکریپت ها کمک میکند. در اسکریپت نویسی پیشرفته, بدون آشنایی با اصول عیب یابی اسکریپت, ممکن است یک خطای تایپی ساده روزها از چشمتان پنهان شود و اسباب زحمت برنامه نویس شود.

AdvancedLinuxShell-8-novinhost.org

برایان کرنیگان (Brian Kernighan), از خالقان لینوکس, و برنامه نویس CronJobs لینوکس, در مورد عیب یابی چنین میگوید» “عیب یابی دو برابر سخت تر از کد نویسی است, بنابراین, اگر شما کد را به هوشمندانه ترین شکل ممکن بنویسید, به تعریف دیگر, برای عیب یابی آن دیگر به اندازه کافی باهوش نیستید.”

شل لینوکس هنگام بروز خطا در اجرای اسکریپت, شماره سطری که در آن خطا را تشخیص داده را چاپ میکند, این شماره الزاما شماره سطری نیست که خطا در آن رخ داده است, به مثال زیر توجه کنید:

#!/bin/bash

# missing-keyword.sh

# What error message will this script generate? And why?

for a in 1 2 3

do

  echo “$a”

# done     # Required keyword ‘done’ commented out in line 8.

exit 0     # Will not exit here!

# === #

# From command line, after script terminates:

  echo $?    # 2

خروجی به این صورت خواهد بود:

missing-keyword.sh: line 10: syntax error: unexpected end of file

       

میبینید که خطا در سطر ۱۰, یعنی جایی که دستور exit 0      قرار دارد, تشخیص داده شده, در حالی که علت اصلی خطا غیر فعال کردن دستور done در سطر ۸ است (# done     )

اگر تازه از ویندوز به لینوکس مهاجرت کرده باشید, با space  ها مشکل خواهید داشت, فاصله ها در لینوکس به اندازه دستورات مهم هستند, اسکریپت زیر قصد دارد همه فایل هایی که در نام خود فاصله دارند را حذف کند:

#!/bin/bash
 
#  This script is supposed to delete all filenames in current directory
#+ containing embedded spaces.
#  It doesn't work.
#  Why not?
 
 
badname=`ls | grep ' '`
 
# Try this:
# echo "$badname"
 
rm "$badname"
 
exit 0

اشکالی که وجود دارد اینجاست که دستور rm فاصله را به عنوان جدا کننده فایل ها میشناسد, و اگر از rm بخواهیم یک فایل به نام “file one”را حذف کند, سعی خواهد کرد فایل های file و one را حذف کند, چرا که فاصله میان آنها را به عنوان جدا کننده میشناسد.

برای رفع این اشکال, اولا باید سعی کنیم در لینوکس به جای فاصله از ‘_’ در نام گذاری ها استفاده کنیم, دوما: لینوکس متغیری سراسری به نام IFS دارد که جدا کننده های فایل ها را مشخص میکند, در صورتی که با دستور IFS=$’\n’ این متغییر را برابر خط جدید “Enter” قرار دهیم, دیگر با کاراکتر فاصله به عنوان جدا کننده رفتار نخواهد کرد, راه حل سوم بسیار ساده تر است, به جای اسکریپتی که در بالا نوشتیم میتوانیم با کمک regex از rm بخواهیم همه فایل های فاصله دار را حذف کند:

rm *\ *
rm *" "*
rm *' '*

در صورتی که اسکریپت طولانی و پیچیده ای مینویسید, بهتر است یک تابع به نام debecho تعریف کنید, وظیفه این تابع این است که در صورت فعال بودن حالت Debug, خروجی های مربوط به عیب یابی را چاپ کند, تابع debecho میتواند به صورت زیر تعریف گردد:

debecho () {
  if [ ! -z "$DEBUG" ]; then
     echo "$1" >&2
  fi
}

حالا در صورتی که به متغیر DEBUG مقدار بدهید, حالت عیب یابی فعال شده و دستور debecho $Whatever مقدار متغیر مربوطه را چاپ خواهد کرد, چاپ کردن مقدار متغیر ها کمک میکند از صحت مقدار اختصاص یافته اطمینان حاصل کنید.

دستور tee نیز کمک میکند از خروجی دستور هایی که به ورودی دستوری دیگر انتقال میابد مطلع شوید.

به طور مثال اگر با دستور command1 | command2 خروجی دستور۱ را به ورودی دستور ۲ هدایت کرده باشید, خروجی دستور۱ را نخواهید دید, اگر دستور tee را بین این دو قرار دهیم, علاوه بر هدایت خروجی دستور اول به دستور دوم, خروجی دستور اول در خط فرمان چاپ خواهد شد.

نتیجه به این شکل خواهد بود:

Command1| tee | command2

در صورتی که میخواهید بدون اجرا کردن اسکریپت, خطا های آنرا چک کنید, میتوانید اسکریپت را با دستور sh -n  scriptname اجرا نمایید, نوشتن دستور set –n  در سطر اول داخل اسکریپت هم همین کار را انجام میدهد, تمام اسکریپت برای  بررسی خطا مرور میشود, اما هیچیک از دستورات اجرا نمیشود.

اجرای اسکریپت با دستور sh -v scriptname باعث میشود هر دستور قبل اجرا در خروجی چاپ شود, نوشتن set –v یا set -o verbose در سطر اول اسکریپت نیز همین نتیجه را خواهد داشت.

دستور sh -x scriptname همین کار را انجام میدهد, اما خروجی خلاصه تر خواهد بود.

نوشته مشابه

ثبت نظر