راهنمای آموزشی اسکریپت نویسی - مقدماتی

لطفا برای بهتر دیدن صفحه از firefox استفاده کنید
Bash Guide for Beginners Machtelt Garrels

راهنمای Bash برای نوآموزان

تمرین ها »
« کاربردهای پیشرفته تر if

فصل 7. دستورات شرطی

فهرست مطالب

معرفی if
کلیات
کاربردهای ساده if
استفاده پیشرفته‌تر if
ساختارهای ‎if/then/else ‎
ساختارهای ‎if/then/elif/else‎
جملات تو در تو
عملگرهای منطقی
کاربرد دستور exit و if
کاربرد جملات case
شرط‌های ساده شده
مثال Initscript
خلاصه
تمرین‌ها

چکیده

در این فصل در باره استفاده از شرط‌ها در اسکریپت‌های Bash صحبت می‌کنیم. این صحبت مباحث زیر را شامل می‌شود:

  • دستور if

  • کاربرد وضعیت‌های خروج یک فرمان

  • مقایسه و بررسی ورودی و فایل‌ها

  • ساختارهای ‎if/then/else‎

  • ساختارهای ‎if/then/elif/else‎

  • کاربرد پارامترهای موقعیتی

  • دستورات if تو در تو

  • عبارت‌های منطقی

  • کاربرد جملات case

مقدمه‌ای بر if

کلیات

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

فشرده‌ترین ترکیب دستور if چنین است:

if TEST-COMMANDS; then CONSEQUENT-COMMANDS; fi

لیست TEST-COMMAND اجرا می‌شود، و اگر کد برگشتی آن صفر باشد، لیست CONSEQUENT-COMMANDS اجرا می‌شود. کد برگشتی، وضعیت خروج آخرین فرمان اجرا شده است، یا در صورتیکه نتیجه بررسی شرط صحیح باشد صفر است.

لیست TEST-COMMAND اغلب بررسی‌های مقایسه‌ای عددی یا رشته‌ای را در بر می‌گیرد، اما می‌تواند هر دستوری نیز باشد، که در صورت اجرای موفق کد صفر و در صورت شکست برخی کدهای وضعیت دیگر را بازگرداند. غالباً عبارت‌های یکانی برای آزمودن وضعیت یک فایل استفاده می‌شود. اگر شناسه FILE به یکی از شکل‌های اصلی ‎ /dev/fd/N‎ باشد، آن‌وقت توصیف‌گر فایل شماره “N” کنترل می‌شود. stdin، stdout و stderr و توصیف‌گرهای مربوطه آنها نیز می‌توانند برای بررسی‌ها استفاده شوند.

عبارت‌های استفاده شده با if

جدول زیر شامل خلاصه‌ ای از “ورودی‌های” شناخته شده که دستور یا لیست دستورات TEST-COMMAND را تشکیل می‌دهند، می‌باشد. این ورودی‌ها برای نشان دادن آن‌که عبارت شرطی هستند در کروشه‌ها قرار دارند.

جدول  7.1: عبارت‌های ورودی

