باش اسکرپٹنگ کے بہترین پریکٹس: قابل اعتماد اور پرفارمنس باش اسکرپٹ کے لیے ایک فوری گائیڈ

باش اسکرپٹنگ کے بہترین پریکٹس: قابل اعتماد اور پرفارمنس باش اسکرپٹ کے لیے ایک فوری گائیڈ
مناپی کے ذریعہ شیل وال پیپر

باش اسکرپٹس کو ڈیبگ کرنا گھاس کے ڈھیر میں سوئی تلاش کرنے کے مترادف ہے، خاص طور پر جب موجودہ کوڈبیس میں ڈھانچے، لاگنگ اور وشوسنییتا کے مسائل پر بروقت غور کیے بغیر نئے اضافے ظاہر ہوں۔ آپ اپنی غلطیوں کی وجہ سے یا اسکرپٹ کے پیچیدہ ڈھیروں کا انتظام کرتے وقت اپنے آپ کو ایسے حالات میں پا سکتے ہیں۔

ٹیم Mail.ru کلاؤڈ سلوشنز سفارشات کے ساتھ ایک مضمون کا ترجمہ کیا جو آپ کو لکھنے، ڈیبگ کرنے اور آپ کے اسکرپٹ کو بہتر طریقے سے برقرار رکھنے میں مدد کرے گا۔ یقین کریں یا نہ کریں، کچھ بھی صاف، استعمال کے لیے تیار بیش کوڈ لکھنے کے اطمینان سے پیچھے نہیں ہٹتا جو ہر بار کام کرتا ہے۔

مضمون میں، مصنف نے پچھلے کچھ سالوں میں جو کچھ سیکھا ہے اس کے ساتھ ساتھ کچھ عام غلطیاں بھی شیئر کی ہیں جنہوں نے اسے چوکس کر دیا ہے۔ یہ ضروری ہے کیونکہ ہر سافٹ ویئر ڈویلپر، اپنے کیریئر کے کسی نہ کسی موقع پر، معمول کے کام کے کاموں کو خودکار کرنے کے لیے اسکرپٹ کے ساتھ کام کرتا ہے۔

ٹریپ ہینڈلر

زیادہ تر باش اسکرپٹس جن کا میں نے سامنا کیا ہے وہ کبھی بھی صفائی کے موثر طریقہ کار کا استعمال نہیں کرتے ہیں جب اسکرپٹ پر عمل درآمد کے دوران کچھ غیر متوقع ہوتا ہے۔

حیرت باہر سے پیدا ہو سکتی ہے، جیسے کور سے سگنل وصول کرنا۔ اس طرح کے معاملات کو سنبھالنا اس بات کو یقینی بنانے کے لیے انتہائی اہم ہے کہ اسکرپٹس پروڈکشن سسٹم پر چلنے کے لیے کافی قابل اعتماد ہیں۔ میں اکثر اس طرح کے منظرناموں کا جواب دینے کے لیے ایگزٹ ہینڈلرز کا استعمال کرتا ہوں:

function handle_exit() {
  // Add cleanup code here
  // for eg. rm -f "/tmp/${lock_file}.lock"
  // exit with an appropriate status code
}
  
// trap <HANDLER_FXN> <LIST OF SIGNALS TO TRAP>
trap handle_exit 0 SIGHUP SIGINT SIGQUIT SIGABRT SIGTERM

trap ایک شیل بلٹ ان کمانڈ ہے جو آپ کو کلین اپ فنکشن رجسٹر کرنے میں مدد کرتی ہے جسے کسی بھی سگنل کی صورت میں بلایا جاتا ہے۔ تاہم، ہینڈلرز کے ساتھ خاص خیال رکھنا چاہئے جیسے SIGINT، جس کی وجہ سے اسکرپٹ اسقاط ہوجاتا ہے۔

اس کے علاوہ، زیادہ تر معاملات میں آپ کو صرف پکڑنا چاہئے EXIT، لیکن خیال یہ ہے کہ آپ اصل میں ہر انفرادی سگنل کے لیے اسکرپٹ کے رویے کو اپنی مرضی کے مطابق بنا سکتے ہیں۔

بلٹ ان سیٹ فنکشنز - غلطی پر تیزی سے ختم

