Таҷрибаҳои беҳтарини скрипти Bash: Роҳнамои зуд барои скриптҳои боэътимод ва иҷроиш Bash

Таҷрибаҳои беҳтарини скрипти Bash: Роҳнамои зуд барои скриптҳои боэътимод ва иҷроиш Bash
Обои Shell аз ҷониби manapi

Debugging скриптҳои bash ба ҷустуҷӯи сӯзан дар хирман монанд аст, хусусан вақте ки иловаҳои нав дар пойгоҳи коди мавҷуда бидуни баррасии саривақтии масъалаҳои сохтор, сабт ва эътимод пайдо мешаванд. Шумо метавонед дар чунин ҳолатҳо ё аз сабаби хатогиҳои худ ё ҳангоми идоракунии скриптҳои мураккаб дучор шавед.

гурӯҳ Mail.ru ҳалли абрӣ мақоларо бо тавсияҳое тарҷума кардааст, ки ба шумо дар навиштан, ислоҳ кардан ва беҳтар нигоҳ доштани скриптҳои шумо кӯмак мекунанд. Ба он бовар кунед ё не, ҳеҷ чиз қаноатмандии навиштани коди тоза ва барои истифода омодаи bash нест, ки ҳар дафъа кор мекунад.

Дар мақола муаллиф он чизеро, ки дар тӯли чанд соли охир омӯхтааст, инчунин баъзе хатогиҳои маъмулие, ки ӯро аз ҳушдор гирифтаанд, нақл мекунад. Ин муҳим аст, зеро ҳар як таҳиягари нармафзор дар як лаҳзаи касби худ бо скриптҳо барои автоматикунонии вазифаҳои кори муқаррарӣ кор мекунад.

Корбарони дом

Аксари скриптҳои bash, ки ман дучор шудаам, ҳеҷ гоҳ механизми самараноки тозакуниро истифода намебаранд, вақте ки ҳангоми иҷрои скрипт ягон чизи ғайричашмдошт рух медиҳад.

Ногаҳон метавонад аз берун ба вуҷуд ояд, масалан, гирифтани сигнал аз ядро. Коркарди чунин ҳолатҳо барои таъмини эътимоднокии скриптҳо барои кор дар системаҳои истеҳсолӣ ниҳоят муҳим аст. Ман аксар вақт коркардкунандагони баромадро барои посух додан ба сенарияҳои зерин истифода мебарам:

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

Навиштани скриптҳо бо ин роҳ шуморо водор мекунад, ки дар бораи рафтори ҳамаи фармонҳои скрипт эҳтиёткортар бошед ва эҳтимолияти хатогиро пеш аз он ки шуморо ногаҳонӣ кунад, пешгӯӣ кунед.

ShellCheck барои ошкор кардани хатогиҳо ҳангоми таҳия

Ин меарзад, ки ба монанди интегратсия ShellCheck ба лӯлаҳои таҳия ва озмоиши худ ворид кунед, то рамзи bash-и худро бо таҷрибаҳои беҳтарин тафтиш кунед.

Ман онро дар муҳитҳои рушди маҳаллии худ истифода мебарам, то дар бораи синтаксис, семантика ва баъзе хатогиҳо дар код, ки ҳангоми таҳияи онҳо аз даст дода буданд, гузоришҳо гирам. Ин як воситаи таҳлили статикӣ барои скриптҳои bash-и шумост ва ман тавсия медиҳам, ки онро истифода баред.

Истифодаи рамзҳои баромади худ

Рамзҳои бозгашт дар 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
}

Эзоҳ: Лутфан бо номҳои тағирёбандае, ки шумо муайян мекунед, бодиққат бошед, то аз тағирёбандаҳои муҳити атроф тасодуфан сарнагун шавад.

Функсияҳои сабт

Сабти зебо ва сохторӣ барои ба осонӣ фаҳмидани натиҷаҳои скрипти шумо муҳим аст. Мисли дигар забонҳои барномасозии сатҳи баланд, ман ҳамеша дар скриптҳои bash-и худ функсияҳои сабти номро истифода мебарам, масалан __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 ва дигарон, ба монанди гузоришҳои Slack, дар алоҳидагӣ ҷойгир карда шудаанд 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 Mail.ru Cloud Solutions.
  3. Канали телеграми мо дар бораи трансформатсияи рақамӣ.

Манбаъ: will.com

Илова Эзоҳ