ورودیمعنی
[ -a FILE ]اگر FILE موجود باشد صحیح است.
[ -b FILE ]اگر FILE موجود و از نوع ویژه فایل بلوکی باشد، صحیح است.
[ -c FILE ]اگر FILE موجود و فایل ویژه کاراکتری باشد، صحیح است.
[ -d FILE ]اگر FILE وجود داشته باشد و از نوع دایرکتوری باشد، صحیح است.
[ -e FILE ]در صورتیکه FILE وجود داشته باشد، صحیح است.
[ -f FILE ]اگر FILE موجود و یک فایل معمولی باشد، صحیح است.
[ -g FILE ]در صورتیکه FILE وجود داشته باشد و بیت SGID آن تنظیم شده باشد، صحیح است.
[ -h FILE ]اگر FILE موجود باشد و یک پیوند نمادین باشد، صحیح است.
[ -k FILE ] اگر FILE وجود داسته باشد و بیت sticky آن تنظیم شده باشد، صحیح است.
[ -p FILE ]اگر FILE موجود و یک لوله نامیده شده(FIFO) باشد، صحیح است.
[ -r FILE ]اگر FILE وجود داشته باشد و خواندنی باشد، صحیح است.
[ -s FILE ]اگر FILE موجود و اندازه بزرگتر از صفر داشته باشد، صحیح است.
[ -t FD ]اگر توصیف‌گر فایل FD باز است و به یک ترمینال رجوع می‌کند، صحیح است.
[ -u FILE ]اگر FILE وجود دارد و بیت SUID(تنظیم ID کاربر ) تنظیم شده، صحیح است.
[ -w FILE ]صحیح است اگر FILE وجود دارد و قابل نوشتن است.
[ -x FILE ]اگر FILE وجود دارد و اجرایی است، صحیح است.
[ -O FILE ]اگر FILE وجود دارد و یک مالک از طریق شماره شناسایی مؤثر کاربر دارد، صحیح است.
[ -G FILE ]اگر FILE وجود دارد و از طریق یک شماره شناسایی مؤثر گروه در مالکیت است، صحیح می‌باشد.
[ -L FILE ]اگر FILE وجود دارد و یک لینک نمادین است،صحیح می‌باشد.
[ -N FILE ]اگر FILE وجود دارد و بعد از آخرین باری که خوانده شده ویرایش شده است، صحیح می‌باشد.
[ -S FILE ]اگر FILE وجود دارد و از نوع فایل سوکت می‌باشد، صحیح است.
[ FILE1 -nt FILE2 ]اگر FILE1 تازه‌تر از FILE2 ویرایش شده است، یااگر FILE1 وجود دارد و FILE2 موجود نیست، صحیح می‌باشد.
[ FILE1 -ot FILE2 ]اگر FILE1 قدیمی‌تر از FILE2 است، یا اگر FILE2 وجود دارد و FILE1 موجود نیست، صحیح می‌باشد.
[ FILE1 -ef FILE2 ]اگر FILE1 و FILE2 هر دو به یک دستگاه و شماره inode ارجاع می‌کنند، صحیح است.
[ -o OPTIONNAME ]اگر گزینه شل “OPTIONNAME” فعال شده است، صحیح است.
[ -z STRING ]اگر طول “STRING” صفر باشد، صحیح است.
[ -n STRING ] or [ STRING ]اگر طول “STRING” صفر نیست، صحیح می‌باشد.
[ STRING1 == STRING2 ] اگر رشته‌ها یکسان هستند، صحیح است. برای سازگاری دقیق با ممکن است ازPOSIX“=” به جای “==” استفاده شود.
[ STRING1 != STRING2 ] اگر رشته‌ها یکسان نباشند، صحیح است.
[ STRING1 < STRING2 ] اگر “STRING1” در ترتیب دیکشنری منطقه جاری قبل از “STRING2” قرار دارد، صحیح است.
[ STRING1 > STRING2 ] اگر “STRING1” در ترتیب دیکشنری منطقه جاری بعداز “STRING2” قرار دارد، صحیح است.
[ ARG1 OP ARG2 ]“OP” یکی از عملگرهای ‎ -eq‎، ‎ -ne‎، ‎ -lt‎، ‎ -le‎، ‎ -gt‎، ‎-ge‎ است. این عملگرهای باینری محاسباتی در صورتیکه “ARG1” به ترتیب از چپ به راست، مساوی با، نامساوی با،کوچکتر از، کوچکتر یا مساوی با، بزرگتر از، بزرگتر یا مساوی با، “ARG2” باشد، مقدار صحیح را برمی‌گردانند. “ARG1” و “ARG2” کمیت‌های صحیح می‌باشند.

عبارت‌ها می‌توانند با استفاده از عملگرهای زیر که با ترتیب کاهش اولویت لیست شده‌اند، با هم ترکیب شوند:

جدول 7.2: ترکیب عبارت‌ها

عملگرنتیجه
[ ! EXPR ]اگر EXPR غلط باشد، صحیح است.
[ ( EXPR ) ]مقدار EXPR را برمی‌گرداند. این می‌تواند برای ابطال اولویت معمولی عملگرها به کار برود.
[ EXPR1 -a EXPR2 ]اگر هر دوی EXPR1 و EXPR2 صحیح باشند، صحیح است.
[ EXPR1 -o EXPR2 ]در صورتیکه هر کدام از EXPR1 یا EXPR2 صحیح باشند، صحیح است.

