مقدمة
التي شل لاستخدامها
Bash
لغة البرمجة النصية الوحيدة التي يمكن استخدامها للملفات القابلة للتنفيذ.
يجب أن تبدأ البرامج النصية بـ #!/bin/bash
مع الحد الأدنى من العلامات. استخدم set
لتعيين خيارات shell بحيث لا يؤدي انتهاك النص البرمجي باسم bash <script_name>
انتهاك وظائفه.
يمنحنا تحديد جميع النصوص البرمجية لـ bash لغة غلاف ثابتة يتم تثبيتها على جميع أجهزتنا.
الاستثناء الوحيد هو إذا كنت مقيدًا بشروط ما تقوم بالبرمجة له. أحد الأمثلة على ذلك حزم Solaris SVR4 ، التي تتطلب استخدام غلاف بورن المعتاد لأي نص برمجي.
متى تستخدم شل
يجب استخدام Shell فقط للمرافق الصغيرة أو أغلفة البرامج النصية البسيطة.
على الرغم من أن برمجة shell ليست لغة تطوير ، إلا أنها تستخدم لكتابة العديد من الأدوات المساعدة في جميع أنحاء Google. يعد دليل الأسلوب هذا أكثر اعترافًا باستخدامه ، وليس مقترحًا لاستخدامه على نطاق واسع.
بعض التوصيات:
- إذا كنت تستخدم أدوات مساعدة أخرى في كثير من الأحيان وقمت بمعالجة بيانات قليلة نسبيًا ، فإن shell هو خيار مقبول لهذه المهمة.
- إذا كان الأداء مهمًا ، فاستخدم شيئًا آخر غير shell.
- إذا وجدت أنك بحاجة إلى استخدام المصفوفات لأكثر من تعيين
${PIPESTATUS}
، فيجب عليك استخدام Python. - إذا كنت تكتب نصًا أطول من 100 سطر ، فمن المحتمل أن تكتبه في Python. ضع في اعتبارك أن النصوص البرمجية تنمو. أعد كتابة النص البرمجي بلغة أخرى في وقت سابق لتجنب إعادة الكتابة التي تستغرق وقتًا طويلاً.
ملفات شل واستدعاء المترجم
ملحقات الملفات
يجب ألا تحتوي الملفات القابلة للتنفيذ على الامتداد (المفضل بشدة) أو الامتداد .sh
. يجب أن يكون .sh
الامتداد .sh
ويجب ألا تكون قابلة للتنفيذ.
ليست هناك حاجة لمعرفة اللغة التي يكتبها البرنامج أثناء تنفيذه ، ولا يتطلب shell امتدادًا ، لذلك نفضل عدم استخدامه للملفات القابلة للتنفيذ.
ومع ذلك ، من المهم للمكتبات أن تعرف اللغة المكتوبة بها ، وأحيانًا يكون من الضروري وجود مكتبات مماثلة بلغات مختلفة. يسمح لك هذا بأن يكون لديك ملفات مكتبة ذات أسماء متطابقة ذات أهداف متطابقة ، ولكن يجب أن تكون مكتوبة بلغات مختلفة متطابقة بالاسم ، باستثناء لاحقة خاصة بلغة معينة.
SUID / SGID
يحظر SUID و SGID على نصوص الغلاف.
هناك الكثير من مشكلات الأمان ، مما يجعل من المستحيل تقريبًا توفير حماية كافية من SUID / SGID. على الرغم من أن باش يعقد إطلاق SUID ، إلا أنه لا يزال ممكنًا على بعض الأنظمة الأساسية ، لذا فإننا نحظر استخدامه صراحة.
استخدم sudo
للوصول المحسن إذا كنت في حاجة إليها.
البيئة
STDOUT مقابل STDERR
يجب إرسال جميع رسائل الخطأ إلى STDERR
.
هذا يساعد على فصل الحالة الطبيعية عن المشاكل الفعلية.
يوصى باستخدام وظيفة عرض رسائل الخطأ مع معلومات الحالة الأخرى.
err() { echo "[$(date +'%Y-%m-%dT%H:%M:%S%z')]: $@" >&2 } if ! do_something; then err "Unable to do_something" exit "${E_DID_NOTHING}" fi
التعليقات
رأس الملف
ابدأ كل ملف بوصف محتوياته.
يجب أن يكون لكل ملف عنوان من التعليق ، بما في ذلك وصف موجز لمحتوياته. إشعار حقوق النشر ومعلومات المؤلف اختيارية.
مثال:
تعليقات الميزة
يجب التعليق على أي وظيفة غير واضحة وقصيرة. يجب التعليق على أي وظيفة في المكتبة بغض النظر عن طولها أو تعقيدها.
تحتاج إلى التأكد من أن شخصًا آخر يفهم كيفية استخدام برنامجك أو كيفية استخدام الوظيفة في مكتبتك بمجرد قراءة التعليقات (والحاجة إلى التحسين الذاتي) دون قراءة التعليمات البرمجية.
يجب أن تتضمن جميع تعليقات الميزات ما يلي:
- وصف الوظيفة
- المتغيرات العالمية المستخدمة والمعدلة
- تم تلقي الحجج
- إرجاع القيم التي تختلف عن رموز الإنهاء القياسية في الأمر الأخير.
مثال:
تعليقات التنفيذ
قم بالتعليق على الأجزاء المعقدة أو غير الواضحة أو المثيرة للاهتمام أو المهمة من التعليمات البرمجية.
يُفترض أن تكون هذه ممارسة شائعة للتعليق على التعليمات البرمجية على Google. لا تعلق على كل شيء. إذا كانت هناك خوارزمية معقدة أو كنت تفعل شيئًا غير عادي ، فأضف تعليقًا قصيرًا.
تعليقات TODO
استخدم تعليقات TODO لرمز مؤقت أو قصير المدى أو جيد جدًا ، ولكنه ليس مثاليًا.
يتوافق هذا مع الاصطلاح الموجود في دليل C ++ .
يجب أن تتضمن تعليقات TODO كلمة TODO بأحرف كبيرة ، متبوعة باسمك بين قوسين. القولون اختياري. من الأفضل أيضًا الإشارة إلى رقم الخطأ / التذكرة بجوار عنصر TODO.
مثال:
على الرغم من أنه يجب عليك اتباع النمط المستخدم بالفعل في الملفات التي تقوم بتحريرها ، إلا أن التالي مطلوب لأي رمز جديد.
المسافة البادئة
مسافة بادئة 2 مسافات. لا علامات تبويب.
استخدم الأسطر الفارغة بين الكتل لتحسين إمكانية القراءة. المسافة البادئة مسافتان. بغض النظر عما تفعله ، لا تستخدم علامات التبويب. بالنسبة للملفات الموجودة ، ابق صادقًا مع المسافة البادئة الحالية.
طول السلسلة وطول القيمة
يبلغ الحد الأقصى لطول الخط 80 حرفًا.
إذا كنت بحاجة إلى كتابة أسطر أطول من 80 حرفًا ، فيجب القيام بذلك باستخدام here document
أو ، إذا أمكن ، newline
مضمن. يُسمح بشكل معقول بالقيم الحرفية التي يمكن أن تكون أطول من 80 حرفًا ولا يمكن فصلها ، ولكن يُنصح بشدة أن تجد طريقة لجعلها أقصر.
خطوط الأنابيب
يجب تقسيم خطوط الأنابيب كل على سطر واحد إذا لم تتناسب مع سطر واحد.
إذا كان خط الأنابيب يناسب خط واحد ، فيجب أن يكون على خط واحد.
إذا لم يكن الأمر كذلك ، فيجب تقسيمه بحيث يكون كل قسم على خط جديد ويوضع مسافة بادئة بمسافتين للقسم التالي. يشير هذا إلى سلسلة الأوامر مجتمعة باستخدام '|' بالإضافة إلى الاتصالات المنطقية باستخدام '||' و "&&".
دورات
مكان ; do
و ; then
على نفس الخط مثل ، أو if
.
تختلف الدورات في الغلاف قليلاً ، لكننا نتبع نفس المبادئ كما هو الحال مع الأقواس المتعرجة عند الإعلان عن الوظائف. هذا هو ; then
; then
و ; do
يجب أن يكون على نفس السطر كما if
/ for
/ while
. else
يجب أن يكون في سطر منفصل ، ويجب أن تكون العبارات الختامية في السطر الخاص بها ، ومحاذاة رأسيًا مع العبارة الافتتاحية.
مثال:
for dir in ${dirs_to_cleanup}; do if [[ -d "${dir}/${ORACLE_SID}" ]]; then log_date "Cleaning up old files in ${dir}/${ORACLE_SID}" rm "${dir}/${ORACLE_SID}/"* if [[ "$?" -ne 0 ]]; then error_message fi else mkdir -p "${dir}/${ORACLE_SID}" if [[ "$?" -ne 0 ]]; then error_message fi fi done
بيان الحالة
- خيارات منفصلة في مسافتين.
- تتطلب خيارات الخط الواحد مسافة بعد قوس إغلاق القالب وقبله
;;
. - يجب تقسيم خيارات الأوامر الطويلة أو المتعددة إلى عدة أسطر مع قالب وإجراءات و
;;
على خطوط منفصلة.
تتراجع التعبيرات المقابلة عن مستوى واحد من case
و esac
. تحتوي الإجراءات متعددة الخطوط أيضًا على مسافات بادئة على مستوى منفصل. ليست هناك حاجة لوضع تعبيرات بين علامتي اقتباس. يجب ألا تكون أنماط التعبير مسبوقة بأقواس مفتوحة. تجنب استخدام &;
و ;;&
تدوين.
case "${expression}" in a) variable="..." some_command "${variable}" "${other_expr}" ... ;; absolute) actions="relative" another_command "${actions}" "${other_expr}" ... ;; *) error "Unexpected expression '${expression}'" ;; esac
يمكن وضع أوامر بسيطة على سطر واحد بالنمط و ;;
بينما يظل التعبير قابلاً للقراءة. غالبًا ما يكون هذا مناسبًا للتعامل مع خيارات الحرف الواحد. عندما لا تتناسب الإجراءات مع سطر واحد ، اترك القالب في السطر ، الإجراء التالي ، ثم ;;
أيضا في السطر الخاص. عندما يكون هذا هو نفس السطر مع الإجراءات ، استخدم مسافة بعد قوس إغلاق القالب وآخر قبل ;;
.
verbose='false' aflag='' bflag='' files='' while getopts 'abf:v' flag; do case "${flag}" in a) aflag='true' ;; b) bflag='true' ;; f) files="${OPTARG}" ;; v) verbose='true' ;; *) error "Unexpected option ${flag}" ;; esac done
توسع متغير
مرتبة حسب الأولوية: لاحظ ما هو مستخدم بالفعل ؛ إرفاق المتغيرات في علامات الاقتباس ؛ تفضل "${var}"
أكثر من "$var"
، ولكن مع التركيز على سياق الاستخدام.
هذه توصيات بالأحرى ، لأن الموضوع مثير للجدل تمامًا للتنظيم الإلزامي. يتم سردها في ترتيب الأولويات.
- استخدم نفس النمط الذي تجده في التعليمات البرمجية الموجودة.
- ضع المتغيرات بين علامتي اقتباس ، انظر قسم عرض الأسعار أدناه.
لا تضع أحرف مفردة خاصة بالمعلمات الصدفة / الموضعية في علامات الاقتباس والأقواس ما لم يكن ذلك ضروريًا تمامًا وتجنب الارتباك العميق.
تفضل الأقواس المتعرجة لجميع المتغيرات الأخرى.
اقتباسات
- استخدم دائمًا علامات الاقتباس للقيم التي تحتوي على متغيرات ، أو استبدالات أوامر ، أو مسافات أو أحرف أولية ، حتى تحتاج إلى عرض القيم بأمان لا بين علامات اقتباس.
- تفضيل علامات الاقتباس للقيم "الكلمات" (على عكس معلمات الأمر أو أسماء المسارات)
- لا تستشهد أبداً بالأعداد الصحيحة.
- اعرف كيف تعمل علامات الاقتباس لأنماط المطابقة في
[[
. - استخدم
"$@"
إذا لم يكن لديك سبب محدد لاستخدام $*
.
الميزات والأخطاء
استبدال الأمر
استخدم $(command)
بدلاً من backticks.
تتطلب backticks المتداخلة الهروب من علامات الاقتباس الداخلية مع \
. لا يتغير تنسيق $ (command)
اعتمادًا على التداخل ويسهل قراءته.
مثال:
الشيكات ، [
و [[
[[ ... ]]
أفضل من [
، test
or /usr/bin/[
.
[[ ... ]]
يقلل من احتمال الخطأ ، لأنه لا يوجد تحليل مسار أو فصل كلمة بين [[
و ]]
، و [[ ... ]]
يسمح لك باستخدام تعبير عادي حيث [ ... ]
ليس كذلك.
تحقق من القيم
استخدم علامات الاقتباس بدلاً من الأحرف الزائدة حيثما أمكن.
Bash ذكي بما يكفي للعمل مع سلسلة فارغة في الاختبار. لذلك ، من السهل جدًا قراءة التعليمات البرمجية الناتجة ؛ استخدم عمليات التحقق من القيم الفارغة / غير الفارغة أو القيم الفارغة ، دون استخدام أحرف إضافية.
لتجنب الارتباك حول ما تقوم بفحصه ، استخدم -z
أو -n
بشكل صريح.
تعبيرات الاستبدال لأسماء الملفات
استخدم المسار الصريح عند إنشاء تعبيرات حرف البدل لأسماء الملفات.
نظرًا لأن أسماء الملفات يمكن أن تبدأ بالحرف -
، فمن الأكثر أمانًا أن ./*
تعبير حرف البدل على أنه ./*
بدلاً من *
.
تقييم
يجب تجنب eval
.
يسمح لك Eval بتوسيع المتغيرات التي تم تمريرها في الإدخال ، ولكن يمكنه أيضًا تعيين متغيرات أخرى ، دون إمكانية التحقق منها.
الأنابيب في حين
استخدم استبدال الأمر أو حلقة for
بدلاً من الأنابيب في while
. المتغيرات المتغيرة في while
لا تنتشر إلى الأصل ، لأن أوامر الحلقة تنفذ في غلاف فرعي.
يمكن أن يؤدي وجود غلاف فرعي ضمني في الأنبوب أثناء التشغيل إلى صعوبة تتبع الأخطاء.
last_line='NULL' your_command | while read line; do last_line="${line}" done
استخدم حلقة for إذا كنت متأكدًا من أن الإدخال لن يحتوي على مسافات أو أحرف خاصة (لا يعني هذا عادةً إدخال المستخدم).
total=0
يسمح لك استخدام استبدال الأوامر بإعادة توجيه الإخراج ، ولكنه ينفذ الأوامر في غلاف فرعي صريح ، على عكس الغلاف الفرعي الضمني ، الذي ينشئ bash while
.
total=0 last_file= while read count filename; do total+="${count}" last_file="${filename}" done < <(your_command | uniq -c)
استخدم while
الحلقات حيث لا توجد حاجة لتمرير النتائج المعقدة إلى القشرة الأم - وهذا أمر نموذجي عند الحاجة إلى "تحليل" أكثر تعقيدًا. تذكر أن الأمثلة البسيطة أسهل أحيانًا لحلها باستخدام أداة مثل awk. يمكن أن يكون مفيدًا أيضًا عندما لا تريد على وجه التحديد تعديل متغيرات البيئة الرئيسية.
اصطلاح التسمية
أسماء الدوال
أحرف صغيرة مع شرطات سفلية لفصل الكلمات. مكتبات منفصلة مع ::
. الأقواس مطلوبة بعد اسم الوظيفة. الكلمة الأساسية الوظيفية اختيارية ، ولكن إذا تم استخدامها ، فهي متسقة طوال المشروع.
إذا قمت بكتابة وظائف منفصلة ، فاستخدم كلمات صغيرة وكتابة منفصلة بشرطة سفلية. إذا كنت تكتب حزمة ، افصل بين أسماء الحزم بـ ::
. يجب أن تكون الأقواس على نفس سطر اسم الوظيفة (كما هو الحال في اللغات الأخرى على Google) ، ولا تحتوي على مسافة بين اسم الوظيفة والقوس.
عندما تأتي "()" بعد اسم الوظيفة ، تبدو الكلمة الرئيسية للوظيفة زائدة عن الحاجة ، ولكنها تحسن التعرف السريع على الوظائف.
اسم متغير
فيما يتعلق بأسماء الوظائف.
يجب تسمية الأسماء المتغيرة للحلقات بالتساوي لأي متغير تقوم بتكراره.
for zone in ${zones}; do something_with "${zone}" done
أسماء ثابتة متغيرة البيئة
يتم الإعلان عن جميع الأحرف الكبيرة ، مفصولة بشرطة سفلية ، في الجزء العلوي من الملف.
يجب أن تكون الثوابت وكل ما يتم تصديره إلى البيئة في حالة كبيرة.
تظل بعض الأشياء ثابتة عند تثبيتها لأول مرة (على سبيل المثال ، عبر getopts
). وبالتالي ، من الطبيعي جدًا تعيين ثابت من خلال getopts
أو بناءً على شرط ، ولكن يجب أن يتم readonly
بعد ذلك مباشرة. لاحظ أن declare
لا يعمل مع المتغيرات العامة داخل الوظائف ، لذا يُنصح readonly
أو export
بدلاً من ذلك.
VERBOSE='false' while getopts 'v' flag; do case "${flag}" in v) VERBOSE='true' ;; esac done readonly VERBOSE
أسماء ملفات المصدر
أحرف صغيرة ، مع تسطير لفصل الكلمات ، إذا لزم الأمر.
ينطبق هذا على مطابقة الأنماط الأخرى من التعليمات البرمجية على Google: maketemplate
أو make_template
، ولكن ليس make-template
.
قراءة المتغيرات فقط
استخدم readonly
أو declare -r
للتأكد من أنها للقراءة فقط.
shell, . , , .
zip_version="$(dpkg --status zip | grep Version: | cut -d ' ' -f 2)" if [[ -z "${zip_version}" ]]; then error_message else readonly zip_version fi
, , local
. .
, , local
. , .
, ; local
exit code .
my_func2() { local name="$1"
. .
, . , set , .
. .
الرئيسية
, main
, , .
, main
. , ( , ). main:
main "$@"
, , , main
— , .
.
$?
if
, .
:
if ! mv "${file_list}" "${dest_dir}/" ; then echo "Unable to move ${file_list} to ${dest_dir}" >&2 exit "${E_BAD_MOVE}" fi
, PIPESTATUS
, - , , PIPESTATUS
( , [
PIPESTATUS
).
tar -cf - ./* | ( cd "${DIR}" && tar -xf - ) return_codes=(${PIPESTATUS[*]}) if [[ "${return_codes[0]}" -ne 0 ]]; then do_something fi if [[ "${return_codes[1]}" -ne 0 ]]; then do_something_else fi
shell , .
, bash, ( , sed
).
:
الخلاصة
.
, Parting Words C++ .