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

IFS چیست؟

سلام

وقتی از دستور cut برای جدا کردن fieldها استفاده می‌کنیم معمولاً با استفاده از آپشن d کاراکتری که با استفاده از اون فیلد‌ها از هم جدا شدن رو مشخص می‌کنیم. برای مثال دستور زیر بدون استفاده از آپشن d تلاش می‌کنه فیلد سوّم خروجی دستور grep رو پیدا کنه:

$ grep -i vahit /etc/passwd | cut -f3
vahit:x:1000:1000::/home/vahit:/usr/bin/zsh

که خب نتیجه‌ی اون کل خط هست. در عوض در دستور زیر با استفاده از آپشن d کاراکتر : به عنوان جدا کننده‌ی فیلد‌ها معرفی شده. در نتیجه دستور cut از اون برای تشخیص حد و حدود فیلد‌ها استفاده می‌کنه:

$ grep -i vahit /etc/passwd | cut -f6 -d":"
/home/vahit

وقت‌هایی هست که نمی‌تونیم مشخص کنیم که شل از چه کاراکتری برای تشخیص حد و حدود فیلد‌ها استفاده بکنه یا اگر راهی وجود داره معمولاً سخت و پیچیده هست. برای همین موقع اجرای شل یک متغیر به اسم IFS مقداردهی می‌شه که برابر می‌شه با مقدار پیش‌فرض مورد استفاده برای این کار. IFS تشکیل شده از سرواژه‌ی کلمات Interval Field Separator هست و مقدار پیش‌فرض اون برابر  کاراکترهای فاصله‌تب‌خط‌جدید (<space><tab><newline>) هست و هر یک(۱) از اونها که وجود داشته باشن مشخص کننده‌ی پایان حد فیلد قبلی و شروع حد فیلد بعدی خواهد بود. یکی از مهمترین موارد استفاده‌ی این متغیر حلقه‌ها (for, while) هستن. برای مثال:

$ for each_dir in $(ls /); do
for> echo $each_dir
for> done
bin
boot
dev
etc
home
lib
lib64
lost+found
media
mnt
opt
proc
root
run
sbin
srv
swapfile
sys
tmp
usr
var

خب ظاهراً همه چیز خوب و روبه‌راه هست و دستور for از کاراکتر newline موجود توی IFS برای جدا کردن فیلد‌های دستور ls استفاده کرده. امّا اگر اسم یکی از فایل‌ها یا دایرکتوری موجود شامل کاراکتر‌های دیگه‌ی موجود توی IFS باشه چی؟! طبیعتاً اونها هم لحاظ می‌شن! برای مثال:

$ ls 
'test diri'  'test dirii'  'test diriii'  'test diriv'

$ for each_dir in $(ls); do
for> echo "==>" $each_dir
for> done
==> test
==> diri
==> test
==> dirii
==> test
==> diriii
==> test
==> diriv

می‌بینید، کل خروجی دستور به هم ریخت. حالا فرض کنید اگر بخوایم این بلوک رو داخل یک اسکریپت بزرگتر استفاده کنیم چه افتضاحی به بار میاد؟!!

خب گفتیم IFS یک متغیر هست پس می‌شه مقدارش رو عوض کرده و مشکل رو حل کرد. برای اینکار اوّل از همه یک پشتیبان از مقدار پیش‌فرض IFS می‌گیریم تا بعداً از اون برای مقداردهی صحیح IFS استفاده کنیم. سپس مقدار IFS رو برابر کاراکتر newline قرار می‌دیم تا دیگه از پردازش فاصله و تب جلوگیری کنیم.

$ OLDIFS=$IFS

$ IFS=$(echo -ne "\n\b")



$ for each_dir in $(ls); do
for> echo "===> "\""$each_dir"\""
for> done
===> "test diri"
===> "test dirii"
===> "test diriii"
===> "test diriv"

$ IFS=$OLDIFS

(۱) برای اطمینان از این مورد می‌تونید دستور ls رو با آپشن‌های مختلفی از جمله ‪-1‬ اجرا کرده و تفاوت‌های اون رو ببینید!!

 



برچسب ها : , , ,