المسارات
/
Bash
Bash
/
المنهج
/
خطوط الأنابيب وقوائم الأوامر
خط

خطوط الأنابيب وقوائم الأوامر في Bash

{zero: "لا توجد تمارين", one: "1 تمرين", two: "تمرينان", few: "%{count} تمارين", many: "%{count} تمرينًا", other: "%{count} تمرين"}

نبذة عن خطوط الأنابيب وقوائم الأوامر

رأينا كيف نكتب أوامر بسيطة، حيث يأتي بعد الأمر وسائط. الآن سنرى كيف نبني أوامر أكثر تعقيدًا بتركيب أوامر بسيطة.

الإدخال والإخراج

قبل أن نبدأ، مقدمة سريعة عن الإدخال والإخراج.

للعمليات "قنوات إدخال/إخراج قياسية".

  • يمكن للعملية أن تستهلك الإدخال من "stdin".
  • ويمكن للعملية أن تُصدر الإخراج على "stdout".
  • ويمكن للعملية أن تُصدر إخراج الأخطاء على "stderr".

يُعد الأمر tr مثالًا نقيًا جدًا على ذلك. كل ما يفعله هو قراءة النص من مدخله، وإجراء تحويلات حرفية، وطباعة النص الناتج إلى مخرجه.

سنرى المزيد عن التعامل مع قنوات "stdio" لاحقًا في المنهج.

خطوط الأنابيب

هذه إحدى "أقوى الميزات" في برمجة الصدفة. تتيح لك خطوط الأنابيب إنشاء تحويلات متطورة على تدفق من النص.

لإنتاج قائمة مستخدمين مرتبة:

cat /etc/passwd | cut -d : -f 1 | sort

يربط رمز الأنبوب (|) مخرجات أمر ما بمدخلات أمر آخر. يقرأ cut مخرجات cat، ويقرأ sort مخرجات cut.

Advanced
  • افتراضيًا، يعمل كل أمر في خط الأنابيب في صدفة فرعية منفصلة. (الصدفة الفرعية هي عملية ابنة تكون نسخة من الصدفة قيد التشغيل حاليًا.)

  • هناك تكلفة أداء لتشغيل خطوط الأنابيب. إذا وجدت نفسك أمام خطوط أنابيب طويلة من أوامر متشابهة، ففكّر في دمجها في أمر واحد. على سبيل المثال، يمكن عمومًا دمج خطوط الأنابيب التي تستخدم عدة نسخ من grep وcut وsed وawk وtr في أمر awk واحد لتحسين الكفاءة.

  • حالة الخروج لخط الأنابيب هي حالة الخروج لآخر أمر فيه. وهذا يعني أنه إذا فشل أمر سابق لكن نجح الأمر الأخير، فإن حالة الخروج لخط الأنابيب كله تكون صفرًا.

    هناك إعداد في الصدفة يمكنه تغيير ذلك؛ فإذا كان الإعداد "pipefail" مُفعَّلًا (عبر set -o pipefail)، فستكون حالة الخروج لخط الأنابيب كالتالي:

    • صفر إذا نجحت جميع الأوامر، وإلا
    • _حالة الخروج غير الصفرية الأخيرة للأوامر في خط الأنابيب.

قوائم الأوامر

قائمة الأوامر هي تسلسل من خطوط الأنابيب تفصل بينها ; (أو سطر جديد)، أو && أو ||.

  • A; B قائمة أوامر يُنفَّذ فيها B بعد اكتمال A.
  • A && B، حيث يُنفَّذ B فقط إذا نجح A (أي خرج بحالة صفر).
  • A || B، حيث يُنفَّذ B فقط إذا فشل A (أي خرج بحالة غير صفرية).

حالة الخروج لقائمة الأوامر هي حالة الخروج لآخر أمر نُفِّذ.

يمكن تسلسل العاملين && و|| بحيث يُنفَّذ الأمر التالي بشكل شرطي بناءً على حالة الأوامر السابقة. على سبيل المثال