غلطیوں کے ہوتے ہی ان کا جواب دینا اور ان پر عملدرآمد کو تیزی سے روکنا بہت ضروری ہے۔ اس طرح کے کمانڈ کو جاری رکھنے سے بدتر کوئی چیز نہیں ہوسکتی ہے۔

rm -rf ${directory_name}/*

براہ کرم نوٹ کریں کہ متغیر directory_name تعین نہیں کیا.

اس طرح کے منظرناموں کو سنبھالنے کے لیے بلٹ ان فنکشنز کا استعمال کرنا ضروری ہے۔ setجیسے set -o errexit, set -o pipefail یا set -o nounset اسکرپٹ کے شروع میں یہ فنکشنز اس بات کو یقینی بناتے ہیں کہ جیسے ہی آپ کا اسکرپٹ کسی بھی غیر صفر ایگزٹ کوڈ کا سامنا کرے گا، غیر متعینہ متغیرات کا استعمال، پائپ کے اوپر سے گزرنے والی غلط کمانڈز، وغیرہ:

#!/usr/bin/env bash

set -o errexit
set -o nounset
set -o pipefail

function print_var() {
  echo "${var_value}"
}

print_var

$ ./sample.sh
./sample.sh: line 8: var_value: unbound variable

نوٹ: بلٹ ان افعال جیسے set -o errexit، جیسے ہی کوئی "را" ریٹرن کوڈ (صفر کے علاوہ) ہوگا اسکرپٹ سے باہر نکل جائے گا۔ اس لیے بہتر ہے کہ کسٹم ایرر ہینڈلنگ کو متعارف کرایا جائے، مثال کے طور پر:

#!/bin/bash
error_exit() {
  line=$1
  shift 1
  echo "ERROR: non zero return code from line: $line -- $@"
  exit 1
}
a=0
let a++ || error_exit "$LINENO" "let operation returned non 0 code"
echo "you will never see me"
# run it, now we have useful debugging output
$ bash foo.sh
ERROR: non zero return code from line: 9 -- let operation returned non 0 code

اسکرپٹ کو اس طرح لکھنا آپ کو اسکرپٹ میں موجود تمام کمانڈز کے رویے کے بارے میں زیادہ محتاط رہنے پر مجبور کرتا ہے اور اس سے پہلے کہ یہ آپ کو حیران کر دے کسی غلطی کے امکان کا اندازہ لگائیں۔

ترقی کے دوران غلطیوں کا پتہ لگانے کے لیے شیل چیک کریں۔

یہ اس طرح کچھ ضم کرنے کے قابل ہے شیل چیک بہترین طریقوں کے خلاف اپنے باش کوڈ کو چیک کرنے کے لیے آپ کی ڈیولپمنٹ اور ٹیسٹنگ پائپ لائنز میں۔

میں اسے اپنے مقامی ترقیاتی ماحول میں نحو، اصطلاحات، اور کوڈ میں کچھ خامیوں کے بارے میں رپورٹس حاصل کرنے کے لیے استعمال کرتا ہوں جو کہ ترقی کرتے وقت میں نے چھوٹ دی ہوں گی۔ یہ آپ کے باش اسکرپٹس کے لیے ایک مستحکم تجزیہ کا آلہ ہے اور میں اسے استعمال کرنے کی انتہائی سفارش کرتا ہوں۔

اپنے ایگزٹ کوڈز کا استعمال کرنا

POSIX میں ریٹرن کوڈز صرف صفر یا ایک نہیں ہوتے بلکہ صفر یا غیر صفر قدر ہوتے ہیں۔ مختلف خرابی کے کیسز کے لیے حسب ضرورت ایرر کوڈز (201-254 کے درمیان) واپس کرنے کے لیے ان خصوصیات کا استعمال کریں۔

اس معلومات کو اس کے بعد دوسری اسکرپٹس کے ذریعہ استعمال کیا جاسکتا ہے جو آپ کو یہ سمجھنے کے لئے لپیٹتے ہیں کہ کس قسم کی خرابی واقع ہوئی ہے اور اس کے مطابق ردعمل ظاہر کرتے ہیں:

#!/usr/bin/env bash

SUCCESS=0
FILE_NOT_FOUND=240
DOWNLOAD_FAILED=241

function read_file() {
  if ${file_not_found}; then
    return ${FILE_NOT_FOUND}
  fi
}

نوٹ: براہ کرم خاص طور پر ان متغیر ناموں سے محتاط رہیں جن کی آپ تعریف کرتے ہیں تاکہ حادثاتی طور پر ماحولیاتی متغیرات کو اوور رائیڈ کرنے سے بچ سکیں۔

لاگنگ کے افعال

آپ کے اسکرپٹ کے نتائج کو آسانی سے سمجھنے کے لیے خوبصورت اور منظم لاگنگ ضروری ہے۔ دیگر اعلیٰ سطحی پروگرامنگ زبانوں کی طرح، میں ہمیشہ اپنے باش اسکرپٹس میں مقامی لاگنگ فنکشنز استعمال کرتا ہوں، جیسے __msg_info, __msg_error اور وغیرہ.

یہ صرف ایک جگہ پر تبدیلیاں کرکے ایک معیاری لاگنگ ڈھانچہ فراہم کرنے میں مدد کرتا ہے:

#!/usr/bin/env bash

function __msg_error() {
    [[ "${ERROR}" == "1" ]] && echo -e "[ERROR]: $*"
}

function __msg_debug() {
    [[ "${DEBUG}" == "1" ]] && echo -e "[DEBUG]: $*"
}

function __msg_info() {
    [[ "${INFO}" == "1" ]] && echo -e "[INFO]: $*"
}

__msg_error "File could not be found. Cannot proceed"

__msg_debug "Starting script execution with 276MB of available RAM"

میں عام طور پر کوشش کرتا ہوں کہ اپنے اسکرپٹ میں کسی قسم کا میکانزم ہو۔ __init، جہاں اس طرح کے لاگر متغیرات اور سسٹم کے دیگر متغیرات کو شروع کیا جاتا ہے یا پہلے سے طے شدہ اقدار پر سیٹ کیا جاتا ہے۔ ان متغیرات کو اسکرپٹ کی درخواست کے دوران کمانڈ لائن کے اختیارات سے بھی سیٹ کیا جا سکتا ہے۔

مثال کے طور پر، کچھ اس طرح:

$ ./run-script.sh --debug

جب اس طرح کے اسکرپٹ کو عمل میں لایا جاتا ہے، تو یہ یقینی بناتا ہے کہ سسٹم کی وسیع ترتیبات کو ڈیفالٹ ویلیوز پر سیٹ کیا گیا ہے اگر ان کی ضرورت ہو، یا کم از کم اگر ضروری ہو تو کسی مناسب چیز پر شروع کیا جائے۔

میں عام طور پر اس انتخاب کی بنیاد رکھتا ہوں کہ صارف انٹرفیس اور کنفیگریشنز کی تفصیلات کے درمیان ٹریڈ آف پر کیا شروع کرنا ہے اور کیا نہیں کرنا ہے جس میں صارف کو غور کرنا چاہیے/کرنا چاہیے۔

دوبارہ استعمال اور صاف نظام کی حالت کے لیے فن تعمیر

ماڈیولر/ دوبارہ قابل استعمال کوڈ

├── framework
│   ├── common
│   │   ├── loggers.sh
│   │   ├── mail_reports.sh
│   │   └── slack_reports.sh
│   └── daily_database_operation.sh

میں ایک علیحدہ ذخیرہ رکھتا ہوں جسے میں ایک نئے پروجیکٹ/بش اسکرپٹ کو شروع کرنے کے لیے استعمال کر سکتا ہوں جسے میں تیار کرنا چاہتا ہوں۔ کوئی بھی چیز جو دوبارہ استعمال کی جا سکتی ہے اسے ایک ذخیرہ میں ذخیرہ کیا جا سکتا ہے اور دوسرے پروجیکٹس کے ذریعہ بازیافت کیا جاسکتا ہے جو اس فعالیت کو استعمال کرنا چاہتے ہیں۔ پروجیکٹس کو اس طرح ترتیب دینے سے دیگر اسکرپٹس کے سائز کو نمایاں طور پر کم کیا جاتا ہے اور یہ بھی یقینی بناتا ہے کہ کوڈ بیس چھوٹا اور جانچنا آسان ہے۔

جیسا کہ اوپر دی گئی مثال میں، تمام لاگنگ فنکشنز جیسے __msg_info, __msg_error اور دیگر، جیسے سلیک رپورٹس، میں الگ سے موجود ہیں۔ common/* اور متحرک طور پر دوسرے منظرناموں میں جڑیں جیسے daily_database_operation.sh.

صاف ستھرا نظام چھوڑ دیں۔

اگر آپ اسکرپٹ کے چلنے کے دوران کوئی وسائل لوڈ کر رہے ہیں، تو یہ تجویز کیا جاتا ہے کہ اس طرح کے تمام ڈیٹا کو ایک مشترکہ ڈائرکٹری میں ایک بے ترتیب نام کے ساتھ ذخیرہ کیا جائے، جیسے /tmp/AlRhYbD97/*. آپ ڈائرکٹری کا نام منتخب کرنے کے لیے بے ترتیب ٹیکسٹ جنریٹرز استعمال کر سکتے ہیں:

rand_dir_name="$(cat /dev/urandom | tr -dc 'a-zA-Z0-9' | fold -w 16 | head -n 1)"

کام کی تکمیل کے بعد، اس طرح کی ڈائریکٹریوں کی صفائی اوپر دی گئی ہک ہینڈلرز میں فراہم کی جا سکتی ہے۔ اگر عارضی ڈائریکٹریوں کا خیال نہ رکھا جائے تو وہ جمع ہو جاتی ہیں اور کسی مرحلے پر میزبان پر غیر متوقع مسائل کا باعث بنتی ہیں، جیسے کہ مکمل ڈسک۔

لاک فائلوں کا استعمال

اکثر آپ کو یہ یقینی بنانا ہوتا ہے کہ کسی بھی وقت میزبان پر اسکرپٹ کی صرف ایک مثال چل رہی ہے۔ یہ لاک فائلوں کا استعمال کرتے ہوئے کیا جا سکتا ہے۔

میں عام طور پر لاک فائلیں بناتا ہوں۔ /tmp/project_name/*.lock اور اسکرپٹ کے شروع میں ان کی موجودگی کی جانچ کریں۔ اس سے اسکرپٹ کو خوبصورتی سے ختم کرنے اور متوازی طور پر چلنے والے دوسرے اسکرپٹ کے ذریعہ سسٹم کی حالت میں غیر متوقع تبدیلیوں سے بچنے میں مدد ملتی ہے۔ لاک فائلوں کی ضرورت نہیں ہے اگر آپ کو ایک ہی اسکرپٹ کی ضرورت ہو تاکہ کسی دیے گئے میزبان پر متوازی طور پر عمل کیا جائے۔

پیمائش کریں اور بہتر بنائیں

ہمیں اکثر اسکرپٹ کے ساتھ کام کرنے کی ضرورت ہوتی ہے جو طویل عرصے تک چلتی ہیں، جیسے روزانہ ڈیٹا بیس آپریشنز۔ اس طرح کے آپریشنز میں عام طور پر اقدامات کا ایک سلسلہ شامل ہوتا ہے: ڈیٹا لوڈ کرنا، بے ضابطگیوں کی جانچ کرنا، ڈیٹا درآمد کرنا، اسٹیٹس رپورٹس بھیجنا، وغیرہ۔

ایسے معاملات میں، میں ہمیشہ اسکرپٹ کو الگ الگ چھوٹے اسکرپٹس میں توڑنے کی کوشش کرتا ہوں اور ان کا استعمال کرتے ہوئے ان کی حیثیت اور عمل کے وقت کی اطلاع دیتا ہوں:

time source "${filepath}" "${args}">> "${LOG_DIR}/RUN_LOG" 2>&1

بعد میں میں اس کے ساتھ عملدرآمد کا وقت دیکھ سکتا ہوں:

tac "${LOG_DIR}/RUN_LOG.txt" | grep -m1 "real"

اس سے مجھے اسکرپٹ میں دشواری/سست علاقوں کی نشاندہی کرنے میں مدد ملتی ہے جن کو اصلاح کی ضرورت ہے۔

گڈ لک!

اور کیا پڑھنا ہے:

  1. جاؤ اور GPU کیش۔
  2. میل ڈاٹ آر یو کلاؤڈ سلوشنز کے S3 آبجیکٹ اسٹوریج میں ویب ہکس پر مبنی ایونٹ سے چلنے والی ایپلیکیشن کی ایک مثال۔
  3. ڈیجیٹل تبدیلی کے بارے میں ہمارا ٹیلیگرام چینل۔

ماخذ: www.habr.com

نیا تبصرہ شامل کریں