اکنون که در باره پارامترهای مکانی آموختهاید، وقت آن است که دستورالعمل باقیمانده کنترل جریان را پوشش بدهیم، for. مانند while و until، از for نیز برای ساختن حلقهها استفاده میشود. for به این شکل کار میکند:
for variable in words; do commands done
در اصل، for یک کلمه از فهرست کلمات را به متغییر مشخص شده تخصیص میدهد، و این کار را بارها و بارها تکرار میکند تا تمام کلمات مصرف بشوند. این هم یک مثال:
#!/bin/bash for i in word1 word2 word3; do echo $i done
در این مثال، رشته "word1" به متغیر
مطلب جالب در باره for روشهای بسیاری است که شما میتوانید فهرست کلمات را بسازید. تمام انواع بسطها میتوانند به کار بروند. در مثال بعدی، ما با استفاده از جایگزینی فرمان فهرستی از کلمات تشکیل میدهیم:
#!/bin/bash count=0 for i in $(cat ~/.bash_profile); do count=$((count + 1)) echo "Word $count ($i) contains $(echo -n $i | wc -c) characters" done
در اینجا فایل .bash_profile را گرفته و تعداد کلمات در فایل و تعداد کاراکترهای هر کلمه را شمارش میکنیم.
بنابراین از پارامترهای مکانی چه استفادهای میکنیم؟ خیلی خوب، یکی از ویژگیهای for آن است که میتواند پارامترهای مکانی را به عنوان فهرست کلمات به کار ببرد:
#!/bin/bash for i in "$@"; do echo $i done
متغیر پوسته "
#!/bin/bash for filename in "$@"; do result= if [ -f "$filename" ]; then result="$filename is a regular file" else if [ -d "$filename" ]; then result="$filename is a directory" fi fi if [ -w "$filename" ]; then result="$result and it is writable" else result="$result and it is not writable" fi echo "$result" done
این اسکریپت را آزمایش کنید. برای دیدن آنکه کار میکند لیستی از فایلها یا یک کاراکتر عام مانند "
این هم یک نمونه اسکریپت دیگر. این یکی فایلهای داخل دو دایرکتوری را مقایسه میکند و فایلهایی از دایرکتوری اول را که در دایرکتوری دوم وجود ندارند لیست میکند.
#!/bin/bash # cmp_dir - برنامهای برای مقایسه دو دایرکتوری # بررسی شناسههای مورد نیاز if [ $# -ne 2 ]; then echo "usage: $0 directory_1 directory_2" 1>&2 exit 1 fi # کسب اطمینان برای آنکه هر دو شناسه دایرکتوری باشند if [ ! -d $1 ]; then echo "$1 is not a directory!" 1>&2 exit 1 fi if [ ! -d $2 ]; then echo "$2 is not a directory!" 1>&2 exit 1 fi # directory_2 و مقایسه آن با directory_1 پردازش هر فایل در missing=0 for filename in $1/*; do fn=$(basename "$filename") if [ -f "$filename" ]; then if [ ! -f "$2/$fn" ]; then echo "$fn is missing from $2" missing=$((missing + 1)) fi fi done echo "$missing files missing"
اکنون ما در جهت کار واقعی میخواهیم تابع home_space در اسکریپتمان را برای بیرون دادن اطلاعات بیشتر بهینهسازی کنیم. به یاد میآورید که نگارش قبلی چیزی مانند این بود:
home_space() { # فقط کاربر ارشد میتواند این اطلاعات را به دست بیاورد if [ "$(id -u)" = "0" ]; then echo "<h2>Home directory space by user</h2>" echo "<pre>" echo "Bytes Directory" du -s /home/* | sort -nr echo "</pre>" fi } # home_space پایان تابع
این هم نگارش جدید:
home_space() { echo "<h2>Home directory space by user</h2>" echo "<pre>" format="%8s%10s%10s %-s\n" printf "$format" "Dirs" "Files" "Blocks" "Directory" printf "$format" "----" "-----" "------" "---------" if [ $(id -u) = "0" ]; then dir_list="/home/*" else dir_list=$HOME fi for home_dir in $dir_list; do total_dirs=$(find $home_dir -type d | wc -l) total_files=$(find $home_dir -type f | wc -l) total_blocks=$(du -s $home_dir) printf "$format" $total_dirs $total_files $total_blocks done echo "</pre>" } # home_space پایان تابع
این نگارش بهینهسازی شده یک فرمان جدید printf معرفی میکند، که برای تولید خروجی قالببندی شده مطابق یک
همچنین فرمان find را معرفی میکنیم. find برای جستجوی فایلها یا دایرکتوریهایی که با ضوابط معینی مطابقت دارند به کار میرود. در تابع home_space، ما فرمان find را برای لیست کردن دایرکتوریها و فایلهای معمولی در هر دایرکتوری خانگی به کار میبریم. با استفاده از فرمان wc، تعداد فایلها و دایرکتوریهای یافت شده را شمارش میکنیم.
مورد واقعاً جالب در باره home_space چگونگی رسیدگی کردن به مشکل دستیابی کاربر ارشد است. شما توجه خواهید داشت که ما با id برای کاربر ارشد بررسی میکنیم و مطابق خروجی از تست، رشتههای متفاوتی به متغیر dir_list تخصیص میدهیم، که لیست کلمات برای حلقه for متعاقب آن میگردند. به این طریق، اگر یک کاربر دلخواه اسکریپت را اجرا کند، تنها دایرکتوری خانگی او لیست خواهد گردید.
یک تابع دیگر که میتواند از یک حلقه for استفاده کند، تابع ناتمام system_info ما است. میتوانیم آن را به این شکل بسازیم:
system_info() { # /etc در release پیدا کردن هر فایل if ls /etc/*release 1>/dev/null 2>&1; then echo "<h2>System release info</h2>" echo "<pre>" for i in /etc/*release; do # ،چون نمیتوانیم از طول فایل مطمئن باشیم # .فقط سطر اول را نمایش میدهیم head -n 1 $i done uname -orp echo "</pre>" fi } # system_info پایان تابع
در این تابع، ما نخست تعیین میکنیم که آیا هیچ فایل release برای پردازش وجود دارد. فایلهای release شامل نام فروشنده و نگارش توزیع هستند. آنها در دایرکتوری
بعد، ما HTML برای این قسمت از صفحه را ایجاد میکنیم، چون اکنون میدانیم که فایلهای release برای پردازش وجود دارند. برای پردازش فایلها، یک حلقه for را جهت عمل کردن روی هر کدام آغاز مینماییم. در داخل حلقه، ما از فرمان head برای باز گرداندن سطر اول هر فایل استفاده میکنیم.
سرانجام، فرمان uname را با گزینههای "