IFS چیست؟
سلام
وقتی از دستور cut برای جدا کردن fieldها استفاده میکنیم معمولاً با استفاده از آپشن d کاراکتری که با استفاده از اون فیلدها از هم جدا شدن رو مشخص میکنیم. برای مثال دستور زیر بدون استفاده از آپشن d تلاش میکنه فیلد سوّم خروجی دستور grep رو پیدا کنه:
1 2 |
$ grep -i vahit /etc/passwd | cut -f3 vahit:x:1000:1000::/home/vahit:/usr/bin/zsh |
که خب نتیجهی اون کل خط هست. در عوض در دستور زیر با استفاده از آپشن d کاراکتر : به عنوان جدا کنندهی فیلدها معرفی شده. در نتیجه دستور cut از اون برای تشخیص حد و حدود فیلدها استفاده میکنه:
1 2 |
$ grep -i vahit /etc/passwd | cut -f6 -d":" /home/vahit |
وقتهایی هست که نمیتونیم مشخص کنیم که شل از چه کاراکتری برای تشخیص حد و حدود فیلدها استفاده بکنه یا اگر راهی وجود داره معمولاً سخت و پیچیده هست. برای همین موقع اجرای شل یک متغیر به اسم IFS مقداردهی میشه که برابر میشه با مقدار پیشفرض مورد استفاده برای این کار. IFS تشکیل شده از سرواژهی کلمات Interval Field Separator هست و مقدار پیشفرض اون برابر کاراکترهای فاصلهتبخطجدید (<space><tab><newline>) هست و هر یک(۱) از اونها که وجود داشته باشن مشخص کنندهی پایان حد فیلد قبلی و شروع حد فیلد بعدی خواهد بود. یکی از مهمترین موارد استفادهی این متغیر حلقهها (for, while) هستن. برای مثال:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 |
$ 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 باشه چی؟! طبیعتاً اونها هم لحاظ میشن! برای مثال:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
$ 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 قرار میدیم تا دیگه از پردازش فاصله و تب جلوگیری کنیم.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
$ 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 اجرا کرده و تفاوتهای اون رو ببینید!!