Cum să captați erorile în scripturile Bash pe Linux
Publicat: 2022-08-27
În mod implicit, un script Bash pe Linux va raporta o eroare, dar va continua să ruleze. Vă arătăm cum să gestionați singur erorile, astfel încât să puteți decide ce trebuie să se întâmple în continuare.
Tratarea erorilor în scripturi
Gestionarea erorilor face parte din programare. Chiar dacă scrieți cod impecabil, puteți încă să întâlniți condiții de eroare. Mediul de pe computer se schimbă în timp, pe măsură ce instalați și dezinstalați software, creați directoare și efectuați upgrade-uri și actualizări.
De exemplu, un script care rula fără probleme poate întâmpina dificultăți dacă căile directorului se modifică sau permisiunile sunt modificate pentru un fișier. Acțiunea implicită a shell-ului Bash este să tipăriți un mesaj de eroare și să continuați să executați scriptul. Aceasta este o valoare implicită periculoasă.
Dacă acțiunea care a eșuat este critică pentru o altă procesare sau acțiune care are loc mai târziu în scriptul dvs., acțiunea critică nu va avea succes. Cât de dezastruos se dovedește a fi, depinde de ceea ce încearcă să facă scenariul tău.
O schemă mai robustă ar detecta erori și ar lăsa scriptul să funcționeze dacă ar trebui să se închidă sau să încerce să remedieze starea de eroare. De exemplu, dacă lipsește un director sau un fișier, poate fi satisfăcător ca scriptul să le recreeze.
Dacă scriptul a întâmpinat o problemă din care nu se poate recupera, se poate opri. Dacă scriptul trebuie să se închidă, poate avea șansa de a efectua orice curățare este necesară, cum ar fi eliminarea fișierelor temporare sau scrierea condiției de eroare și a motivului de închidere într-un fișier jurnal.
Detectarea stării de ieșire
Comenzile și programele generează o valoare care este trimisă sistemului de operare atunci când se încheie. Aceasta se numește starea lor de ieșire. Are o valoare zero dacă nu au existat erori sau o valoare diferită de zero dacă a apărut o eroare.
Putem verifica starea de ieșire, cunoscută și sub numele de cod de returnare, a comenzilor pe care le utilizează scriptul și să stabilim dacă comanda a avut succes sau nu.
În Bash, zero echivalează cu adevărat. Dacă răspunsul de la comandă este altceva decât adevărat, știm că a apărut o problemă și putem lua măsurile corespunzătoare.
Copiați acest script într-un editor și salvați-l într-un fișier numit „bad_command.sh”.
#!/bin/bash if ( ! bad_command ); apoi echo "bad_command a semnalat o eroare." iesirea 1 fi
Va trebui să faceți scriptul executabil cu comanda chmod
. Acesta este un pas necesar pentru a face orice script executabil, așa că, dacă doriți să încercați scripturile pe propria mașină, nu uitați să faceți acest lucru pentru fiecare dintre ele. Înlocuiți numele scriptului corespunzător în fiecare caz.
chmod +x bad_command.sh
Când rulăm scriptul, vedem mesajul de eroare așteptat.
./bad_command.sh
Nu există o comandă ca „bad_command” și nici nu este numele unei funcții din script. Nu poate fi executat, deci răspunsul nu este zero. Dacă răspunsul nu este zero - punctul de exclamare este folosit aici ca operator logic NOT
- corpul instrucțiunii if
este executat.
Într-un script din lumea reală, acest lucru ar putea termina scriptul, ceea ce face exemplul nostru, sau ar putea încerca să remedieze condiția de eroare.
Ar putea părea că linia de exit 1
este redundantă. La urma urmei, nu există nimic altceva în script și se va termina oricum. Dar utilizarea comenzii de exit
ne permite să transmitem o stare de ieșire înapoi către shell. Dacă scriptul nostru este apelat vreodată dintr-un al doilea script, al doilea script va ști că acest script a întâmpinat erori.
Puteți utiliza operatorul logic OR
cu starea de ieșire a unei comenzi și puteți apela o altă comandă sau o funcție din scriptul dvs. dacă există un răspuns diferit de zero de la prima comandă.
comanda_1 || comanda_2
Acest lucru funcționează deoarece fie prima comandă rulează, OR
a doua. Prima se execută comanda din stânga. Dacă reușește, a doua comandă nu este executată. Dar dacă prima comandă eșuează, a doua comandă este executată. Deci putem structura codul astfel. Acesta este „logic-or./sh”.
#!/bin/bash error_handler() { echo „Eroare: ($?) $1” iesirea 1 } comandă_rea || error_handler „bad_command eșuat, linie: ${LINENO}”
Am definit o funcție numită error_handler
. Aceasta tipărește starea de ieșire a comenzii eșuate, păstrată în variabila $?
și o linie de text care îi este transmisă atunci când funcția este apelată. Aceasta este menținută în variabila $1
. Funcția termină scriptul cu o stare de ieșire de unu.
Scriptul încearcă să ruleze bad_command
, care evident eșuează, deci comanda din dreapta operatorului logic OR
, ||
, este executat. Aceasta apelează funcția error_handler
și transmite un șir care numește comanda care a eșuat și conține numărul de linie al comenzii care a eșuat.
Vom rula scriptul pentru a vedea mesajul de gestionare a erorilor, apoi vom verifica starea de ieșire a scriptului folosind echo.
./logic-or.sh
eco $?
Mica noastră funcție error_handler
oferă starea de ieșire a încercării de a rula bad_command
, numele comenzii și numărul liniei. Acestea sunt informații utile atunci când depanați un script.

