
Bash-skriptide tĂ”rkeotsing on nagu nĂ”ela otsimine heinas, eriti kui olemasolevas koodibaasis ilmuvad uued lisandused ilma struktuuri, logimise ja usaldusvÀÀrsuse kĂŒsimuste Ă”igeaegse kaalumiseta. Sellistes olukordades vĂ”ib tekkida probleeme nii oma vigade tĂ”ttu kui ka keerukate skriptide haldamisel.
Meeskond tÔlkis artikli soovitustega, mis aitavad teil paremini kirjutada, tÔrkeotsingut teha ja oma skripte hallata. Usuge vÔi mitte, aga mitte miski ei saa vÔrreldagi rahuloluga, mida toob puhta, kasutamiseks valmis bash-koodi kirjutamine, mis töötab iga kord.
Artiklis jagab autor teavet, mida on ta viimase paar aasta jooksul Ă”ppinud, ning mĂ”ned levinud vead, mis on teda ĂŒllatanud. See on oluline, kuna iga tarkvaraarendaja töötab mingil hetkel oma karjÀÀris skriptidega, et automatiseerida rutiinseid tĂ¶Ă¶ĂŒlesandeid.
PĂŒĂŒdja kĂ€sitlejad
Enamik bash-skripte, millega olen kokku puutunud, ei ole kunagi kasutanud tÔhusat puhastusmechanismi, kui skripti kÀivitamise ajal juhtub midagi ootamatut.
Ootamatud olukorrad vĂ”ivad tekkida vĂ€ljastpoolt, nĂ€iteks kui tuum saadab signaali. Sarnaste olukordade kĂ€sitlemine on ÀÀrmiselt oluline, et skriptid oleksid piisavalt usaldusvÀÀrsed tootmisĂŒsteemides kĂ€itamiseks. Kasutan sageli vĂ€ljapÀÀsukĂ€sitlejaid, et reageerida jĂ€rgmistele olukordadele:
function handle_exit() {
// Lisa siia puhastuskood
// nÀiteks rm -f "/tmp/${lock_file}.lock"
// lahkuge sobiva olekukoodiga
}
// pĂŒĂŒdke <HANDLER_FXN> <SIGNALITE LOETEL ĂIGUS>
pĂŒĂŒdke handle_exit 0 SIGHUP SIGINT SIGQUIT SIGABRT SIGTERM
trap â on sisseehitatud kĂ€su shellis, mis aitab teil registreerida puhastamisfunktsiooni, mida kutsutakse esile, kui mĂ”ni signaal ilmneb. Tuleks siiski olla erilise ettevaatlikkusega selliste kĂ€sitlejate osas nagu SIGINT, mis kutsub skripti katkestama.
Lisaks peaks enamikul juhtudel pĂŒĂŒdma ainult EXIT, aga idee on selles, et saate tĂ”eliselt kohandada skripti kĂ€itumist iga eraldi signaali jaoks.
Sisseehitatud funktsioonid set â kiire lĂ”petamine, kui ilmneb viga
On oluline reageerida vigadele kohe, kui need ilmnevad, ja kiiresti katkestada tÀitmine. Mitte midagi ei saa olla halvem kui jÀtkata sellise kÀsu tÀitmist:
rm -rf ${directory_name}/*
Pange tÀhele, et muutuja directory_name ei ole mÀÀratud.
Selliste stsenaariumide kÀsitlemiseks on oluline kasutada sisseehitatud funktsioone set, nagu set -o errexit, set -o pipefail vÔi set -o nounset skripti alguses. Need funktsioonid tagavad, et teie skript lÔpetab töö, kui see kohtab mingit mitte-null lÔpetamiskoodi, mÀÀramata muutujaid, valeid kÀske, mis edastatakse kanalite kaudu jne:
#!/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
MÀrkus: sisseehitatud funktsioonid, nagu set -o errexit, lÔpetavad skripti, kui ilmneb "töötlemata" tagastusvÀÀrtus (vÀlja arvatud null). SeetÔttu on parem luua kohandatud vigade töötlemine, nÀiteks:
#!/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
Selliste skriptide kirjutamine paneb teid hoolikalt jĂ€lgima kĂ”igi skripti kĂ€skude kĂ€itumist ja arvestama, et viga vĂ”ib tekkida enne, kui see teid ĂŒllatab.
ShellCheck vigade tuvastamiseks arendamise ajal
Tasub integreerida midagi sellist nagu oma arendus- ja testimisprotsessidesse, et kontrollida oma bash-koodi parimate praktikate rakendamise osas.
Kasutangi seda oma kohalikus arenduskeskkonnas, et saada aruandeid sĂŒntaksist, semantikast ja mĂ”nest koodiveast, mis olen arendamise kĂ€igus vĂ”inud vahele jĂ€tta. See on staatilise analĂŒĂŒsi tööriist teie bash-skriptide jaoks ja soovitan selle rakendamist.
Oma vÀljundkoodide kasutamine
VĂ€ljastamisnumbri koodid POSIXis ei ole lihtsalt null vĂ”i ĂŒks, vaid null vĂ”i mitte-null vÀÀrtus. Kasutage neid vĂ”imalusi, et tagastada kohandatud veakoodid (vahemikus 201â254) erinevate veatĂŒĂŒpide jaoks.
Seda teavet saab seejĂ€rel kasutada teiste skriptide poolt, mis teie ĂŒmber pakendavad, et tĂ€pselt mĂ”ista, milline veatĂŒĂŒp toimus, ja reageerida vastavalt:
#!/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
}
MĂ€rkus: palun olge eriti ettevaatlik, milliseid muutujaid te mÀÀrate, et mitte juhuslikult keskkonnamuutujaid ĂŒle kirjutada.
Logifunktsioonid
Ilus ja struktureeritud logimine on oluline, et mÔista teie skripti tÀitmise tulemusi. Nagu teistes kÔrgemates programmeerimiskeeltes, kasutan ma alati oma bash skriptides logimise funktsioone, nÀiteks __msg_info, __msg_error ja nii edasi.
See aitab tagada standardiseeritud logistruktuuri, tehes muudatusi ainult ĂŒhes kohas:
#!/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"
Ma pĂŒĂŒan tavaliselt oma skriptides omada mingit mehhanismi __init, kus sellised logeri muutujad ja teised sĂŒsteemimuutujad initsialiseeritakse vĂ”i seatakse vaikimisi vÀÀrtustesse. Need muutujad vĂ”ivad samuti olla seatud kĂ€ivitusargumentide kaudu skripti kĂ€ivitamise ajal.
NĂ€iteks midagi sellist:
$ ./run-script.sh --debug
Kui selline skript kĂ€ivitatakse, on tagatud, et sĂŒsteemiasetused on seatud vaikimisi vÀÀrtustesse, kui need on kohustuslikud, vĂ”i vĂ€hemalt initsialiseeritud millegagi sobivaga, kui see on vajalik.
Ma pĂ”hjan tavaliselt oma valikut, mida initsialiseerida ja mida mitte, kompromissile kasutajaliidese ja konfiguratsioonide detailide vahel, millesse kasutaja vĂ”ib/peab sĂŒvenema.
Arhitektuur taaskasutamise ja puhta sĂŒsteemi jaoks
Modulaarne / korduvkasutatav kood
âââ framework
â âââ common
â â âââ loggers.sh
â â âââ mail_reports.sh
â â âââ slack_reports.sh
â âââ daily_database_operation.sh
Hoian eraldi hoidlat, mida saab kasutada uue bash projekti/skripti initsialiseerimiseks, mida soovin arendada. KÔik, mida saab uuesti kasutada, vÔib olla salvestatud hoidlas ja saadud teistes projektides, mis tahavad selliseid funktsioone kasutada. Selline projektide korraldus vÀhendab oluliselt teiste skriptide suurust ning tagab, et koodibaas on vÀike ja hÔlpsasti testitav.
Nagu eespool toodud nĂ€ites, sisaldavad kĂ”ik logimisfunktsioonid, nĂ€iteks __msg_info, __msg_error ja muud, nĂ€iteks Slacki aruanded, on eraldi common/* ja tĂ”mmatakse dĂŒnaamiliselt teistes skriptides, nagu daily_database_operation.sh.
JĂ€tke enda jĂ€rel puhas sĂŒsteem
Kui laadite skripti kĂ€itamise ajal mingeid ressursse, on soovitatav hoida kĂ”ik sellised andmed ĂŒldises kataloogis juhusliku nimega, nĂ€iteks /tmp/AlRhYbD97/*Saate kasutada juhuslike tekstide genereerijaid, et valida katalooge nimi:
rand_dir_name="$(cat /dev/urandom | tr -dc 'a-zA-Z0-9' | fold -w 16 | head -n 1)"
PĂ€rast töö lĂ”petamist saab selliste kataloogide puhastamine tagada ĂŒlaltoodud lĂ”ksu töötlejates. Kui ajutiste kataloogide puhusele ei hoolitseta, kogunevad need ja mingil hetkel pĂ”hjustavad ootamatuid probleeme hostis, nĂ€iteks tĂ€is kĂ”vaketas.
Lock-failide kasutamine
Sageli on vajalik tagada, et hostis oleks igal hetkel kĂ€imas ainult ĂŒks skript. Seda saab teha lock-failide abil.
Ma loon tavaliselt lock-failid /tmp/project_name/*.lock ja kontrollin nende olemasolu skripti alguses. See aitab skripti Ă”igesti lĂ”petada ja vĂ€ltida ootamatuid sĂŒsteemi oleku muutusi, kui teine skript töötab paralleelselt. Lock-failid ei ole vajalikud, kui peate sama skripti kĂ€ivitama paralleelselt antud hostis.
MÔÔtke ja parandage
Peame sageli töötama skriptidega, mis töötavad pikka aega, nÀiteks igapÀevaste andmebaasi toimingutega. Need toimingud hÔlmavad tavaliselt tegevuste jÀrjestust: andmete laadimine, anomaaliate kontrollimine, andmete importimine, olekuteate saatmine jne.
Sellistes olukordades pĂŒĂŒan alati skripti jagada eraldi vĂ€ikesteks skriptideks ja edastada nende olek ja tĂ€itmise aeg jĂ€rgmistel viisidel:
time source "${filepath}" "${args}" >> "${LOG_DIR}/RUN_LOG" 2>&1
Hiljem saan vaadata tÀitmise aega jÀrgmistel viisidel:
tac "${LOG_DIR}/RUN_LOG.txt" | grep -m1 "real"
See aitab mul mÀÀrata probleemseid/aeglaseid kohti skriptides, mis vajavad optimeerimist.
Edu!
Mida veel lugeda:
Allikas: habr.com
