IFS - آموزش اسکریپت نویسی
X
تبلیغات
رایتل

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

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

#!/bin/bash

IFS

متغیر IFS

متغیر IFS در پوسته‌ها(Bourne، POSIX، ksh، bash) به عنوان جداکننده فیلد ورودی (یا جداکننده داخلی فیلد) به کار می‌رود. در اصل، رشته‌ای از کاراکترهای خاصی است، که موقع تجزیه یک سطر از ورودی، باید با آنها به عنوان جداکننده مابین کلمات/فیلدها، رفتار بشود.

مقدار پیش‌فرض IFS، فاصله، tab، سطرجدید است. (یک رشته سه کاراکتری.) اگر IFS برقرار نباشد(unset)، مانند آن عمل می‌کند که به این مقدار پیش‌فرض تنظیم شده باشد. (این احتمالاً برای سادگی در پوسته‌هایی است که از ترکیب دستوری ‎ $'...'‎ برای کاراکترهای خاص پشتیبانی نمی‌کنند.) اگر IFS به یک رشته تهی تنظیم گردد (که خیلی متفاوت با عدم برقرار بودن--unset-- آن است!)، تجزیه‌ای انجام نخواهد شد.

این متغیر در چند محل مختلف به کار می‌رود. با تعابیر کمی متفاوت:

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

  • موقع انجام تفکیک کلمه در یک بسط نقل‌قولی نشده، IFS برای تجزیه محتوای بسط به چندین کلمه، به کار می‌رود.

  • موقع اجرای بسط ‎ "$*"‎ یا‎ "${array[*]}"‎ (* همان @ نیست، و نقل‌قولی شده است -- یادداشت ویژه را ببینید!)، برای ساختن رشته خروجی نهایی، کاراکتر اول از IFS ، بین عناصر جای می‌گیرد.

  • همچنین، موقع انجام بسط ‎ "${!prefix*}"‎،کاراکتر اول از IFS بین نام متغیرهای سازنده رشته خروجی قرار می‌گیرد. (باز هم، یادداشت ویژه را ببینید.)

  • IFS توسط دستور ‎ complete -W‎ تحت اجرای قابل برنامه‌ریزی، به کار می‌رود.

در تجزیه فیلد ، هر یک از موقعیت‌های فوق, (در دو تای اول)، قواعد ویژه‌ای برای کار با کاراکترهای فضای سفید IFS وجود دارد. کاراکترهای فضای سفید IFS موجود در اول و آخر رشته به طور کامل پاک می‌شوند، و با کاراکترهای فضای سفید متوالی IFS داخل یک رشته به عنوان یک جداکننده منفرد رفتار می‌شود. برای مثال، مورد ذیل را ملاحظه نمایید:

IFS=: read user pwhash uid gid gecos home shell \
   <<< 'statd:x:105:65534::/var/lib/nfs:/bin/false'

IFS=$' \t\n' read one two three \
   <<< '   1      2  3'

در مثال اول، به متغیر gecos یک رشته تهی اختصاص داده می‌شود، که محتوای فیلد مابین دو کاراکتر کولن مجاور است. کولن‌ها با هم یگانه‌سازی نمی‌شوند، با آنها به صورت جداکننده‌های مجزا رفتار می‌گردد. در مثال دوم، متغیر one مقدار 1 را می‌پذیرد، و متغیر two مقدار 2 را دریافت می‌کند. فضاهای سفید مقدم هَرَس می‌شوند، و فضاهای سفید داخلی یگانه می‌شوند.

نمونه‌های تصادفی بیشتر:

$ IFS= read a b c <<< 'the plain gold ring'
$ echo "=$a="
=the plain gold ring=

$ IFS=$' \t\n' read a b c <<< 'the plain gold ring'
$ echo "=$c="
=gold ring=

$ IFS=$' \t\n' read a b c <<< 'the    plain gold      ring'
$ echo "=$a= =$b= =$c="
=the= =plain= =gold      ring=

اولین مثال بالا فقدان تجزیه را درموقع تهی بودن متغیر IFS نشان می‌دهد. دومی نشان می‌دهد که آخرین نام متغیری که به فرمان read داده شده، باقیمانده کلمات ورودی را جذب می‌کند. سومی نشان می‌دهد، که وقتی فیلدهای اضافه به آخرین متغیر اختصاص داده ‌شود، تجزیه و یکی نمودن جداکننده‌ها روی قسمت باقیمانده سطر انجام نمی‌شود.

$ IFS=: read a b c <<< '1:2:::3::4'
$ echo "=$a= =$b= =$c="
=1= =2= =::3::4=

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

IFS=:
set -f
for dir in $PATH; do
   ...
done
set +f
unset IFS

این مثال روی تمام عناصر جدا شده با کولن متغیر PATH تکرار می‌کند، احتمالاً برای یافتن یک فرمان. این یک نمونه فوق‌العاده ساده شده است، اما به نمایش آن که چطور ممکن است IFS برای کنترل تفکیک کلمه به کار رود، خدمت می‌کند. برای راهکار مناسب‌تری جهت پیدا کردن دستورات FAQ شماره 81 را ببینید.

یادداشت ویژه

در باره رفتار ‎$*‎ در برابر ‎"$*"‎ ( و به طور قابل مقایسه،‎ ${array[*]}‎ و ‎${!prefix*}‎)، متغیر IFS در هر دو شکل نقل‌قولی و غیرنقل‌قولی استفاده می‌شود، اما در شکل غیر نقل‌قولی بی‌فایده می‌شود. ملاحظه کنید:

$ set -- one two three
$ IFS=+
$ echo $*
one two three

در اینجا واقعاً چه اتفاقی می‌افتد؟ در نگاه اول، اینطور دیده می‌شود که ‎$*‎ لیستی ار کلمات بدون هرگونه جداکننده‌ای تولید کرده است، و echo فاصله‌ای بین آنها قرار داده است.

اما اینظور نیست. ‎$*‎ یک رشته منفرد شامل جداکننده IFS تعیین شده ما در بین عناصر آن، تولید نموده است، سپس به علت آنکه نقل‌قولی نشده، قبل از آنکه echo آنرا تحویل بگیرد، تجزیه به کلمات صورت گرفته.

$ tmp=$*
$ echo "$tmp"
one+two+three

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

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

باز هم دلیل دیگری است برای آنکه چرا باید بیشتر از نقل‌قولها استفاده کنید!

توضیح مترجم: مثال اخیر را به این شکل بازنویسی می‌کنم که مطلب کاملاً روشن بشود.

$ set -- one two three
$ IFS=+
$ tmp=$*
$ echo "$tmp"    #  نقل‌قولی 
one+two+three    #  بدون تفکیک کلمه، محتوای واقعی متغیر(با جداکننده) چاپ شده 
$
$ echo $tmp      #  غیر نقل‌قولی 
one two three    #  جداکننده در اثر تفکیک کلمه غایب شده 
$


  • IFS (آخرین ویرایش ‎2010-08-10 16:11:21‎ توسط GreyCat)