Bash Scripting Praktika Onenak: Bash Scripts fidagarri eta errendimendurako gida azkarra

Bash Scripting Praktika Onenak: Bash Scripts fidagarri eta errendimendurako gida azkarra
Shell horma-papera manapi-ren eskutik

Bash script-ak araztea belar-pila batean orratz bat bilatzea bezalakoa da, batez ere lehendik dagoen kode-oinarrian gehigarri berriak agertzen direnean egitura, erregistro eta fidagarritasun arazoak garaiz kontuan hartu gabe. Horrelako egoeretan aurki dezakezu zure akatsengatik edo script pila konplexuak kudeatzen dituzunean.

Team Mail.ru Cloud Solutions artikulu bat itzuli du zure gidoiak hobeto idazten, arazketan eta mantentzen lagunduko dizuten gomendioekin. Sinetsi ala ez, ezerk ez du gainditzen aldi bakoitzean funtzionatzen duen bash kode garbi eta erabiltzeko prest idaztearen poztasuna.

Artikuluan, egileak azken urteotan ikasitakoa partekatzen du, baita ustekabean harrapatu duten ohiko akats batzuk ere. Hau garrantzitsua da software-garatzaile bakoitzak, bere karrerako uneren batean, scriptekin lan egiten duelako ohiko lan-zereginak automatizatzeko.

Tranpa-kudeatzaileak

Topatu ditudan bash script gehienek ez dute inoiz garbiketa mekanismo eraginkorrik erabiltzen script exekuzioan ustekabeko zerbait gertatzen denean.

Kanpotik sor daitezke sorpresak, esate baterako, nukleotik seinale bat jasotzea. Horrelako kasuak maneiatzea oso garrantzitsua da scriptak ekoizpen sistemetan exekutatzeko nahikoa fidagarriak direla ziurtatzeko. Askotan erabiltzen ditut irteera-kudeatzaileak honelako agertokiei erantzuteko:

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 Seinaleren bat izanez gero deitzen den garbiketa-funtzioa erregistratzen laguntzen duen shell-eko komando integratua da. Hala ere, arreta berezia izan behar da kudeatzaileekin SIGINT, script-a bertan behera uztea eragiten duena.

Gainera, kasu gehienetan bakarrik harrapatu behar duzu EXIT, baina ideia da benetan pertsonaliza dezakezula gidoiaren portaera seinale bakoitzarentzat.

Eraikitako multzo-funtzioak - akatsean amaitzea azkarra

Oso garrantzitsua da akatsak gertatu bezain laster erantzutea eta exekuzioa azkar gelditzea. Ez dago ezer okerragorik honelako komando bat exekutatzen jarraitzea baino:

