Bestu starfsvenjur Bash forskrifta: Fljótleg leiðarvísir um áreiðanleg og afkastamikil Bash forskriftir

Bestu starfsvenjur Bash forskrifta: Fljótleg leiðarvísir um áreiðanleg og afkastamikil Bash forskriftir
Skelja veggfóður frá manapi

Að kemba bash forskriftir er eins og að leita að nál í heystakki, sérstaklega þegar nýjar viðbætur birtast í núverandi kóðagrunni án þess að íhuga tímanlega atriði varðandi uppbyggingu, skógarhögg og áreiðanleika. Þú getur lent í slíkum aðstæðum annað hvort vegna eigin mistaka eða þegar þú stjórnar flóknum haugum af handritum.

Team Mail.ru skýjalausnir þýddi grein með tilmælum sem hjálpa þér að skrifa, kemba og viðhalda handritunum þínum betur. Trúðu það eða ekki, ekkert er jafn ánægjulegt að skrifa hreinan, tilbúinn bash kóða sem virkar í hvert skipti.

Í greininni deilir höfundur því sem hann hefur lært á undanförnum árum, auk nokkurra algengra mistaka sem hafa gripið hann í taumana. Þetta er mikilvægt vegna þess að sérhver hugbúnaðarframleiðandi, einhvern tíma á ferlinum, vinnur með forskriftir til að gera sjálfvirkan venjubundin vinnuverkefni.

Meðhöndlarar gildru

Flest bash forskriftir sem ég hef kynnst nota aldrei árangursríkan hreinsunarbúnað þegar eitthvað óvænt gerist við framkvæmd handrits.

Óvæntir geta komið upp utan frá, eins og að fá merki frá kjarnanum. Meðhöndlun slíkra mála er afar mikilvæg til að tryggja að forskriftirnar séu nógu áreiðanlegar til að keyra á framleiðslukerfum. Ég nota oft útgöngustjóra til að bregðast við atburðarás eins og þessa:

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 er innbyggð skel skipun sem hjálpar þér að skrá hreinsunaraðgerð sem er kölluð ef einhver merki eru. Hins vegar ber að gæta sérstakrar varúðar við umsjónarmenn eins og SIGINT, sem veldur því að handritið hættir.

Að auki ættir þú í flestum tilfellum aðeins að veiða EXIT, en hugmyndin er sú að þú getur í raun sérsniðið hegðun handritsins fyrir hvert einstakt merki.

Innbyggðar stillingar - hröð uppsögn við villu

Það er mjög mikilvægt að bregðast við villum um leið og þær koma upp og stöðva framkvæmd fljótt. Ekkert gæti verið verra en að halda áfram að keyra skipun eins og þessa:

