مقدمة إلى if في Bash

من موسوعة حسوب

قد تحتاج إلى تحديد سلاسل إجراءات مختلفة داخل برامج الصدفة (shell scripts) بناءً على نجاح تنفيذ أمر أو فشله، وتأتي أداة if الشرطية من أجل مثل تلك الحالات، وأصغر بنية لغوية لأمر if هي التالية:

if TEST-COMMANDS; then CONSEQUENT-COMMANDS; fi

تُنفَّذ قائمة أوامر الاختبار TEST-COMMANDS، ثم تُنفَّذ قائمة الأوامر التابعة CONSEQUENT-COMMANDS إن كانت حالة الإعادة لها هي صفر. وتكون حالة الإعادة هي حالة خروج آخر أمر تم تنفيذه، أو تكون صفرًا إن لم تتحقق أي حالة من أوامر الاختبار.

يتضمن أمر الاختبار TEST-COMMAND في الغالب اختبارات مقارنات عددية أو نصية، لكن هذا لا يمنع أنه قد يكون أي أمر يُعيد حالة صفرية إذا نجح وحالة أخرى عند فشله، وتُستخدم التعبيرات الأحادية (Unary Expressions) في الغالب لاختبار حالة ملف ما، فإن كان وسيط FILE لأحد الأساسيات (primaries) على صيغة dev/fd/N فيُتفقَّد واصف الملف N. كذلك قد تُستخدم ملفات stdin و stdout وstderr وواصفات الملفات الخاصة بها -على الترتيب- في تلك الاختبارات.

التعابير المستخدمة مع if

يشتمل الجدول التالي على ملخص لما يسمى بالأساسيات التي تكوِّن أمر الاختبار TEST-COMMAND أو قائمة أوامر الاختبار في بنية if الشرطية، وتوضع هذه الأساسيات بين أقواس مربعة لبيان اختبار التعبير الشرطي.

جدول 7.1: التعابير الأساسية

التعبير الأساسي المعنى
[ a FILE-] صحيح إن كان FILE موجودًا
[ b FILE-] صحيح إن كان FILE موجودًا وكان ملفًا من نوع block-special.
[ c FILE-] صحيح إن كان FILE موجودًا وكان ملفًا من نوع character-special.
[ d FILE-] صحيح إن كان FILE موجودًا وكان مجلدًا.
[ e FILE-] صحيح إن كان FILE موجودًا.
[ f FILE-] صحيح إن كان FILE موجودًا وكان ملفًا عاديًا.
[ g FILE-] صحيح إن كان FILE موجودًا وضُبِط بِتّ SGID فيه.
[ h FILE-] صحيح إن كان FILE موجودًا وكان رابطًا رمزيًا (symbolic link)
[ k FILE-] صحيح إن كان FILE موجودًا وضُبط البِتّ اللزج (sticky bit) فيها.
[ p FILE-] صحيح إن كان FILE موجودًا وكان أنبوبًا مُسمَّى (FIFO).
[ r FILE-] صحيح إن كان FILE موجودًا ويمكن قراءته (Readable).
[ s FILE-] صحيح إن كان FILE موجودًا وحجمه أكبر من الصفر.
[ t FD-] صحيح إن كان واصف الملف FD مفتوحًا ويشير إلى الطرفية.
[ u FILE-] صحيح إن كان FILE موجودًا وضُبط بتّ SUID (ضبط معرِّف المستخدم Set User ID)
[ w FILE-] صحيح إن كان FILE موجودًا ويمكن الكتابة فيه (writable).
[ x FILE-] صحيح إن كان FILE موجودًا ويمكن تنفيذه (executable).
[ O FILE-] صحيح إن كان FILE موجودًا ويملكه معرِّف مستخدم فعَّال (effective user ID).
[ G FILE-] صحيح إن كان FILE موجودًا ويملكه معرِّف مجموعة فعَّال (effective group ID).
[ L FILE-] صحيح إن كان FILE موجودًا وكان رابطًا رمزيًا (symbolic link).
[ N FILE-] صحيح إن كان FILE موجودُا وحدثت فيه تعديلات بعد آخر مرة قُرأ فيها.
[ S FILE-] صحيح إن كان FILE موجودًا وكان مقبسًا (socket) -المقبس هو قناة لنقل بيانات تظهر كملف للبرنامج الذي يستخدمها-.
[ FILE1 -ntFILE2 ] صحيح إن تم تعديل FILE1 بعد FILE2، أو إن كان FILE1 موجودًا و FILE2 غير موجود.
[ FILE1 -otFILE2 ] صحيح إن كان FILE1 أقدم من FILE2، أو كان FILE2 موجودًا وFILE1 غير موجود.
[ FILE1 -ef FILE2 ] صحيح إن كان FILE1 و FILE2 يشيران إلى نفس أرقام الجهاز (device) ومؤشر الفهرسة (inode).
[ o OPTIONNAME- ] صحيح إن كان خيار OPTIONNAME مفعَّلًا.
[ z OPTIONNAME- ] صحيح إن كان طول STRING يساوي صفرًا.
[ n STRING- ] أو [ STRING ] صحيح إن كان طول STRING لا يساوي صفرًا.
[ STRING1 == STRING2 ] صحيح إن كانت المقاطع النصية (strings) متساوية. قد تُستخدم = بدلًا من == لضمان الالتزام بمعايير POSIX.
[ STRING1 != STRING2 ] صحيح إن كانت المقاطع النصية غير متساوية.
[ STRING1 < STRING2 ] صحيح إن صُنِّف STRING1 قبل STRING2 بشكل معجمي في الإعدادات المحلية الحالية.
[ STRING1 > STRING2 ] صحيح إن صُنِّف STRING1 بعد STRING2 بشكل معجمي في الإعدادات المحلية الحالية.
[ ARG1 OP ARG2 ] OP هو أحد المعامِلات الحسابية الثنائية التالية: eq- أو ne- أو lt- أو le- أو gt- أو ge-، وتعيد تلك المعامِلات حالة صحيحة (true) إن كان ARG1 يساوي، أو لا يساوي، أو أقل من، أو أقل من أو يساوي، أو أكبر من، أو أكبر من أو يساوي ARG2، على الترتيب. وARG1 و ARG2 هما أعداد صحيحة.

