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

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

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

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

NullGlob

nullglob

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

به طور عادی، وقتی یک glob که بر هیچ نام فایلی منطبق نمی‌شود، بسط داده می‌شود، بدون تغییر باقی می‌ماند. بدین معنی که نتایجی مانند این به دست می‌آورید:

  •  $ rm *.bak
     rm: cannot remove `*.bak': No such file or directory

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

به هرحال، این موضوع در برنامه‌نویسی باعث برخی نتایج نامطلوب می‌گردد. یک آرایه مانند این را ملاحظه کنید:

  •  # Bash  در پوسته
     files=(*)
     echo "There are ${#files[*]} files here."

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

گزینه nullglob امکان اجتناب از این مشکل را برای ما فراهم می‌کند. اگر این گزینه تنظیم شود، جانشینِ منطبق نشده به جای اینکه به عنوان یک کلمه منفرد آنجا بماند، کاملاً کنار گذاشته می‌شود. -- با صفر کلمه جایگزین می‌شود-- .

  •  # Bash  در پوسته
     shopt -s nullglob
     files=(*)
     echo "There are ${#files[*]} files here."

گزینه nullglob به طور پیش‌فرض فعال نیست زیرا موقعیت‌های دیگری موجود است، که در آنها این رفتارش می‌تواند بینهایت مبهوت کننده باشد. برای نمونه، اگر یک جانشین انطباق نیافته، از لیست شناسه‌های ls حذف گردد، به طور کاملاً غیر منتظره‌ای رفتار می‌کند:

  •   shopt -s nullglob
     ls *.xyzqj
     # .در این حالت تمام فایلهای این دایرکتوری لیست خواهند شد
     # ‎.بدون شناسه به کار برود ls‎ درست مانند موقعی که دستور  

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

  •  # Bash در پوسته
     shopt -s dotglob
     shopt -s nullglob
     files=(*)
     echo "There are ${#files[*]} files here."

فقط به خاطر داشته باشید که این گزینه‌ها تا موقعی که غیر فعال نشده‌اند، برای پردازش پوسته جاری مؤثر باقی می‌مانند.

هشدار

فعالسازی nullglob در یک محدوده، گسترده می‌تواند باگ‌های ناشی از تکنیک‌های نامناسب برنامه نویسی را راه‌اندازی نماید که در غیر اینصورت می‌توانند در بیشترین وضعیت‌ها علائمی بروز ندهند.

برای نمونه، ‎unset var[1]‎ به طور غیر منتظره درست کار نخواهد نمود. این به علت آن است که bash تصور می‌کند ‎var[1]‎ یک glob است، که فایلی که با آن مطابقت کند پیدا نگردیده، و طبق دستورالعمل nullglob آن را حذف می‌کند، که باعث می‌شود اسکریپت شما به جای ‎unset var[1]‎ دستور unset را اجرا کند - و هیچ چیز غیرفعال نمی‌شود. روش صحیح برای اصلاح این مسئله نقل‌قول نمودن نام متغیر است (و همیشه ‎-v‎ را به طور صریح ذکر کنید): ‎unset -v 'var[1]'‎. یک مثال دیگر تعریف یک آرایه با کاربرد ‎arr=([1]=*)‎ است که در آن طرف راست عبارت تخصیص یک glob غیرنقل‌قولی شده می‌باشد. اگر ‎nullglob‎ در این حالت فعال بشود آنوقت نتیجه یک آرایه تهی خواهد شد. این یک باگ Bash است که باید در نگارش بعدی اصلاح بشود، اما باز هم نقل‌قول کردن آنها شیوه مناسبی است.

با موارد استثنای بسیار کم (تعداد اندکی از دستورات داخلی که در شرایط ویژه از تجزیه اصلاح شده‌ای استفاده می‌کنند، برای مثال declare)، موقعی که شناسه‌های فرمان ساده می‌توانند به عنوان globها تفسیر گردند (کلماتی که شامل *، ‎?‎، و ‎[‎ هستند، و در صورتیکه الگوهای extglob فعال شده باشند) همیشه از نقل‌قولها استفاده کنید. اگر می‌خواهید حالت‌هایی را که در آنها بسط نام مسیر در محل‌های ناخواسته صورت می‌گیرد تشخیص بدهید، می‌توانید گزینه failglob را فعال کنید تا در صورتیکه یک الگوی glob در انطباق با هیچ نام فایلی موفق نشود Bash با یک پیغام خطا خارج شود. به هر حال، آنوقت شما باید تضمین کنید که تمام globهایی که واقعاً برای glob بودن در نظر گرفته شده‌اند حداقل با یک نام فایل منطبق شوند. همچنین توجه نمایید که تضمین نمی‌شود که نتیجه یک بسط glob با خود glob تفاوت داشته باشد. failglob در یک دایرکتوری که شامل تنها یک فایل به نام ‎?‎ باشد ‎echo ?‎ را از ‎echo '?'‎ تمیز نخواهد داد. nullglob تمیز می‌دهد.

فعال کردن failglob، nullglob، یا هر دو در ضمن توسعه و تست می‌تواند به زود فهمیدن اشتباهات کمک کند.

قابلیت حمل

‎"null globbing"‎ توسط POSIX تعریف نگردیده است. در اسکریپت‌های قابل حمل، شما باید به طور صریح با بررسی کردن آنکه فایلها واقعا وجود دارند، کنترل نمایید که یک انطباق glob موفق بوده.

# POSIX

for x in *; do
    [ -e "$x" ] || break
    ...
done

# POSIX

f() {
    [ -e "$1" ] || return 1

    for x; do
        ...
    done
}

f * || echo 'No files found'

برخی پوسته‌های مدرن سازگار با POSIX به عنوان یک الحاقیه، null globbing را ممکن می‌سازند.

# Bash
shopt -s nullglob

در ksh93، گزینه تعویض عملکرد وجود ندارد. در عوض برای اینکه آن رفتار "nullglob" فعال بشود استفاده درون برنامه‌ای از گزینه ‎"N"‎ در ترکیب الگوی فرعی ‎∼()‎ تعیین شده است.

# ksh93

for x in ~(N)*; do
    ...
done

# zsh
setopt NULL_GLOB

mksh هنوز پشتیبانی از nullglob ندارد ( نگهدارنده‌اش می‌گوید فکری برایش خواهد کرد).

See Also


NullGlob (آخرین ویرایش ‎2012-09-04 09:44:50‎ توسط ormaaj)