rm -rf ${directory_name}/*

Athugið að breyt directory_name ekki ákveðið.

Það er mikilvægt að nota innbyggðar aðgerðir til að takast á við slíkar aðstæður set, Svo sem set -o errexit, set -o pipefail eða set -o nounset í upphafi handritsins. Þessar aðgerðir tryggja að handritið þitt muni hætta um leið og það rekst á einhvern útgöngukóða sem er ekki núll, notkun á óskilgreindum breytum, ógildar skipanir sem sendar eru yfir pípu og svo framvegis:

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

Ath: innbyggðar aðgerðir eins og set -o errexit, mun hætta í handritinu um leið og það er "hrár" skilakóði (annar en núll). Þess vegna er betra að kynna sérsniðna villumeðferð, til dæmis:

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

Að skrifa forskriftir á þennan hátt neyðir þig til að vera varkárari varðandi hegðun allra skipana í handritinu og sjá fyrir möguleika á villu áður en hún kemur þér í opna skjöldu.

ShellCheck til að greina villur meðan á þróun stendur

Það er þess virði að samþætta eitthvað eins og Skeljarathugun inn í þróunar- og prófunarleiðslur þínar til að athuga bash kóðann þinn í samræmi við bestu starfsvenjur.

Ég nota það í staðbundnu þróunarumhverfinu mínu til að fá skýrslur um setningafræði, merkingarfræði og nokkrar villur í kóðanum sem ég gæti hafa misst af við þróun. Þetta er kyrrstöðugreiningartæki fyrir bash forskriftirnar þínar og ég mæli eindregið með því að nota það.

Notaðu þína eigin útgöngukóða

Skilakóðar í POSIX eru ekki bara núll eða einn, heldur núll eða ekki núll gildi. Notaðu þessa eiginleika til að skila sérsniðnum villukóðum (á milli 201-254) fyrir ýmis villutilvik.

Þessar upplýsingar geta síðan verið notaðar af öðrum forskriftum sem umlykja þitt til að skilja nákvæmlega hvers konar villu átti sér stað og bregðast við í samræmi við það:

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

Ath: vinsamlegast vertu sérstaklega varkár með breytuheitin sem þú skilgreinir til að forðast að hnekkja umhverfisbreytum óvart.

Skráningaraðgerðir

Falleg og skipulögð skráning er mikilvæg til að skilja niðurstöður handrits þíns auðveldlega. Eins og með önnur forritunarmál á háu stigi nota ég alltaf innfædda skráningaraðgerðir í bash skriftunum mínum, eins og __msg_info, __msg_error og svo framvegis.

Þetta hjálpar til við að veita staðlaða skógarhöggsuppbyggingu með því að gera breytingar á aðeins einum stað:

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

Ég reyni venjulega að hafa einhvers konar vélbúnað í handritunum mínum __init, þar sem slíkar skráningarbreytur og aðrar kerfisbreytur eru frumstilltar eða stilltar á sjálfgefin gildi. Þessar breytur er einnig hægt að stilla úr skipanalínuvalkostum meðan á skriftukalli stendur.

Til dæmis eitthvað eins og:

$ ./run-script.sh --debug

Þegar slíkt handrit er keyrt tryggir það að stillingar fyrir allt kerfið séu stilltar á sjálfgefin gildi ef þess er krafist, eða að minnsta kosti frumstillt á eitthvað viðeigandi ef þörf krefur.

Ég byggi valið á því hvað á að frumstilla og hvað ekki að gera yfirleitt á skiptum á milli notendaviðmótsins og smáatriðin í þeim stillingum sem notandinn getur/ætti að kafa ofan í.

Arkitektúr fyrir endurnotkun og hreint kerfisástand

Mát/endurnýtanlegur kóði

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

Ég geymi sérstaka geymslu sem ég get notað til að frumstilla nýtt verkefni/bash forskrift sem ég vil þróa. Allt sem hægt er að endurnýta er hægt að geyma í geymslu og ná í önnur verkefni sem vilja nota þá virkni. Að skipuleggja verkefni með þessum hætti minnkar verulega stærð annarra skrifta og tryggir einnig að kóðagrunnurinn sé lítill og auðvelt að prófa.

Eins og í dæminu hér að ofan, allar skráningaraðgerðir eins og __msg_info, __msg_error og aðrar, eins og Slack skýrslur, er að finna sérstaklega í common/* og tengdu á virkan hátt í öðrum aðstæðum eins og daily_database_operation.sh.

Skildu eftir hreint kerfi

Ef þú ert að hlaða einhverjum tilföngum á meðan handritið er í gangi er mælt með því að geyma öll slík gögn í sameiginlegri möppu með handahófsheiti, t.d. /tmp/AlRhYbD97/*. Þú getur notað handahófskennda textaframleiðendur til að velja nafn möppu:

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

Eftir að vinnu er lokið er hægt að útvega hreinsun á slíkum möppum í krókameðferðartækjunum sem fjallað er um hér að ofan. Ef ekki er séð um tímabundnar möppur safnast þær upp og valda á einhverju stigi óvæntum vandamálum á hýsingaraðilanum, svo sem fullum diski.

Að nota læsingarskrár

Oft þarf að tryggja að aðeins eitt tilvik af skriftu sé keyrt á hýsil á hverjum tíma. Þetta er hægt að gera með því að nota læsingarskrár.

Ég bý venjulega til læsingarskrár /tmp/project_name/*.lock og athugaðu hvort þau séu til staðar í upphafi handritsins. Þetta hjálpar til við að loka smáforritinu á þokkafullan hátt og forðast óvæntar breytingar á kerfisástandinu með öðru handriti sem keyrir samhliða. Ekki er þörf á læsa skrám ef þú þarft að keyra sama handritið samhliða á tilteknum hýsil.

Mæla og bæta

Við þurfum oft að vinna með forskriftir sem keyra yfir langan tíma, eins og daglega gagnagrunnsaðgerðir. Slíkar aðgerðir fela venjulega í sér röð skrefa: að hlaða gögnum, athuga með frávik, flytja inn gögn, senda stöðuskýrslur og svo framvegis.

Í slíkum tilfellum reyni ég alltaf að skipta handritinu í aðskildar litlar forskriftir og tilkynna stöðu þeirra og framkvæmdartíma með því að nota:

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

Seinna get ég séð framkvæmdartímann með:

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

Þetta hjálpar mér að bera kennsl á vandamál/hæg svæði í skriftum sem þarfnast hagræðingar.

Gangi þér vel!

Hvað annað að lesa:

  1. Go og GPU skyndiminni.
  2. Dæmi um atburðadrifið forrit sem byggir á vefhókum í S3 hlutageymslu Mail.ru Cloud Solutions.
  3. Telegram rás okkar um stafræna umbreytingu.

Heimild: www.habr.com

Bæta við athugasemd