قد تُدمج التعابير باستخدام المعامِلات التالية مرتبة بأولوية تناقصية:

جدول 7.2: دمج التعابير

العملية الأثر
[ EXPR ! ] صحيح إن كان EXPR خطأ.
[ ( EXPR ) ] يعيد قيمة EXPR، قد يُستخدم هذا لإلغاء الأولوية الطبيعية للمعامِلات.
[ EXPR1 -a EXPR2 ] صحيح إن كان كل من EXPR1 و EXPR2 صحيحين.
[ EXPR1 -o EXPR2 ] صحيح إن كان EXPR1 صحيحًا أو كان EXPR2 صحيحًا، أحدهما يكفي.

يُقيِّم أمر ] (أو test) التعابير الشرطية باستخدام مجموعة من القواعد بناءً على عدد الوسائط (arguments)، ستجد مزيدًا من الشرح عن هذا في توثيق Bash. أيضًا، يجب أن يُغلق القوس المربع بعد سرد الشروط تمامًا مثلما يجب غلق if الشرطية بـ fi.

الأوامر التي تلي عبارة then

قد تكون الأوامر التابعة CONSEQUENT-COMMANDS التي تلي عبارة then أيّ أمر في نظام يونكس أو برنامج قابل للتنفيذ أو برنامج للصدفة (shell script) أو عبارة للصدفة (shell statement)، باستثناء عبارة fi الغالقة طبعًا. ربما يجب أن تتذكر أن then و fi هما عبارتين منفصلتيْن في الصدفة، لهذا فإنهما يُفصلان بفاصلة منقوطة ; عند كتابتهما في سطر الأوامر. كذلك فإنالأجزاء المختلفة من عبارة if داخل برنامج للصدفة تُفصَل جيدًا، ستجد بعض الأمثلة على ذلك فيما يلي.

فحص الملفات

يبحث المثال الأول في وجود ملف msgcheck.sh:

hsoub ~> 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."

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

...done.

فحص خيارات الصدفة

لإضافة ملفات إعدادات Bash الخاصة بك:

# noclobber ستطبع هذه الأسطر رسالة إن تم ضبط خيار:

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

البيئة

سيُنَفَّذ المثال السابق عند إدخاله في سطر الأوامر:

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

your files are protected against overwriting.

hsoub ~>

لكن إن استخدمت اختبار الشروط التي تعتمد على البيئة فقد تحصل على نتائج مختلفة حين تُدخل نفس الأمر في برنامج للصدفة (shell script)، ذلك أن البرنامج سيفتح صدفة جديدة قد لا تكون المتغيرات والخيارات مضبوطة تلقائيًا فيها.

تطبيقات بسيطة على عبارة if

اختبار حالة الخروج

يحتوي متغير ? على حالة الخروج للأمر الذي نُفِّذ سابقًا (آخر عملية تمت في الواجهة). يوضح المثال التالي اختبارًا بسيطًا:

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

hsoub ~>

أما هذا المثال فيوضح كيف أن TEST-COMMANDقد يكون أي أمر يونكس يعيد حالة خروج، وأن عبارة if تعيد مرة أخرى حالة خروج صفرية:

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

hsoub > echo $?
0

hsoub >

يمكن الحصول على نفس النتيجة كما يلي:

hsoub > grep $USER /etc/passwd

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

hsoub >

المقارنات العددية

الأمثلة أدناه تستخدم مقارنات عددية:

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

hsoub > echo $num
201

hsoub > 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.

hsoub >

تنفَّذ هذه الشيفرة بأداة cron كل يوم أحد، وترسل لك رسالة تذكير بإخراج سلات القمامة حتى لو كان رقم الأسبوع زوجيًا:

#!/bin/bash

# date احسب رقم الأسبوع باستخدام أمر:

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

# تنظر العبارة الشرطية إن كان لدينا تذكير، فإن لم يكن فإن الأسبوع يكون زوجيًا، فترسل لنا رسالة
# في حالة أي نتيجة أخرى، لا تفعل العبارة شيئًا.

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

المقارنات النصية

إليك مثالًا على مقارنة النصوص لاختبار معرِّف المستخدم:

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 )

يحدد تعبير || ما يجب فعله إن كان الاختبار خطأً، تمامًا مثل تعبير && الذي يوضح ما يجب فعله إن كان الاختبار صحيحًا. كذلك، يمكن استخدام التعابير النمطية في المقارنات:

hsoub > gender="male"

hsoub > if [[ "$gender" == m* ]]
More input> then echo "Pleasure to meet you, Sir."; fi
Pleasure to meet you, Sir.

hsoub >

المبرمجون الحقيقيون

يفضِّل أغلب المبرمجين استخدام أمر test الذي يساوي استخدام الأقواس المربعة للمقارنة، انظر المثال التالي:

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

أمر exit

إن استدعيت أمر exit في صدفة فرعية فلن يمرر المتغيرات إلى الصدفة الأم، فاستخدم { و } بدلًا من ( و ) إن كنت لا تريد أن تفتح Bash صدفة فرعية.

انظر صفحات دليل info للمزيد من المعلومات عن مطابقة الأنماط باستخدام بُنى (( EXPRESSION )) و [[ EXPRESSION ]].

انظر أيضًا

مصادر