A && B && C && D || E
  • يُنفَّذ B إذا نجح A،
  • يُنفَّذ C إذا نجح A وB،
  • يُنفَّذ D إذا نجحت A وB وC،
  • يُنفَّذ E إذا فشل أيٌّ من A أو B أو C أو D.
Caution

استخدم هذه العوامل المنطقية باعتدال. فسرعان ما يمكن أن تؤدي إلى كود غير مقروء، أو منطق يصعب فهمه.

على سبيل المثال، قد تظن أن هذين الأمرين متطابقان:

if A; then B; else C; fi
A && B || C

الفرق هو: متى يُنفَّذ C؟

  • في المقطع الأول (الجملة الشرطية)، لن يُنفَّذ C إلا إذا فشل A.
  • في المقطع الثاني، سيُنفَّذ C إذا فشل A أو إذا نجح A لكن فشل B!

استخدامات قوائم الأوامر

إليك مثالين حيث يمكن لقوائم الأوامر أن تبسّط الكود.

قراءة كتلٍ من الأسطر من ملف

لنفترض أن لديك ملف بيانات يحتوي على بيانات عن مثلثات، ويُمثَّل المثلث بثلاثة أسطر منفصلة تحمل أضلاع المثلث.

$ cat triangle.dat
3
4
5
9
12
14

يمكنك استخدام حلقة while حيث يكون الشرط ثلاثة أوامر read منفصلة:

while read a && read b && read c; do
    if is_pythagorean "$a" "$b" "$c"; then
        echo "$a:$b:$c is pythagorean"
    else
        echo "$a:$b:$c is not pythagorean"
    fi
done < triangle.dat

بافتراض أن is_pythagorean أمر يحدد ما إذا كانت الأضلاع الثلاثة تحقق معادلة فيثاغورس، فسيكون الإخراج:

3:4:5 is pythagorean
9:12:14 is not pythagorean
التأكيدات

تحتوي العديد من لغات البرمجة على شكل من التأكيد حيث يُرمى استثناء إذا فشل شرط ما

assert(user == "Administrator", "wrong user");

يمكننا استخدام عامل OR في Bash لمحاكاة هذه الدالة:

die () { # a little convenience function
    echo "$*" >&2
    exit 1
}

[[ $user == "Administrator" ]] || die "wrong user"
[[ $password == "secret!" ]]   || die "incorrect password"

اعتبارات الأسلوب

سرعان ما تصبح قوائم الأوامر الطويلة صعبة القراءة. ويمكن أن يساعد الاستخدام السخي لأسطر جديدة كثيرًا.

تأمّل هذا المثال حيث تُضاف كلمة إلى مصفوفة إذا تحقق شرطان.

[[ "$word" != "$topic" ]] && [[ "$key" == "$(sorted "$topic")" ]] && anagrams+=("$candidate")

يتيح لك Bash إضافة سطر جديد بعد الأنبوب أو عامل منطقي.

[[ "$word" != "$topic" ]] &&
[[ "$key" == "$(sorted "$topic")" ]] &&
anagrams+=("$candidate")

غير أن العامل قد يسهل تفويته في نهاية السطر. واستخدام متابعة السطر يعني أنه يمكنك وضع العامل أولًا، مما يجعل استمرار القائمة أوضح:

[[ "$word" != "$topic" ]] \
&& [[ "$key" == "$(sorted "$topic")" ]] \
&& anagrams+=("$candidate")
Note

متابعة السطر هي تسلسل من حرفين: "شرطة مائلة عكسية" و"سطر جديد" (\ + \n). وعندما يرى Bash هذا التسلسل، يُزال ببساطة من الكود، وبذلك يُتابع السطر الحالي بالسطر التالي. احرص على ألّا تترك أي مسافات بين الشرطة المائلة العكسية والسطر الجديد.

إليك مثالًا آخر

printf "%s\n" "${numbers[@]}" | bc --mathlib | sort --general-numeric-sort

أو

printf "%s\n" "${numbers[@]}" \
| bc --mathlib \
| sort --general-numeric-sort
تعديل عبر GitHub يفتح الرابط في نافذة أو علامة تبويب جديدة