فرمان داخلی ‎[‎ (یا test) با استفاده از یک مجموعه قواعدبر اساس تعداد شناسه‌ها، عبارت‌های شرطی را ارزیابی می‌کند. اطلاعات بیشتر در باره این موضوع را می‌توانید در مستندات Bash پیدا کنید. درست مثل if که با fi بسته می‌شود، کروشه باز باید پس از آن که شرط‌ها لیست شده‌اند با علامت برعکس آن بسته شود.

فرمان‌های پس از جمله then

لیست CONSEQUENT-COMMANDS که به دنبال جمله then آمده می‌تواند هر دستور معتبر یونیکس ، هر برنامه اجرایی، هر اسکریپت اجرایی پوسته، یا هر دستور پوسته، به استثنای بستن با fi باشد. این اهمیت دارد که به خاطر بسپارید که then و fi در پوسته به عنوان جملاتی که باید جدا از یکدیگر باشند درنظر گرفته شده‌اند. بنابراین، موقعی که در خط‌فرمان صادر می‌شوند باید با کاراکتر سمی‌کالن جدا شوند.

در یک اسکریپت، بخش‌های مختلف دستور if معمولاً به‌خوبی جدا می‌شوند. در این‌جا یک جفت مثال ساده.

کنترل فایل‌ها

مثال اول وجود یک فایل را بررسی می‌کند:

anny ~> cat msgcheck.sh
#!/bin/bash

echo "This scripts checks the existence of the messages file."
echo "Checking..."
if [ -f /var/log/messages ]
  then
    echo "/var/log/messages exists."
fi
echo
echo "...done."

anny ~> ./msgcheck.sh
This scripts checks the existence of the messages file.
Checking...
/var/log/messages exists.

...done.

بررسی گزینه‌های شل

برای افزودن به فایل‌های پیکربندی Bash خودتان:

# These lines will print a message if the noclobber option is set:

if [ -o noclobber ]
  then
	echo "Your files are protected against accidental overwriting using redirection."
fi


[Note]محیط

مثال فوق وقتی در خط‌فرمان وارد شود نیز کار خواهد کرد:

anny ~> if [ -o noclobber ] ; then echo ; echo "your files are protected
against overwriting." ; echo ; fi

your files are protected against overwriting.

anny ~>

هرچند که، اگر شرط‌هایی که وابسته به محیط هستند را بررسی می‌کنید، ممکن است موقع اجرا در اسکریپت و یا خط‌فرمان نتایج متفاوتی به‌دست آورید، چرا که اسکریپت یک پوسته جدید را باز می‌کند، که ممکن است در آن متغیرها و گزینه‌های مورد انتظار به طور خودکار برقرار نگردند,.

کاربردهای ساده if

بررسی وضعیت خروج

متغیر ? وضعیت خروج فرمان اجرا شده قبلی ( آخرین پردازش کامل شده پیش‌زمینه ) را در خود نگاه می‌دارد.

مثال زیر یک بررسی ساده را نشان می‌دهد:

anny ~> if [ $? -eq 0 ]
More input> then echo 'That was a good job!'
More input> fi
That was a good job!

anny ~>

مثال زیر نشان می‌دهد که TEST-COMMANDS می‌تواند هر فرمان یونیکسی که یک کد وضعیت خروج برمی‌گرداند،باشد، و آن if دوباره یک کد وضعیت صفر برمی‌گرداند:

anny ~> if ! grep $USER /etc/passwd
More input> then echo "your user account is not managed locally"; fi
your user account is not managed locally

anny > echo $?
0

anny >

همین نتیجه به طریق زیر نیز می‌تواند حاصل گردد:

anny > grep $USER /etc/passwd

anny > if [ $? -ne 0 ] ; then echo "not a local account" ; fi
not a local account

anny >

مقایسه‌های عددی

مثال زیر مقایسه‌های عددی را به کار می‌برد:

anny > num=`wc -l work.txt`

anny > echo $num
201

anny > if [ "$num" -gt "150" ]
More input> then echo ; echo "you've worked hard enough for today."
More input> echo ; fi

you've worked hard enough for today.


anny >

این اسکریپت توسط cron هر یکشنبه اجرا می‌شود. اگر عدد هفته زوج باشد، یادآوری می‌کند که سطل زباله را بیرون بگذارید:

#!/bin/bash

# Calculate the week number using the date command:

WEEKOFFSET=$[ $(date +"%V") % 2 ]

# Test if we have a remainder.  If not, this is an even week so send a message.
# Else, do nothing.

if [ $WEEKOFFSET -eq "0" ]; then
  echo "Sunday evening, put out the garbage cans." | mail -s "Garbage cans out" your@your_domain.org
fi

مقایسه‌های رشته‌ای

یک مثال از مقایسه رشته‌ها برای بررسی ID:کاربر

if [ "$(whoami)" != 'root' ]; then
        echo "You have no permission to run $0 as non-root user."
        exit 1;
fi

در Bash، می‌توانید این ساختار را کوتاه کنید. معادل فشرده مثال فوق به صورت زیر می‌باشد:

[ "$(whoami)" != 'root' ] && ( echo you are using a non-privileged account; exit 1 )

مشابه عبارت “&&” که اشاره می‌کند اگر نتیجه بررسی صحیح باشد چه‌کاری انجام شود، و“||” که تعیین می‌کند اگر نتیجه غلط بود چه کاری انجام شود.

عبارت‌های منظم نیز در مقایسه‌ها می‌توانند به کار روند:

anny > gender="female"

anny > if [[ "$gender" == f* ]]
More input> then echo "Pleasure to meet you, Madame."; fi
Pleasure to meet you, Madame.

anny >

[Note]برنامه‌نویسان حقیقی

اکثر برنامه‌نویسان ترجیح می‌دهند دستور داخلی test را یه کار ببرند، که معادل کروشه‌ها برای مقایسه هستند، مانند این:

test "$(whoami)" != 'root' && (echo you are using a non-privileged account; exit 1)
[Note]خارج نشود؟

اگر در یک زیرپوسته exit را فراخوانی کنید، متغیرها را به پوسته والد عبور نمی‌دهد. اگر می‌حواهید Bash به یک زیرپوسته ابشعاب نکنداز ‎ { and }‎ به جای ‎ ( and ) ‎ استفاده کنید.

صفحه‌های info از Bash را برای انطباق الگو با ساختارهای ‎ “(( EXPRESSION ))”‎ و ‎“[[ EXPRESSION ]]”‎ جهت اطلاعات بیشتر ملاحظه کنید.

تمرین ها »
« کاربردهای پیشرفته تر if
ترجمه محمود پهلوانی