خط فرمان لینوکس

ترجمه فارسی LinuxCommand.org

خط فرمان لینوکس

ترجمه فارسی LinuxCommand.org

کنترل جریان - بخش 3

کنترل جریان - بخش 3

اکنون که در باره پارامترهای مکانی آموخته‌اید، وقت آن است که دستورالعمل باقیمانده کنترل جریان را پوشش بدهیم، 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"‎ به متغیر i تخصیص داده می‌شود، سپس جمله ‎echo $i‎ اجرا می‌گردد، آنوقت به متغیر i رشته ‎"word2"‎ تخصیص داده می‌شود، و جمله ‎echo $i‎ اجرا می‌شود، و به همین ترتیب، تا تمام کلماتِ فهرست تخصیص یافته باشند.

مطلب جالب در باره 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 معرفی می‌کند، که برای تولید خروجی قالب‌بندی شده مطابق یک قالب رشته به کار می‌رود. printf از زبان برنامه‌نویسی C شروع شده و در بسیاری زبانهای برنامه‌نویسی دیگر از جمله ‎C++‎‏، Perl‏، awk‏، java‏، PHP، و البته، bash پیاده سازی گردیده است. در باره قالب‌های رشته 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 شامل نام فروشنده و نگارش توزیع هستند. آنها در دایرکتوری ‎/etc‎ قرار داده می‌شوند. برای یافتن آنها، ما یک فرمان ls اجرا می‌کنیم و تمام خروجی‌اش را دور می‌اندازیم. فقط وضعیت خروج را می‌خواهیم. که اگر فایلی پیدا شده باشد صحیح خواهد بود.

بعد، ما HTML برای این قسمت از صفحه را ایجاد می‌کنیم، چون اکنون می‌دانیم که فایلهای release برای پردازش وجود دارند. برای پردازش فایلها، یک حلقه for را جهت عمل کردن روی هر کدام آغاز می‌نماییم. در داخل حلقه، ما از فرمان head برای باز گرداندن سطر اول هر فایل استفاده می‌کنیم.

سرانجام، فرمان uname را با گزینه‌های ‎"o"‎‏، ‎"r"‎، و ‎"p"‎ جهت به دست آوردن برخی اطلاعات اضافی سیستم به کار می‌بریم.