rm -rf ${directory_name}/*

Kontuan izan aldagaia dela directory_name zehaztu gabe.

Garrantzitsua da integratutako funtzioak erabiltzea horrelako eszenatokiak kudeatzeko set, Hala nola, set -o errexit, set -o pipefail edo set -o nounset gidoiaren hasieran. Funtzio hauek ziurtatzen dute zure script-a irtengo dela zero ez den edozein irteera-kode aurkitu bezain laster, definitu gabeko aldagaien erabilera, kanalaren gainetik pasatako komando baliogabeak eta abar:

#!/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

Oharra: bezalako funtzio integratuak set -o errexit, scriptetik irtengo da itzulera-kode "gordina" dagoen bezain laster (zeroa ez den). Horregatik, hobe da erroreen kudeaketa pertsonalizatua sartzea, adibidez:

#!/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

Scriptak horrela idazteak behartzen zaitu scripteko komando guztien portaerarekin kontu gehiago izatera eta errore bat gerta daitekeela ustekabean hartu aurretik.

ShellCheck garapenean zehar akatsak detektatzeko

Merezi du horrelako zerbait integratzea ShellCheck zure garapen eta proba kanaletan zure bash kodea praktika onenekin egiaztatzeko.

Nire tokiko garapen-inguruneetan erabiltzen dut sintaxiari, semantikari eta garatzen ari nintzen bitartean galduko nituzkeen kodean akats batzuei buruzko txostenak lortzeko. Hau zure bash scriptetarako analisi estatikoko tresna bat da eta oso gomendatzen dut erabiltzea.

Zure irteera kodeak erabiliz

POSIX-en itzulera-kodeak ez dira zero edo bat bakarrik, zero edo zero ez den balio bat baizik. Erabili funtzio hauek errore-kode pertsonalizatuak itzultzeko (201-254 artean) errore-kasu desberdinetarako.

Informazio hori zurea biltzen duten beste script batzuek erabil dezakete zer errore mota gertatu den zehazki ulertzeko eta horren arabera erreakzionatzeko:

#!/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
}

Oharra: mesedez, kontuz ibili bereziki definitzen dituzun aldagai-izenekin ingurune-aldagaiak ustekabean gainidaztea saihesteko.

Erregistro-funtzioak

Erregistro ederra eta egituratua garrantzitsua da zure gidoiaren emaitzak erraz ulertzeko. Goi-mailako beste programazio-lengoaiekin gertatzen den bezala, beti erabiltzen ditut jatorrizko erregistro-funtzioak nire bash scriptetan, adibidez __msg_info, __msg_error eta abar.

Honek erregistro-egitura estandarizatu bat eskaintzen laguntzen du aldaketak leku bakarrean eginez:

#!/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"

Normalean saiatzen naiz nolabaiteko mekanismo bat izaten nire gidoietan __init, non erregistratzaileen aldagai horiek eta sistemaren beste aldagai batzuk hasieratzen diren edo balio lehenetsietan ezartzen diren. Aldagai hauek komando-lerroko aukeretatik ere ezar daitezke script-a deitzean.

Adibidez, horrelako zerbait:

$ ./run-script.sh --debug

Script hori exekutatzen denean, sistema osorako ezarpenak balio lehenetsietan ezarrita daudela ziurtatzen du, beharrezkoak badira, edo, gutxienez, behar izanez gero, zerbait egokian hasieratzen direla.

Normalean zer abiarazi eta zer ez egin aukeratzen dut erabiltzailearen interfazearen eta erabiltzaileak sakondu ditzakeen/behar lituzkeen konfigurazioen xehetasunen arteko truke-off batean.

Berrerabiltzeko eta sistema garbitzeko arkitektura

Kode modularra/berrerabilgarria

β”œβ”€β”€ framework
β”‚   β”œβ”€β”€ common
β”‚   β”‚   β”œβ”€β”€ loggers.sh
β”‚   β”‚   β”œβ”€β”€ mail_reports.sh
β”‚   β”‚   └── slack_reports.sh
β”‚   └── daily_database_operation.sh

Garatu nahi dudan proiektu/bash script berri bat hasieratzeko erabil dezakedan biltegi bereizi bat gordetzen dut. Berrerabili daitekeen edozer biltegi batean gorde daiteke eta funtzionalitate hori erabili nahi duten beste proiektu batzuek berreskura dezakete. Proiektuak horrela antolatzeak beste scripten tamaina nabarmen murrizten du eta, gainera, kode-oinarria txikia eta probatzeko erraza dela ziurtatzen du.

Goiko adibidean bezala, erregistro-funtzio guztiak adibidez __msg_info, __msg_error eta beste batzuk, hala nola Slack txostenak, bereizita daude common/* eta modu dinamikoan konektatu beste eszenatoki batzuetan daily_database_operation.sh.

Utzi sistema garbi bat

Scripta exekutatzen ari den bitartean baliabideren bat kargatzen ari bazara, datu horiek guztiak ausazko izen batekin partekatutako direktorio batean gordetzea gomendatzen da, adibidez. /tmp/AlRhYbD97/*. Ausazko testu-sorgailuak erabil ditzakezu direktorioaren izena hautatzeko:

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

Lana amaitu ondoren, direktorio horien garbiketa goian aipaturiko kako-kudeatzaileetan eman daiteke. Behin-behineko direktorioak zaintzen ez badira, pilatu egiten dira eta uneren batean ustekabeko arazoak sortzen dituzte ostalarian, adibidez, disko osoa.

Blokeo fitxategiak erabiliz

Askotan ziurtatu behar duzu une bakoitzean script baten instantzia bakarra exekutatzen ari dela ostalari batean. Hau blokeo fitxategiak erabiliz egin daiteke.

Normalean blokeo fitxategiak sortzen ditut /tmp/project_name/*.lock eta egiaztatu gidoiaren hasieran duten presentzia. Honek script-a ondo amaitzen laguntzen du eta sistemaren egoeran ustekabeko aldaketak saihesten ditu paraleloan exekutatzen den beste script baten bidez. Blokeatu fitxategiak ez dira beharrezkoak ostalari jakin batean script bera paraleloan exekutatu behar baduzu.

Neurtu eta hobetu

Askotan denbora luzez exekutatzen diren scriptekin lan egin behar dugu, adibidez, eguneroko datu-baseen eragiketak. Eragiketa horiek normalean urrats sekuentzia bat izaten dute: datuak kargatzea, anomaliak egiaztatzea, datuak inportatzea, egoera-txostenak bidaltzea, etab.

Halakoetan, beti saiatzen naiz scripta script txikietan banatzen eta haien egoera eta exekuzio denboraren berri ematen dut:

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

Geroago exekuzio-denbora ikus dezaket honekin:

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

Honek optimizazioa behar duten scriptetan arazo/motelak identifikatzen laguntzen dit.

Zorte on!

Zer gehiago irakurri:

  1. Joan eta GPU cacheak.
  2. Mail.ru Cloud Solutions-en S3 objektuen biltegian webhooketan oinarritutako gertaerak gidatutako aplikazio baten adibidea.
  3. Eraldaketa digitalari buruzko gure telegram kanala.

Iturria: www.habr.com

Gehitu iruzkin berria