బాష్ స్క్రిప్ట్లను డీబగ్గింగ్ చేయడం అనేది గడ్డివాములో సూది కోసం వెతకడం లాంటిది, ప్రత్యేకించి నిర్మాణం, లాగింగ్ మరియు విశ్వసనీయత వంటి సమస్యలను సకాలంలో పరిగణించకుండా ఇప్పటికే ఉన్న కోడ్బేస్లో కొత్త చేర్పులు కనిపించినప్పుడు. మీరు మీ స్వంత పొరపాట్ల వల్ల లేదా సంక్లిష్టమైన స్క్రిప్ట్లను నిర్వహించేటప్పుడు ఇటువంటి పరిస్థితుల్లో మిమ్మల్ని మీరు కనుగొనవచ్చు.
జట్టు 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
ఈ విధంగా స్క్రిప్ట్లను వ్రాయడం వలన స్క్రిప్ట్లోని అన్ని ఆదేశాల ప్రవర్తన గురించి మరింత జాగ్రత్తగా ఉండవలసిందిగా మిమ్మల్ని బలవంతం చేస్తుంది మరియు అది మిమ్మల్ని ఆశ్చర్యానికి గురిచేసేలోపు ఒక లోపం సంభవించే అవకాశాన్ని అంచనా వేయండి.
అభివృద్ధి సమయంలో లోపాలను గుర్తించడానికి ShellCheck
ఇది వంటి వాటిని ఏకీకృతం చేయడం విలువ షెల్ చెక్ ఉత్తమ అభ్యాసాలకు వ్యతిరేకంగా మీ బాష్ కోడ్ని తనిఖీ చేయడానికి మీ అభివృద్ధి మరియు పరీక్ష పైప్లైన్లలోకి ప్రవేశించండి.
సింటాక్స్, సెమాంటిక్స్ మరియు కోడ్లోని కొన్ని ఎర్రర్ల గురించి రిపోర్ట్లను పొందడానికి నేను నా స్థానిక డెవలప్మెంట్ ఎన్విరాన్మెంట్లలో దీనిని ఉపయోగిస్తాను. ఇది మీ బాష్ స్క్రిప్ట్ల కోసం స్టాటిక్ అనాలిసిస్ టూల్ మరియు దీన్ని ఉపయోగించమని నేను బాగా సిఫార్సు చేస్తున్నాను.
మీ స్వంత నిష్క్రమణ కోడ్లను ఉపయోగించడం
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
అటువంటి స్క్రిప్ట్ అమలు చేయబడినప్పుడు, సిస్టమ్-వైడ్ సెట్టింగ్లు అవసరమైతే డిఫాల్ట్ విలువలకు సెట్ చేయబడతాయని లేదా అవసరమైతే కనీసం ఏదైనా ప్రారంభించబడిందని నిర్ధారిస్తుంది.
నేను సాధారణంగా వినియోగదారు ఇంటర్ఫేస్ మరియు వినియోగదారు పరిశోధించగల/పరిశోధించాల్సిన కాన్ఫిగరేషన్ల మధ్య ట్రేడ్-ఆఫ్లో ఏమి ప్రారంభించాలి మరియు ఏమి చేయకూడదు అనే ఎంపికపై ఆధారపడి ఉంటాను.
పునర్వినియోగం మరియు క్లీన్ సిస్టమ్ స్థితి కోసం ఆర్కిటెక్చర్
నేను డెవలప్ చేయాలనుకుంటున్న కొత్త ప్రాజెక్ట్/బాష్ స్క్రిప్ట్ని ప్రారంభించడానికి నేను ఉపయోగించగల ప్రత్యేక రిపోజిటరీని ఉంచుతాను. తిరిగి ఉపయోగించగల ఏదైనా రిపోజిటరీలో నిల్వ చేయబడుతుంది మరియు ఆ కార్యాచరణను ఉపయోగించాలనుకునే ఇతర ప్రాజెక్ట్ల ద్వారా తిరిగి పొందవచ్చు. ఈ విధంగా ప్రాజెక్ట్లను నిర్వహించడం వలన ఇతర స్క్రిప్ట్ల పరిమాణాన్ని గణనీయంగా తగ్గిస్తుంది మరియు కోడ్ బేస్ చిన్నదిగా మరియు సులభంగా పరీక్షించేలా నిర్ధారిస్తుంది.
పై ఉదాహరణలో వలె, అన్ని లాగింగ్ ఫంక్షన్లు వంటివి __msg_info, __msg_error మరియు స్లాక్ రిపోర్ట్ల వంటి ఇతరాలు వేరుగా ఉంటాయి common/* మరియు వంటి ఇతర దృశ్యాలలో డైనమిక్గా కనెక్ట్ అవ్వండి daily_database_operation.sh.
స్వచ్ఛమైన వ్యవస్థను వదిలివేయండి
స్క్రిప్ట్ రన్ అవుతున్నప్పుడు మీరు ఏవైనా వనరులను లోడ్ చేస్తుంటే, అటువంటి డేటా మొత్తాన్ని యాదృచ్ఛిక పేరుతో షేర్ చేసిన డైరెక్టరీలో నిల్వ చేయాలని సిఫార్సు చేయబడింది, ఉదా. /tmp/AlRhYbD97/*. డైరెక్టరీ పేరును ఎంచుకోవడానికి మీరు యాదృచ్ఛిక టెక్స్ట్ జనరేటర్లను ఉపయోగించవచ్చు:
పని పూర్తయిన తర్వాత, అటువంటి డైరెక్టరీల క్లీనప్ పైన చర్చించిన హుక్ హ్యాండ్లర్లలో అందించబడుతుంది. తాత్కాలిక డైరెక్టరీలను జాగ్రత్తగా చూసుకోకపోతే, అవి పేరుకుపోతాయి మరియు కొన్ని దశలో పూర్తి డిస్క్ వంటి ఊహించని సమస్యలను హోస్ట్లో కలిగిస్తాయి.
లాక్ ఫైళ్లను ఉపయోగించడం
తరచుగా మీరు ఏ సమయంలోనైనా హోస్ట్లో స్క్రిప్ట్ యొక్క ఒక ఉదాహరణ మాత్రమే రన్ అవుతుందని నిర్ధారించుకోవాలి. లాక్ ఫైల్లను ఉపయోగించి ఇది చేయవచ్చు.
నేను సాధారణంగా లాక్ ఫైల్లను సృష్టిస్తాను /tmp/project_name/*.lock మరియు స్క్రిప్ట్ ప్రారంభంలో వారి ఉనికిని తనిఖీ చేయండి. ఇది స్క్రిప్ట్ను సునాయాసంగా ముగించడానికి మరియు సమాంతరంగా నడుస్తున్న మరొక స్క్రిప్ట్ ద్వారా సిస్టమ్ స్థితికి ఊహించని మార్పులను నివారించడానికి సహాయపడుతుంది. ఇచ్చిన హోస్ట్లో సమాంతరంగా అమలు చేయడానికి మీకు అదే స్క్రిప్ట్ అవసరమైతే లాక్ ఫైల్లు అవసరం లేదు.
కొలవండి మరియు మెరుగుపరచండి
రోజువారీ డేటాబేస్ కార్యకలాపాలు వంటి సుదీర్ఘ కాల వ్యవధిలో పనిచేసే స్క్రిప్ట్లతో మనం తరచుగా పని చేయాల్సి ఉంటుంది. ఇటువంటి కార్యకలాపాలు సాధారణంగా దశల క్రమాన్ని కలిగి ఉంటాయి: డేటాను లోడ్ చేయడం, క్రమరాహిత్యాల కోసం తనిఖీ చేయడం, డేటాను దిగుమతి చేయడం, స్థితి నివేదికలను పంపడం మొదలైనవి.
అటువంటి సందర్భాలలో, నేను ఎల్లప్పుడూ స్క్రిప్ట్ను వేర్వేరు చిన్న స్క్రిప్ట్లుగా విభజించి, వాటి స్థితి మరియు అమలు సమయాన్ని ఉపయోగించి నివేదించడానికి ప్రయత్నిస్తాను:
time source "${filepath}" "${args}">> "${LOG_DIR}/RUN_LOG" 2>&1
తరువాత నేను దీనితో అమలు సమయాన్ని చూడగలను:
tac "${LOG_DIR}/RUN_LOG.txt" | grep -m1 "real"
ఆప్టిమైజేషన్ అవసరమయ్యే స్క్రిప్ట్లలో సమస్య/నెమ్మదైన ప్రాంతాలను గుర్తించడంలో ఇది నాకు సహాయపడుతుంది.