Starea de ieșire a scriptului este una. Starea de ieșire 127 raportată de error_handler
înseamnă „comanda nu a fost găsită”. Dacă am dori, am putea folosi asta ca stare de ieșire a scriptului, trecându-l la comanda de exit
.
O altă abordare ar fi extinderea error_handler
pentru a verifica diferitele valori posibile ale stării de ieșire și pentru a efectua diferite acțiuni în consecință, folosind acest tip de construct:
exit_code=$? if [ $exit_code -eq 1 ]; apoi echo „Operațiunea nu este permisă” elif [ $exit_code -eq 2 ]; apoi echo „Utilizarea greșită a elementelor integrate de shell” . . . elif [ $status -eq 128 ]; apoi echo „Argument nevalid” fi
Folosind setarea Pentru a forța o ieșire
Dacă știți că doriți ca scriptul dvs. să iasă ori de câte ori apare o eroare, îl puteți forța să facă asta. înseamnă că renunțați la șansa oricărei curățări sau a oricărei alte daune, deoarece scriptul dvs. se termină de îndată ce detectează o eroare.
Pentru a face acest lucru, utilizați comanda set
cu opțiunea -e
(eroare). Aceasta îi spune scriptului să iasă ori de câte ori o comandă eșuează sau returnează un cod de ieșire mai mare decât zero. De asemenea, utilizarea opțiunii -E
asigură că detectarea erorilor și captarea funcționează în funcțiile shell.
Pentru a prinde și variabile neinițializate, adăugați opțiunea -u
(dezactivat). Pentru a vă asigura că erorile sunt detectate în secvențele piperate, adăugați -o pipefail
. Fără aceasta, starea de ieșire a unei secvențe de comenzi canalizate este starea de ieșire a comenzii finale din secvență. O comandă eșuată în mijlocul secvenței canalizate nu ar fi detectată. Opțiunea -o pipefail
trebuie să apară în lista de opțiuni.
Secvența de adăugat în partea de sus a scriptului este:
set -Eeuo pipefail
Iată un script scurt numit „unset-var.sh”, cu o variabilă unset în el.
#!/bin/bash set -Eeou pipefail echo „$unset_variable” echo "Vedem această linie?"
Când rulăm scriptul, unset_variable este recunoscută ca o variabilă neinițializată și scriptul este terminat.
./unset-var.sh
A doua comandă echo
nu este niciodată executată.
Utilizarea capcanei cu erori
Comanda Bash trap vă permite să nominalizați o comandă sau o funcție care ar trebui apelată atunci când este ridicat un anumit semnal. De obicei, aceasta este folosită pentru a capta semnale precum SIGINT
, care este ridicată atunci când apăsați combinația de taste Ctrl+C. Acest script este „sigint.sh”.
#!/bin/bash capcană "echo -e '\nTerminat de Ctrl+c'; ieșire" SIGINT contor=0 în timp ce adevărat do echo „Numărul buclei:” $((++contor)) somn 1 Terminat
Comanda trap
conține o comandă echo
și comanda de exit
. Acesta va fi declanșat când SIGINT
este ridicat. Restul scriptului este o buclă simplă. Dacă rulați scriptul și apăsați Ctrl+C, veți vedea mesajul din definiția trap
, iar scriptul se va termina.
./sigint.sh
Putem folosi trap
cu semnalul ERR
pentru a detecta erorile pe măsură ce apar. Acestea pot fi apoi transmise unei comenzi sau funcție. Acesta este „trap.sh.” Trimitem notificări de eroare către o funcție numită error_handler
.
#!/bin/bash capcană 'error_handler $? $LINENO' ERR error_handler() { echo „Eroare: ($1) a apărut pe $2” } principal() { echo „În interiorul funcției main()” comandă_rea al doilea al treilea ieșire din $? } al doilea() { echo "După apelul la main()" echo „În interiorul funcției secunde ()” } al treilea() { echo „În interiorul funcției a treia ()” } principal
Cea mai mare parte a scriptului se află în interiorul funcției main
, care apelează a second
și a third
funcție. Când se întâlnește o eroare — în acest caz, deoarece bad_command
nu există — instrucțiunea trap
direcționează eroarea către funcția error_handler
. Transmite starea de ieșire de la comanda eșuată și numărul de linie la funcția error_handler
.
./capcană.sh
Funcția noastră error_handler
listează pur și simplu detaliile erorii în fereastra terminalului. Dacă doriți, puteți adăuga o comandă de exit
la funcție pentru a termina scriptul. Sau puteți folosi o serie de instrucțiuni if/elif/fi
pentru a efectua diferite acțiuni pentru diferite erori.
Este posibil să se remedieze unele erori, altele ar putea necesita oprirea scriptului.
Un sfat final
Captarea erorilor înseamnă adesea să anticipați lucrurile care pot merge prost și să introduceți cod pentru a face față acestor eventualități în cazul în care acestea apar. Asta în plus față de a vă asigura că fluxul de execuție și logica internă a scriptului dvs. sunt corecte.
Dacă utilizați această comandă pentru a rula scriptul, Bash vă va afișa o ieșire de urmărire pe măsură ce scriptul se execută:
bash -x your-script.sh
Bash scrie rezultatul urmăririi în fereastra terminalului. Afișează fiecare comandă cu argumentele sale — dacă are. Acest lucru se întâmplă după ce comenzile au fost extinse, dar înainte de a fi executate.
Poate fi un ajutor extraordinar în urmărirea erorilor evazive.
LEGATE: Cum să validați sintaxa unui script Linux Bash înainte de a-l rula