Cum să captați erorile în scripturile Bash pe Linux

Publicat: 2022-08-27
Laptop Linux afișează un prompt bash
fatmawati achmad zaenuri/Shutterstock.com

Î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.

Personalizarea erorilor de validare a parametrilor în PowerShell
RELATED Personalizarea erorilor de validare a parametrilor în PowerShell

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 

Realizarea unui script executabil folosind chmod

Când rulăm scriptul, vedem mesajul de eroare așteptat.

 ./bad_command.sh 

Verificarea stării de ieșire a unei comenzi pentru a determina dacă a existat o eroare

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 $? 

Folosind operatorul logic OR pentru a apela manipulatorul de erori într-un script

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.

Cum să utilizați set și pipefail în scripturile Bash pe Linux
LEGATE Cum să utilizați set și pipefail în scripturile Bash pe Linux

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 

Utilizarea comenzii set într-un script pentru a termina scriptul dacă apare o eroare

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 

Folosind capcană într-un script pentru a prinde Ctrl+c

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 

Utilizarea trap cu ERR pentru a detecta erorile dintr-un script

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